diff options
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/eisa/eisavar.h | 15 | ||||
-rw-r--r-- | sys/dev/ic/dp8573areg.h | 121 | ||||
-rw-r--r-- | sys/dev/ic/dp857xreg.h | 133 | ||||
-rw-r--r-- | sys/dev/ic/ds1286reg.h | 182 | ||||
-rw-r--r-- | sys/dev/ic/seeq8003reg.h | 134 | ||||
-rw-r--r-- | sys/dev/ic/wd33c93.c | 2337 | ||||
-rw-r--r-- | sys/dev/ic/wd33c93reg.h | 510 | ||||
-rw-r--r-- | sys/dev/ic/wd33c93var.h | 262 | ||||
-rw-r--r-- | sys/dev/ic/z8530reg.h | 7 |
9 files changed, 3556 insertions, 145 deletions
diff --git a/sys/dev/eisa/eisavar.h b/sys/dev/eisa/eisavar.h index d8d5b59f84c..e48cfa8f561 100644 --- a/sys/dev/eisa/eisavar.h +++ b/sys/dev/eisa/eisavar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: eisavar.h,v 1.13 2010/05/23 14:50:31 deraadt Exp $ */ +/* $OpenBSD: eisavar.h,v 1.14 2012/03/28 20:44:23 miod Exp $ */ /* $NetBSD: eisavar.h,v 1.11 1997/06/06 23:30:07 thorpej Exp $ */ /* @@ -54,17 +54,12 @@ struct eisabus_attach_args; /* * Machine-dependent definitions. */ -#if (__alpha__ + __i386__ + __hppa__ != 1) -#error COMPILING FOR UNSUPPORTED MACHINE, OR MORE THAN ONE. -#endif -#if __alpha__ +#if defined(__alpha__) #include <alpha/eisa/eisa_machdep.h> -#endif -#if __i386__ +#elif defined(__i386__) #include <i386/eisa/eisa_machdep.h> -#endif -#if __hppa__ -#include <hppa/include/eisa_machdep.h> +#else +#include <machine/eisa_machdep.h> #endif typedef int eisa_slot_t; /* really only needs to be 4 bits */ diff --git a/sys/dev/ic/dp8573areg.h b/sys/dev/ic/dp8573areg.h new file mode 100644 index 00000000000..bf66e70bf1e --- /dev/null +++ b/sys/dev/ic/dp8573areg.h @@ -0,0 +1,121 @@ +/* $OpenBSD: dp8573areg.h,v 1.1 2012/03/28 20:44:23 miod Exp $ */ +/* $NetBSD: dp8573areg.h,v 1.1 2009/02/12 06:33:57 rumble Exp $ */ + +/* + * Copyright (c) 2003 Steve Rumble + * Copyright (c) 2001 Erik Reid + * + * 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 AUTHOR ``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 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. + */ + +/* + * National Semiconductor DP8573A Real Time Clock + */ + +/* Control and Status Register Offsets and Masks */ +#define DP8573A_STATUS 0x00 /* Main Status */ +#define DP8573A_STATUS_INTSTAT 0x01 /* Interrupt Status */ +#define DP8573A_STATUS_PWRFAIL 0x02 /* Power Fail Interrupt */ +#define DP8573A_STATUS_PERINT 0x04 /* Period Interrupt */ +#define DP8573A_STATUS_ALMINT 0x08 /* Alarm Interrupt */ +#define DP8573A_STATUS_REGSEL 0x40 /* Register Select */ + +/* Register Select = 0 */ +#define DP8573A_PFLAG 0x03 /* Periodic Flag */ +#define DP8573A_PFLAG_MIN 0x01 /* Minutes */ +#define DP8573A_PFLAG_10SEC 0x02 /* Ten Second */ +#define DP8573A_PFLAG_SEC 0x04 /* Seconds */ +#define DP8573A_PFLAG_100MIL 0x08 /* 100 Millisecond */ +#define DP8573A_PFLAG_10MIL 0x10 /* 10 Millisecond */ +#define DP8573A_PFLAG_MIL 0x20 /* Milliseconds */ +#define DP8573A_PFLAG_OFSS 0x40 /* Oscillator Fail/Single Supply */ +#define DP8573A_PFLAG_TESTMODE 0x80 /* Test Mode Enable */ + +#define DP8573A_TIMESAVE_CTL 0x04 /* Time Save Control */ +#define DP8573A_TIMESAVE_CTL_EN 0x80 /* Time Save Enable */ + +/* Register Select = 1 */ +#define DP8573A_RT_MODE 0x01 /* Real Time Mode */ +#define DP8573A_RT_MODE_LYLSB 0x01 /* Leap Year LSB */ +#define DP8573A_RT_MODE_LYMSB 0x02 /* Leap Year MSB */ +#define DP8573A_RT_MODE_1224 0x04 /* 12(low)/24(high) Hour Mode */ +#define DP8573A_RT_MODE_CLKSS 0x08 /* Clock Start(high)/Stop(low) */ +#define DP8573A_RT_MODE_INTPFOP 0x10 /* Interrupt PF Operation */ + +#define DP8573A_OUT_MODE 0x02 /* Output Mode */ +#define DP8573A_OUT_MODE_MFOPO 0x80 /* MFO Pin as Oscillator */ + +#define DP8573A_INT0_CTL 0x03 /* Interrupt Control 0 */ +#define DP8573A_INT0_CTL_MIN 0x01 /* Minutes Enable */ +#define DP8573A_INT0_CTL_10SEC 0x02 /* 10 Second Enable */ +#define DP8573A_INT0_CTL_SEC 0x04 /* Seconds Enable */ +#define DP8573A_INT0_CTL_100MIL 0x08 /* 100 Millisecond Enable */ +#define DP8573A_INT0_CTL_10MIL 0x10 /* 10 Millisecond Enable */ +#define DP8573A_INT0_CTL_MIL 0x20 /* Millisecond Enable */ + +#define DP8573A_INT1_CTL 0x04 /* Interrupt Control 1 */ +#define DP8573A_INT1_CTL_SECC 0x01 /* Second Compare Enable */ +#define DP8573A_INT1_CTL_MINC 0x02 /* Minute Compare Enable */ +#define DP8573A_INT1_CTL_HOURC 0x04 /* Hour Compare Enable */ +#define DP8573A_INT1_CTL_DOMC 0x08 /* Day of Month Compare Enable */ +#define DP8573A_INT1_CTL_MONTHC 0x10 /* Month Compare Enable */ +#define DP8573A_INT1_CTL_DOWC 0x20 /* Day of Week Compare Enable */ +#define DP8573A_INT1_CTL_ALMINT 0x40 /* Alarm Interrupt Enable */ +#define DP8573A_INT1_CTL_PWRINT 0x80 /* Power Fail Interrupt Enable */ + +/* Clock Counter Offsets */ +#define DP8573A_COUNTERS 0x05 /* Start of Clock Counters */ +#define DP8573A_SUBSECOND 0x05 /* 1/100 Second */ +#define DP8573A_SECOND 0x06 /* Seconds */ +#define DP8573A_MINUTE 0x07 /* Minutes */ +#define DP8573A_HOUR 0x08 /* Hours */ +#define DP8573A_DOM 0x09 /* Day of Month */ +#define DP8573A_MONTH 0x0a /* Months */ +#define DP8573A_YEAR 0x0b /* Years */ +#define DP8573A_DOW 0x0e /* Day of Week */ + +/* Comparsion Registers */ +#define DP8573A_CMP_SEC 0x13 /* Seconds */ +#define DP8573A_CMP_MIN 0x14 /* Minutes */ +#define DP8573A_CMP_HOUR 0x15 /* Hours */ +#define DP8573A_CMP_DOM 0x16 /* Day of Month */ +#define DP8573A_CMP_MONTH 0x17 /* Months */ +#define DP8573A_CMP_DOW 0x18 /* Day of Week */ + +/* Time Save Registers */ +#define DP8573A_SAVE_SEC 0x19 /* Seconds */ +#define DP8573A_SAVE_MIN 0x1a /* Minutes */ +#define DP8573A_SAVE_HOUR 0x1b /* Hours */ +#define DP8573A_SAVE_DOM 0x1c /* Day of Month */ +#define DP8573A_SAVE_MONTH 0x1d /* Months */ + +/* RAM Registers */ +#define DP8573A_RAM_0C 0x0c /* RAM */ +#define DP8573A_RAM_1E 0x1e /* RAM */ +#define DP8573A_RAM_1F 0x1f /* RAM */ + +/* 12/24 Hour Masks */ +#define DP8573A_HOUR_12HR_MASK 0x1f +#define DP8573A_HOUR_24HR_MASK 0x3f + +#define DP8573A_NREG 0x20 diff --git a/sys/dev/ic/dp857xreg.h b/sys/dev/ic/dp857xreg.h deleted file mode 100644 index 9164c574718..00000000000 --- a/sys/dev/ic/dp857xreg.h +++ /dev/null @@ -1,133 +0,0 @@ -/* $OpenBSD: dp857xreg.h,v 1.4 2012/03/07 18:15:25 miod Exp $ */ - -/* - * Copyright (c) 1996 Per Fogelstrom - * - * 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. - * - */ - -#if !defined(_DP857X_H) -#define _DP857X_H - -/* - * Definition of Real Time Clock address space. - * - * Clock is a National DP8570A RTC - */ -#define BSIZE 1 /* No of Bytes for Address Spacing */ -#define MAIN_STATUS 0x00 /* Main status register */ -/* - * Registers selected with BS=0 RS=0 - */ -#define TIMER0_CTRL 0x01 /* Timer 0 control register */ -#define TIMER1_CTRL 0x02 /* Timer 0 control register */ -#define PERIODIC_FLAGS 0x03 /* Timer periodic flag register */ -#define INTERRUPT_ROUT 0x04 /* Interrupt routing register */ -/* - * Registers selected with BS=0 RS=1 - */ -#define REAL_TIME_MODE 0x01 /* Real Time Mode register */ -#define OUTPUT_MODE 0x02 /* Output mode register */ -#define INTERRUPT_CTRL0 0x03 /* Interrupt control register 0 */ -#define INTERRUPT_CTRL1 0x04 /* Interrupt control register 1 */ -/* - * Clock and timer registers when BS=0 - */ -#define CLK_SUBSECONDS 0x05 /* 1/100 seconds register */ -#define CLK_SECONDS 0x06 /* Seconds */ -#define CLK_MINUTES 0x07 /* Minutes */ -#define CLK_HOURS 0x08 /* Hours */ -#define CLK_DAY 0x09 /* Day of month */ -#define CLK_MONTH 0x0a /* Month */ -#define CLK_YEAR 0x0b /* Year */ -#define CLK_JULIAN_L 0x0c /* Lsb of Julian date */ -#define CLK_JULIAN_H 0x0d /* Msb of Julian date */ -#define CLK_WEEKDAY 0x0e /* Day of week */ -#define TIMER0_LSB 0x0f /* Timer 0 lsb */ -#define TIMER0_MSB 0x10 /* Timer 0 msb */ -#define TIMER1_LSB 0x11 /* Timer 1 lsb */ -#define TIMER1_MSB 0x12 /* Timer 1 msb */ -#define CMP_SECONDS 0x13 /* Seconds compare */ -#define CMP_MINUTES 0x14 /* Minutes compare */ -#define CMP_HOUR 0x15 /* Hours compare */ -#define CMP_DAY 0x16 /* Day of month compare */ -#define CMP_MONTH 0x17 /* Month compare */ -#define CMP_WEEKDAY 0x18 /* Day of week compare */ -#define SAVE_SECONDS 0x19 /* Seconds time save */ -#define SAVE_MINUTES 0x1a /* Minutes time save */ -#define SAVE_HOUR 0x1b /* Hours time save */ -#define SAVE_DAY 0x1c /* Day of month time save */ -#define SAVE_MONTH 0x1d /* Month time save */ -#define RAM_1E 0x1e /* Ram location 1e */ -#define RAM_1F 0x1f /* Ram location 1f */ -#define SIZE_DP857X 0x20 /* Size of dp address map */ - -#define DP_FIRSTTODREG CLK_SUBSECONDS -#define DP_LASTTODREG CLK_WEEKDAY - -typedef u_int dp_todregs[SIZE_DP857X]; -u_int dp857x_read(void *sc, u_int reg); -void dp857x_write(void *sc, u_int reg, u_int datum); - -/* - * Get all of the TOD/Alarm registers - * Must be called at splhigh(), and with the RTC properly set up. - */ -#define DP857X_GETTOD(sc, regs) \ - do { \ - int i; \ - \ - /* make sure clock regs are selected */ \ - dp857x_write(sc, MAIN_STATUS, 0); \ - /* try read until no rollover */ \ - do { \ - /* read all of the tod/alarm regs */ \ - for (i = DP_FIRSTTODREG; i < SIZE_DP857X; i++) \ - (*regs)[i] = dp857x_read(sc, i); \ - } while(dp857x_read(sc, PERIODIC_FLAGS) & 7); \ - } while (0); - -/* - * Set all of the TOD/Alarm registers - * Must be called at splhigh(), and with the RTC properly set up. - */ -#define DP857X_PUTTOD(sc, regs) \ - do { \ - int i; \ - \ - /* stop updates while setting, eg clear start bit */ \ - dp857x_write(sc, MAIN_STATUS, 0x40); \ - dp857x_write(sc, REAL_TIME_MODE, \ - dp857x_read(sc, REAL_TIME_MODE) & 0xF7); \ - \ - /* write all of the tod/alarm regs */ \ - for (i = DP_FIRSTTODREG; i <= DP_LASTTODREG; i++) \ - dp857x_write(sc, i, (*regs)[i]); \ - \ - /* reenable updates, eg set clock start bit */ \ - dp857x_write(sc, REAL_TIME_MODE, \ - dp857x_read(sc, REAL_TIME_MODE) | 0x08); \ - } while (0); - -#endif /*_DP857X_H*/ - diff --git a/sys/dev/ic/ds1286reg.h b/sys/dev/ic/ds1286reg.h new file mode 100644 index 00000000000..2b625fc181f --- /dev/null +++ b/sys/dev/ic/ds1286reg.h @@ -0,0 +1,182 @@ +/* $OpenBSD: ds1286reg.h,v 1.1 2012/03/28 20:44:23 miod Exp $ */ +/* $NetBSD: ds1286reg.h,v 1.8 2005/12/11 12:21:26 christos Exp $ */ + +/* + * Copyright (c) 2001 Rafal K. Boni + * + * 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 AUTHOR ``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 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. + */ + +/* + * Originally based on mc146818reg.h, with the following license: + * + * Copyright (c) 1995 Carnegie-Mellon University. + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software and + * its documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND + * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +/* + * Definitions for the Dallas Semiconductor DS1286/DS1386 Real Time Clock. + * + * Plucked right from the Dallas Semicomductor specs available at + * http://pdfserv.maxim-ic.com/arpdf/DS1286.pdf and + * http://pdfserv.maxim-ic.com/arpdf/DS1386-DS1386P.pdf + * + * The DS1286 and 1386 have 14 clock-related registers and some amount + * of user registers (50 for the 1286, 8K or 32K for the 1386). The + * first eleven registers contain time-of-day and alarm data, the rest + * contain various control bits and the watchdog timer functionality. + * + * Since the locations of these ports and the method used to access + * them can be machine-dependent, the low-level details of reading + * and writing the RTC's registers are handled by machine-specific + * functions. + * + * The DS1286/DS1386 chips always store time-of-day and alarm data in + * BCD. The "hour" time-of-year and alarm fields can either be stored + * in AM/PM format, or in 24-hour format. If AM/PM format is chosen, + * the hour fields can have the values: 1-12 (for AM) and 21-32 (for + * PM). If the 24-hour format is chosen, they can have the values 0 + * to 23. The hour format is selectable separately for the time and + * alarm fields, and is controller by bit 6 of the respective register. + */ + +/* + * The registers, and the bits within each register. + */ + +#define DS1286_SUBSEC 0x0 /* Time of year: hundredths of seconds (0-99) */ +#define DS1286_SEC 0x1 /* Time of year: seconds (0-59) */ +#define DS1286_MIN 0x2 /* Time of year: minutes (0-59) */ +#define DS1286_AMIN 0x3 /* Alarm: minutes */ +#define DS1286_HOUR 0x4 /* Time of year: hour (see above) */ + +#define DS1286_HOUR_12MODE 0x40 /* Hour mode: 12-hour (on), 24 (off) */ +#define DS1286_HOUR_12HR_PM 0x20 /* AM/PM in 12-hour mode: on = PM */ +#define DS1286_HOUR_12HR_MASK 0x1f /* Mask for hours in 12hour mode */ +#define DS1286_HOUR_24HR_MASK 0x3f /* Mask for hours in 24hour mode */ + +#define DS1286_AHOUR 0x5 /* Alarm: hour */ +#define DS1286_DOW 0x6 /* Time of year: day of week (1-7) */ +#define DS1286_ADOW 0x7 /* Alarm: day of week (1-7) */ +#define DS1286_DOM 0x8 /* Time of year: day of month (1-31) */ +#define DS1286_MONTH 0x9 /* Time of year: month (1-12), wave generator */ + +#define DS1286_MONTH_MASK 0x3f /* Mask to extract month */ +#define DS1286_WAVEGEN_MASK 0xc0 /* Mask to extract wave bits */ + +#define DS1286_YEAR 0xA /* Time of year: year in century (0-99) */ + +#define DS1286_CONTROL 0xB /* Control register A */ + +#define DS1286_TE 0x80 /* Update in progress (on == disable update) */ +#define DS1286_INTSWAP 0x40 /* Swap INTA, INTB outputs */ +#define DS1286_INTBSRC 0x20 /* INTB source (on) or sink (off) current */ +#define DS1286_INTAPLS 0x10 /* INTA pulse (on) or level (off) mode */ +#define DS1286_WAM 0x08 /* Watchdog alarm mask */ +#define DS1286_TDM 0x04 /* Time-of-day alarm mask */ +#define DS1286_WAF 0x02 /* Watchdog alarm flag */ +#define DS1286_TDF 0x01 /* Time-of-day alarm flag */ + +#define DS1286_NREGS 0xd /* 14 registers; CMOS follows */ +#define DS1286_NTODREGS 0xb /* 11 of those regs are for TOD and alarm */ + +#define DS1286_NVRAM_START 0xe /* start of NVRAM: offset 14 */ + +/* NVRAM size depends on the chip -- the 1286 only has 50 bytes, whereas + * the 1386 can have 8K or 32K + */ +#define DS1286_NVRAM_SIZE 50 /* 50 bytes of NVRAM */ + +/* + * RTC register/NVRAM read and write functions -- machine-dependent. + * Appropriately manipulate RTC registers to get/put data values. + */ +u_int ds1286_read(void *, u_int); +void ds1286_write(void *, u_int, u_int); + +/* + * A collection of TOD/Alarm registers. + */ +typedef u_int ds1286_todregs[DS1286_NTODREGS]; + +/* + * Get all of the TOD/Alarm registers + * Must be called at splhigh(), and with the RTC properly set up. + */ +#define DS1286_GETTOD(sc, regs) \ + do { \ + int i; \ + u_int ctl; \ + \ + /* turn off update for now */ \ + ctl = ds1286_read(sc, DS1286_CONTROL); \ + ds1286_write(sc, DS1286_CONTROL, ctl | DS1286_TE); \ + \ + /* read all of the tod/alarm regs */ \ + for (i = 0; i < DS1286_NTODREGS; i++) \ + (*regs)[i] = ds1286_read(sc, i); \ + \ + /* turn update back on */ \ + ds1286_write(sc, DS1286_CONTROL, ctl); \ + } while (0); + +/* + * Set all of the TOD/Alarm registers + * Must be called at splhigh(), and with the RTC properly set up. + */ +#define DS1286_PUTTOD(sc, regs) \ + do { \ + int i; \ + u_int ctl; \ + \ + /* turn off update for now */ \ + ctl = ds1286_read(sc, DS1286_CONTROL); \ + ds1286_write(sc, DS1286_CONTROL, ctl | DS1286_TE); \ + \ + /* write all of the tod/alarm regs */ \ + for (i = 0; i < DS1286_NTODREGS; i++) \ + ds1286_write(sc, i, (*regs)[i]); \ + \ + /* turn update back on */ \ + ds1286_write(sc, DS1286_CONTROL, ctl); \ + } while (0); diff --git a/sys/dev/ic/seeq8003reg.h b/sys/dev/ic/seeq8003reg.h new file mode 100644 index 00000000000..c0978c67508 --- /dev/null +++ b/sys/dev/ic/seeq8003reg.h @@ -0,0 +1,134 @@ +/* $OpenBSD: seeq8003reg.h,v 1.1 2012/03/28 20:44:23 miod Exp $ */ +/* $NetBSD: seeq8003reg.h,v 1.3 2001/06/07 05:19:26 thorpej Exp $ */ + +/* + * Copyright (c) 2000 Soren S. Jorvang. All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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. + */ + +/* + * Register definitions for the Seeq 8003 and 80C03 ethernet controllers + * + * Based on documentation available at + * http://www.lsilogic.com/techlib/techdocs/networking/eol/80c03.pdf . + */ + +#define SEEQ_ADDR0 0 /* Station Address Byte 0 */ +#define SEEQ_ADDR1 1 /* Station Address Byte 1 */ +#define SEEQ_ADDR2 2 /* Station Address Byte 2 */ +#define SEEQ_ADDR3 3 /* Station Address Byte 3 */ +#define SEEQ_ADDR4 4 /* Station Address Byte 4 */ +#define SEEQ_ADDR5 5 /* Station Address Byte 5 */ + +#define SEEQ_TXCOLLS0 0 /* Transmit Collision Counter LSB */ +#define SEEQ_TXCOLLS1 1 /* Transmit Collision Counter MSB */ +#define SEEQ_ALLCOLL0 2 /* Total Collision Counter LSB */ +#define SEEQ_ALLCOLL1 3 /* Total Collision Counter MSB */ + +#define SEEQ_TEST 4 /* "For Test Only" - Do Not Use */ + +#define SEEQ_SQE 5 /* SQE / No Carrier */ +#define SQE_FLAG 0x01 /* SQE Flag */ +#define SQE_NOCARR 0x02 /* No Carrier Flag */ + +#define SEEQ_RXCMD 6 /* Rx Command */ +#define RXCMD_IE_OFLOW 0x01 /* Interrupt on Overflow Error */ +#define RXCMD_IE_CRC 0x02 /* Interrupt on CRC Error */ +#define RXCMD_IE_DRIB 0x04 /* Interrupt on Dribble Error */ +#define RXCMD_IE_SHORT 0x08 /* Interrupt on Short Frame */ +#define RXCMD_IE_END 0x10 /* Interrupt on End of Frame */ +#define RXCMD_IE_GOOD 0x20 /* Interrupt on Good Frame */ +#define RXCMD_REC_MASK 0xc0 /* Receiver Match Mode Mask */ +#define RXCMD_REC_NONE 0x00 /* Receiver Disabled */ +#define RXCMD_REC_ALL 0x40 /* Receive All Frames */ +#define RXCMD_REC_BROAD 0x80 /* Receive Station/Broadcast Frames */ +#define RXCMD_REC_MULTI 0xc0 /* Station/Broadcast/Multicast */ + +#define SEEQ_RXSTAT 6 /* Rx Status */ +#define RXSTAT_OFLOW 0x01 /* Frame Overflow Error */ +#define RXSTAT_CRC 0x02 /* Frame CRC Error */ +#define RXSTAT_DRIB 0x04 /* Frame Dribble Error */ +#define RXSTAT_SHORT 0x08 /* Received Short Frame */ +#define RXSTAT_END 0x10 /* Received End of Frame */ +#define RXSTAT_GOOD 0x20 /* Received Good Frame */ +#define RXSTAT_OLDNEW 0x80 /* Old/New Status */ + +#define SEEQ_TXCMD 7 /* Tx Command */ +#define TXCMD_IE_UFLOW 0x01 /* Interrupt on Transmit Underflow */ +#define TXCMD_IE_COLL 0x02 /* Interrupt on Transmit Collision */ +#define TXCMD_IE_16COLL 0x04 /* Interrupt on 16 Collisions */ +#define TXCMD_IE_GOOD 0x08 /* Interrupt on Transmit Succes */ +#define TXCMD_ENABLE_C 0xf0 /* (80C03) Enable 80C03 Mode */ +#define TXCMD_BANK_MASK 0x60 /* (80C03) Register Bank Mask */ +#define TXCMD_BANK0 0x00 /* (80C03) Register Bank 0 (8003) */ +#define TXCMD_BANK1 0x20 /* (80C03) Register Bank 1 (Writes) */ +#define TXCMD_BANK2 0x40 /* (80C03) Register Bank 2 (Writes) */ + +#define SEEQ_TXSTAT 7 /* Tx Status */ +#define TXSTAT_UFLOW 0x01 /* Transmit Underflow */ +#define TXSTAT_COLL 0x02 /* Transmit Collision */ +#define TXSTAT_16COLL 0x04 /* 16 Collisions */ +#define TXSTAT_GOOD 0x08 /* Transmit Success */ +#define TXSTAT_OLDNEW 0x80 /* Old/New Status */ + +/* + * 80C03 Mode Register Bank 1 + */ + +#define SEEQ_MC_HASH0 0 /* Multicast Filter Byte 0 (LSB) */ +#define SEEQ_MC_HASH1 1 /* Multicast Filter Byte 1 */ +#define SEEQ_MC_HASH2 2 /* Multicast Filter Byte 2 */ +#define SEEQ_MC_HASH3 3 /* Multicast Filter Byte 3 */ +#define SEEQ_MC_HASH4 4 /* Multicast Filter Byte 4 */ +#define SEEQ_MC_HASH5 5 /* Multicast Filter Byte 5 */ + +/* + * 80C03 Mode Register Bank 2 + */ + +#define SEEQ_MC_HASH6 0 /* Multicast Filter Byte 6 */ +#define SEEQ_MC_HASH7 1 /* Multicast Filter Byte 7 (MSB) */ + +#define SEEQ_RESERVED0 2 /* Reserved (Set to All Zeroes) */ + +#define SEEQ_TXCTRL 3 /* Tx Control */ +#define TXCTRL_TXCOLL 0x01 /* Clear/Enable Tx Collision Counter */ +#define TXCTRL_COLL 0x02 /* Clear/Enable Collision Counter */ +#define TXCTRL_SQE 0x04 /* Clear/Enable SQE Flag */ +#define TXCTRL_HASH 0x08 /* Enable Multicast Hash Filter */ +#define TXCTRL_SHORT 0x10 /* Receive Short (<13 Bytes) Frames */ +#define TXCTRL_NOCARR 0x20 /* Clear/Enable No Carrier Flag */ + +#define SEEQ_CFG 4 /* Transmit/Receive Configuration */ +#define CFG_RX_GRPADDR 0x01 /* Ignore Last 4 Bits of Address */ +#define CFG_TX_AUTOPAD 0x02 /* Automatically Pad to 60 Bytes */ +#define CFG_TX_NOPRE 0x04 /* Do Not Add Preamble Pattern */ +#define CFG_RX_NOOWN 0x08 /* Do Not Receive Own Packets */ +#define CFG_TX_NOCRC 0x10 /* No Not Append CRC */ +#define CFG_TX_DUPLEX 0x20 /* AutoDUPLEX - Ignore Carrier */ +#define CFG_RX_CRCFIFO 0x40 /* Write CRC to FIFO */ +#define CFG_RX_FASTDISC 0x80 /* Fast Receive Discard Mode */ + +#define SEEQ_RESERVED1 5 /* Reserved */ +#define SEEQ_RESERVED2 6 /* Reserved */ +#define SEEQ_RESERVED3 7 /* Reserved */ diff --git a/sys/dev/ic/wd33c93.c b/sys/dev/ic/wd33c93.c new file mode 100644 index 00000000000..2c6fabc6660 --- /dev/null +++ b/sys/dev/ic/wd33c93.c @@ -0,0 +1,2337 @@ +/* $OpenBSD: wd33c93.c,v 1.1 2012/03/28 20:44:23 miod Exp $ */ +/* $NetBSD: wd33c93.c,v 1.24 2010/11/13 13:52:02 uebayasi Exp $ */ + +/* + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Van Jacobson of Lawrence Berkeley Laboratory. + * + * 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. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#)scsi.c 7.5 (Berkeley) 5/4/91 + */ + +/* + * Changes Copyright (c) 2001 Wayne Knowles + * Changes Copyright (c) 1996 Steve Woodford + * Original Copyright (c) 1994 Christian E. Hopps + * + * This code is derived from software contributed to Berkeley by + * Van Jacobson of Lawrence Berkeley Laboratory. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#)scsi.c 7.5 (Berkeley) 5/4/91 + */ + +/* + * This version of the driver is pretty well generic, so should work with + * any flavour of WD33C93 chip. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/kernel.h> /* For hz */ +#include <sys/malloc.h> +#include <sys/pool.h> + +#include <scsi/scsi_all.h> +#include <scsi/scsiconf.h> +#include <scsi/scsi_message.h> + +#include <machine/bus.h> + +#include <dev/ic/wd33c93reg.h> +#include <dev/ic/wd33c93var.h> + +/* + * SCSI delays + * In u-seconds, primarily for state changes on the SPC. + */ +#define SBIC_CMD_WAIT 200000 /* wait per step of 'immediate' cmds */ +#define SBIC_DATA_WAIT 200000 /* wait per data in/out step */ +#define SBIC_INIT_WAIT 200000 /* wait per step (both) during init */ + +#define STATUS_UNKNOWN 0xff /* uninitialized status */ + +/* + * Convenience macro for waiting for a particular wd33c93 event + */ +#define SBIC_WAIT(regs, until, timeo) wd33c93_wait(regs, until, timeo, __LINE__) + +void wd33c93_init(struct wd33c93_softc *); +void wd33c93_reset(struct wd33c93_softc *); +int wd33c93_go(struct wd33c93_softc *, struct wd33c93_acb *); +int wd33c93_dmaok(struct wd33c93_softc *, struct scsi_xfer *); +int wd33c93_wait(struct wd33c93_softc *, u_char, int , int); +u_char wd33c93_selectbus(struct wd33c93_softc *, struct wd33c93_acb *); +int wd33c93_xfout(struct wd33c93_softc *, int, void *); +int wd33c93_xfin(struct wd33c93_softc *, int, void *); +int wd33c93_poll(struct wd33c93_softc *, struct wd33c93_acb *); +int wd33c93_nextstate(struct wd33c93_softc *, struct wd33c93_acb *, + u_char, u_char); +int wd33c93_abort(struct wd33c93_softc *, struct wd33c93_acb *, + const char *); +void wd33c93_xferdone(struct wd33c93_softc *); +void wd33c93_error(struct wd33c93_softc *, struct wd33c93_acb *); +void wd33c93_scsidone(struct wd33c93_softc *, struct wd33c93_acb *, int); +void wd33c93_sched(struct wd33c93_softc *); +void wd33c93_dequeue(struct wd33c93_softc *, struct wd33c93_acb *); +void wd33c93_dma_stop(struct wd33c93_softc *); +void wd33c93_dma_setup(struct wd33c93_softc *, int); +int wd33c93_msgin_phase(struct wd33c93_softc *, int); +void wd33c93_msgin(struct wd33c93_softc *, u_char *, int); +void wd33c93_reselect(struct wd33c93_softc *, int, int, int, int); +void wd33c93_sched_msgout(struct wd33c93_softc *, u_short); +void wd33c93_msgout(struct wd33c93_softc *); +void wd33c93_timeout(void *arg); +void wd33c93_watchdog(void *arg); +u_char wd33c93_stp2syn(struct wd33c93_softc *, struct wd33c93_tinfo *); +void wd33c93_setsync(struct wd33c93_softc *, struct wd33c93_tinfo *); + +struct pool wd33c93_pool; /* Adapter Control Blocks */ +int wd33c93_pool_initialized = 0; + +/* + * Timeouts + */ +int wd33c93_cmd_wait = SBIC_CMD_WAIT; +int wd33c93_data_wait = SBIC_DATA_WAIT; +int wd33c93_init_wait = SBIC_INIT_WAIT; + +int wd33c93_nodma = 0; /* Use polled IO transfers */ +int wd33c93_nodisc = 0; /* Allow command queues */ +int wd33c93_notags = 0; /* No Tags */ + +/* + * Some useful stuff for debugging purposes + */ +#ifdef SBICDEBUG + +#define QPRINTF(a) SBIC_DEBUG(MISC, a) + +int wd33c93_debug = 0; /* Debug flags */ + +void wd33c93_print_csr (u_char); +void wd33c93_hexdump (u_char *, int); + +#else +#define QPRINTF(a) /* */ +#endif + +static const char *wd33c93_chip_names[] = SBIC_CHIP_LIST; + +/* + * Attach instance of driver and probe for sub devices + */ +void +wd33c93_attach(struct wd33c93_softc *sc, struct scsi_adapter *adapter) +{ + struct scsibus_attach_args saa; + + sc->sc_cfflags = sc->sc_dev.dv_cfdata->cf_flags; + timeout_set(&sc->sc_watchdog, wd33c93_watchdog, sc); + wd33c93_init(sc); + + printf(": %s, %d.%d MHz, %s\n", + wd33c93_chip_names[sc->sc_chip], + sc->sc_clkfreq / 10, sc->sc_clkfreq % 10, + (sc->sc_dmamode == SBIC_CTL_DMA) ? "DMA" : + (sc->sc_dmamode == SBIC_CTL_DBA_DMA) ? "DBA" : + (sc->sc_dmamode == SBIC_CTL_BURST_DMA) ? "burst DMA" : "PIO"); + if (sc->sc_chip == SBIC_CHIP_WD33C93B) { + printf("%s: microcode revision 0x%02x", + sc->sc_dev.dv_xname, sc->sc_rev); + if (sc->sc_minsyncperiod < 50) + printf(", fast SCSI"); + printf("\n"); + } + + sc->sc_link.adapter_softc = sc; + sc->sc_link.adapter_target = sc->sc_id; + sc->sc_link.adapter_buswidth = SBIC_NTARG; + sc->sc_link.adapter = adapter; + sc->sc_link.openings = 2; + sc->sc_link.luns = SBIC_NLUN; + + bzero(&saa, sizeof(saa)); + saa.saa_sc_link = &sc->sc_link; + + config_found(&sc->sc_dev, &saa, scsiprint); + timeout_add_sec(&sc->sc_watchdog, 60); +} + +/* + * Initialize driver-private structures + */ +void +wd33c93_init(struct wd33c93_softc *sc) +{ + u_int i; + + timeout_del(&sc->sc_watchdog); + + if (!wd33c93_pool_initialized) { + /* All instances share the same pool */ + pool_init(&wd33c93_pool, sizeof(struct wd33c93_acb), 0, 0, 0, + "wd33c93_acb", NULL); + ++wd33c93_pool_initialized; + } + + if (sc->sc_state == 0) { + TAILQ_INIT(&sc->ready_list); + + sc->sc_nexus = NULL; + sc->sc_disc = 0; + memset(sc->sc_tinfo, 0, sizeof(sc->sc_tinfo)); + } else { + /* XXX cancel all active commands */ + panic("wd33c93: reinitializing driver!"); + } + + sc->sc_flags = 0; + sc->sc_state = SBIC_IDLE; + wd33c93_reset(sc); + + for (i = 0; i < SBIC_NTARG; i++) { + struct wd33c93_tinfo *ti = &sc->sc_tinfo[i]; + /* + * cf_flags = 0xTTSSRR + * + * TT = Bitmask to disable Tagged Queues + * SS = Bitmask to disable Sync negotiation + * RR = Bitmask to disable disconnect/reselect + */ + ti->flags = T_NEED_RESET; + if (CFFLAGS_NOSYNC(sc->sc_cfflags, i)) + ti->flags |= T_NOSYNC; + if (CFFLAGS_NODISC(sc->sc_cfflags, i) || wd33c93_nodisc) + ti->flags |= T_NODISC; + ti->period = sc->sc_minsyncperiod; + ti->offset = 0; + } +} + +void +wd33c93_reset(struct wd33c93_softc *sc) +{ + u_int my_id, s, div, i; + u_char csr, reg; + + SET_SBIC_cmd(sc, SBIC_CMD_ABORT); + WAIT_CIP(sc); + + s = splbio(); + + if (sc->sc_reset != NULL) + (*sc->sc_reset)(sc); + + my_id = sc->sc_link.adapter_target & SBIC_ID_MASK; + + /* Enable advanced features and really(!) advanced features */ +#if 1 + my_id |= (SBIC_ID_EAF | SBIC_ID_RAF); /* XXX - MD Layer */ +#endif + + SET_SBIC_myid(sc, my_id); + + /* Reset the chip */ + SET_SBIC_cmd(sc, SBIC_CMD_RESET); + DELAY(25); + SBIC_WAIT(sc, SBIC_ASR_INT, 0); + + /* Set up various chip parameters */ + SET_SBIC_control(sc, SBIC_CTL_EDI | SBIC_CTL_IDI); + + GET_SBIC_csr(sc, csr); /* clears interrupt also */ + GET_SBIC_cdb1(sc, sc->sc_rev); /* valid with RAF on wd33c93b */ + + switch (csr) { + case SBIC_CSR_RESET: + sc->sc_chip = SBIC_CHIP_WD33C93; + break; + case SBIC_CSR_RESET_AM: + SET_SBIC_queue_tag(sc, 0x55); + GET_SBIC_queue_tag(sc, reg); + sc->sc_chip = (reg == 0x55) ? + SBIC_CHIP_WD33C93B : SBIC_CHIP_WD33C93A; + SET_SBIC_queue_tag(sc, 0x0); + break; + default: + sc->sc_chip = SBIC_CHIP_UNKNOWN; + } + + /* + * Choose a suitable clock divisor and work out the resulting + * sync transfer periods in 4ns units. + */ + if (sc->sc_clkfreq < 110) { + my_id |= SBIC_ID_FS_8_10; + div = 2; + } else if (sc->sc_clkfreq < 160) { + my_id |= SBIC_ID_FS_12_15; + div = 3; + } else if (sc->sc_clkfreq < 210) { + my_id |= SBIC_ID_FS_16_20; + div = 4; + } else + panic("wd33c93: invalid clock speed %d", sc->sc_clkfreq); + + for (i = 0; i < 7; i++) + sc->sc_syncperiods[i] = + (i + 2) * div * 1250 / sc->sc_clkfreq; + sc->sc_minsyncperiod = sc->sc_syncperiods[0]; + SBIC_DEBUG(SYNC, ("available sync periods: %d %d %d %d %d %d %d\n", + sc->sc_syncperiods[0], sc->sc_syncperiods[1], + sc->sc_syncperiods[2], sc->sc_syncperiods[3], + sc->sc_syncperiods[4], sc->sc_syncperiods[5], + sc->sc_syncperiods[6])); + + if (sc->sc_clkfreq >= 160 && sc->sc_chip == SBIC_CHIP_WD33C93B) { + for (i = 0; i < 3; i++) + sc->sc_fsyncperiods[i] = + (i + 2) * 2 * 1250 / sc->sc_clkfreq; + SBIC_DEBUG(SYNC, ("available fast sync periods: %d %d %d\n", + sc->sc_fsyncperiods[0], sc->sc_fsyncperiods[1], + sc->sc_fsyncperiods[2])); + sc->sc_minsyncperiod = sc->sc_fsyncperiods[0]; + } + + /* Max Sync Offset */ + if (sc->sc_chip == SBIC_CHIP_WD33C93A || + sc->sc_chip == SBIC_CHIP_WD33C93B) + sc->sc_maxoffset = SBIC_SYN_93AB_MAX_OFFSET; + else + sc->sc_maxoffset = SBIC_SYN_93_MAX_OFFSET; + + /* + * don't allow Selection (SBIC_RID_ES) + * until we can handle target mode!! + */ + SET_SBIC_rselid(sc, SBIC_RID_ER); + + /* Asynchronous for now */ + SET_SBIC_syn(sc, 0); + + sc->sc_flags = 0; + sc->sc_state = SBIC_IDLE; + + splx(s); +} + +void +wd33c93_error(struct wd33c93_softc *sc, struct wd33c93_acb *acb) +{ + struct scsi_xfer *xs = acb->xs; + + KASSERT(xs); + + if (xs->flags & SCSI_SILENT) + return; + + sc_print_addr(xs->sc_link); + printf("SCSI Error\n"); +} + +/* + * Determine an appropriate value for the synchronous transfer register + * given the period and offset values in *ti. + */ +u_char +wd33c93_stp2syn(struct wd33c93_softc *sc, struct wd33c93_tinfo *ti) +{ + unsigned i; + + /* see if we can handle fast scsi (100-200ns) first */ + if (ti->period < 50 && sc->sc_minsyncperiod < 50) { + for (i = 0; i < 3; i++) + if (sc->sc_fsyncperiods[i] >= ti->period) + return (SBIC_SYN(ti->offset, i + 2, 1)); + } + + for (i = 0; i < 7; i++) { + if (sc->sc_syncperiods[i] >= ti->period) { + if (i == 6) + return (SBIC_SYN(0, 0, 0)); + else + return (SBIC_SYN(ti->offset, i + 2, 0)); + } + } + + /* XXX - can't handle it; do async */ + return (SBIC_SYN(0, 0, 0)); +} + +/* + * Setup sync mode for given target + */ +void +wd33c93_setsync(struct wd33c93_softc *sc, struct wd33c93_tinfo *ti) +{ + u_char syncreg; + + if (ti->flags & T_SYNCMODE) + syncreg = wd33c93_stp2syn(sc, ti); + else + syncreg = SBIC_SYN(0, 0, 0); + + SBIC_DEBUG(SYNC, ("wd33c93_setsync: sync reg = 0x%02x\n", syncreg)); + SET_SBIC_syn(sc, syncreg); +} + +/* + * Check if current operation can be done using DMA + * + * returns 1 if DMA OK, 0 for polled I/O transfer + */ +int +wd33c93_dmaok(struct wd33c93_softc *sc, struct scsi_xfer *xs) +{ + if (wd33c93_nodma || sc->sc_dmamode == SBIC_CTL_NO_DMA || + (xs->flags & SCSI_POLL) || xs->datalen == 0) + return (0); + return(1); +} + +/* + * Setup for DMA transfer + */ +void +wd33c93_dma_setup(struct wd33c93_softc *sc, int datain) +{ + struct wd33c93_acb *acb = sc->sc_nexus; + int s; + + sc->sc_daddr = acb->daddr; + sc->sc_dleft = acb->dleft; + + s = splbio(); + /* Indicate that we're in DMA mode */ + if (sc->sc_dleft) { + sc->sc_dmasetup(sc, &sc->sc_daddr, &sc->sc_dleft, + datain, &sc->sc_dleft); + } + splx(s); + return; +} + + +/* + * Save DMA pointers. Take into account partial transfer. Shut down DMA. + */ +void +wd33c93_dma_stop(struct wd33c93_softc *sc) +{ + size_t count; + int asr; + + /* Wait until WD chip is idle */ + do { + GET_SBIC_asr(sc, asr); /* XXX */ + if (asr & SBIC_ASR_DBR) { + printf("wd33c93_dma_stop: asr %02x canceled!\n", asr); + break; + } + } while (asr & (SBIC_ASR_BSY|SBIC_ASR_CIP)); + + /* Only need to save pointers if DMA was active */ + if (sc->sc_flags & SBICF_INDMA) { + int s = splbio(); + + /* Shut down DMA and flush FIFO's */ + sc->sc_dmastop(sc); + + /* Fetch the residual count */ + SBIC_TC_GET(sc, count); + + /* Work out how many bytes were actually transferred */ + count = sc->sc_tcnt - count; + + if (sc->sc_dleft < count) + printf("xfer too large: dleft=%zu resid=%zu\n", + sc->sc_dleft, count); + + /* Fixup partial xfers */ + sc->sc_daddr = (char *)sc->sc_daddr + count; + sc->sc_dleft -= count; + sc->sc_tcnt = 0; + sc->sc_flags &= ~SBICF_INDMA; + splx(s); + SBIC_DEBUG(DMA, ("dma_stop\n")); + } + /* + * Ensure the WD chip is back in polled I/O mode, with nothing to + * transfer. + */ + SBIC_TC_PUT(sc, 0); + SET_SBIC_control(sc, SBIC_CTL_EDI | SBIC_CTL_IDI); +} + + +/* + * Handle new request from scsi layer + */ +void +wd33c93_scsi_cmd(struct scsi_xfer *xs) +{ + struct scsi_link *sc_link = xs->sc_link; + struct wd33c93_softc *sc = sc_link->adapter_softc; + struct wd33c93_acb *acb; + int flags, s; + + SBIC_DEBUG(MISC, ("wd33c93_scsi_cmd\n")); + + flags = xs->flags; + + if (sc->sc_nexus && (flags & SCSI_POLL)) + panic("wd33c93_scsicmd: busy"); + + s = splbio(); + acb = (struct wd33c93_acb *)pool_get(&wd33c93_pool, + PR_NOWAIT | PR_ZERO); + splx(s); + + if (acb == NULL) { + xs->error = XS_NO_CCB; + scsi_done(xs); + return; + } + + acb->flags = ACB_ACTIVE; + acb->xs = xs; + acb->timeout = xs->timeout; + timeout_set(&acb->to, wd33c93_timeout, acb); + + memcpy(&acb->cmd, xs->cmd, xs->cmdlen); + acb->clen = xs->cmdlen; + acb->daddr = xs->data; + acb->dleft = xs->datalen; + +#if 0 + if (flags & SCSI_POLL) { + /* + * Complete currently active command(s) before + * issuing an immediate command + */ + while (sc->sc_nexus) + wd33c93_poll(sc, sc->sc_nexus); + } +#endif + + s = splbio(); + TAILQ_INSERT_TAIL(&sc->ready_list, acb, chain); + acb->flags |= ACB_READY; + + /* If nothing is active, try to start it now. */ + if (sc->sc_state == SBIC_IDLE) + wd33c93_sched(sc); + splx(s); + + if ((flags & SCSI_POLL) == 0) + return; + + if (wd33c93_poll(sc, acb)) { + wd33c93_timeout(acb); + if (wd33c93_poll(sc, acb)) /* 2nd retry for ABORT */ + wd33c93_timeout(acb); + } +} + +/* + * attempt to start the next available command + */ +void +wd33c93_sched(struct wd33c93_softc *sc) +{ + struct scsi_link *sc_link; + struct wd33c93_acb *acb; + struct wd33c93_tinfo *ti; + struct wd33c93_linfo *li; + int lun, tag, flags; + int s; + + if (sc->sc_state != SBIC_IDLE) + return; + + KASSERT(sc->sc_nexus == NULL); + + /* Loop through the ready list looking for work to do... */ + TAILQ_FOREACH(acb, &sc->ready_list, chain) { + sc_link = acb->xs->sc_link; + lun = sc_link->lun; + ti = &sc->sc_tinfo[sc_link->target]; + + KASSERT(acb->flags & ACB_READY); + + /* Select type of tag for this command */ + if ((ti->flags & T_NODISC) != 0) + tag = 0; + else if ((ti->flags & T_TAG) == 0) + tag = 0; + else if ((acb->flags & ACB_SENSE) != 0) + tag = 0; + else if (acb->xs->flags & SCSI_POLL) + tag = 0; /* No tags for polled commands */ + else + tag = MSG_SIMPLE_Q_TAG; + + s = splbio(); + li = TINFO_LUN(ti, lun); + if (li == NULL) { + /* Initialize LUN info and add to list. */ + li = malloc(sizeof(*li), M_DEVBUF, M_NOWAIT | M_ZERO); + if (li == NULL) { + splx(s); + continue; + } + li->lun = lun; + if (lun < SBIC_NLUN) + ti->lun[lun] = li; + } + li->last_used = time_second; + + /* + * We've found a potential command, but is the target/lun busy? + */ + + if (tag == 0 && li->untagged == NULL) + li->untagged = acb; /* Issue untagged */ + + if (li->untagged != NULL) { + tag = 0; + if ((li->state != L_STATE_BUSY) && li->used == 0) { + /* Issue this untagged command now */ + acb = li->untagged; + sc_link = acb->xs->sc_link; + } else{ + /* Not ready yet */ + splx(s); + continue; + } + } + + acb->tag_type = tag; + if (tag != 0) { + int i; + + /* Allocate a tag */ + if (li->used == 255) { + /* no free tags */ + splx(s); + continue; + } + /* Start from the last used location */ + for (i = li->avail; i < 256; i++) { + if (li->queued[i] == NULL) + break; + } + /* Couldn't find one, start again from the beginning */ + if (i == 256) { + for (i = 0; i < 256; i++) { + if (li->queued[i] == NULL) + break; + } + } +#ifdef DIAGNOSTIC + if (i == 256) + panic("%s: tag alloc failure", __func__); +#endif + + /* Save where to start next time. */ + li->avail = i + 1; + li->used++; + li->queued[i] = acb; + acb->tag_id = i; + } + splx(s); + if (li->untagged != NULL && (li->state != L_STATE_BUSY)) { + li->state = L_STATE_BUSY; + break; + } + if (li->untagged == NULL && tag != 0) { + break; + } else + printf("%d:%d busy\n", sc_link->target, sc_link->lun); + } + + if (acb == NULL) { + SBIC_DEBUG(ACBS, ("wd33c93sched: no work\n")); + return; /* did not find an available command */ + } + + SBIC_DEBUG(ACBS, ("wd33c93_sched(%d,%d)\n", sc_link->target, + sc_link->lun)); + + TAILQ_REMOVE(&sc->ready_list, acb, chain); + acb->flags &= ~ACB_READY; + + flags = acb->xs->flags; + if (flags & SCSI_RESET) + wd33c93_reset(sc); + + /* XXX - Implicitly call scsidone on select timeout */ + if (wd33c93_go(sc, acb) != 0 || acb->xs->error == XS_SELTIMEOUT) { + acb->dleft = sc->sc_dleft; + wd33c93_scsidone(sc, acb, sc->sc_status); + return; + } +} + +void +wd33c93_scsidone(struct wd33c93_softc *sc, struct wd33c93_acb *acb, int status) +{ + struct scsi_xfer *xs = acb->xs; + struct scsi_link *sc_link = xs->sc_link; + struct wd33c93_tinfo *ti; + struct wd33c93_linfo *li; + int s; + +#ifdef DIAGNOSTIC + KASSERT(sc->target == sc_link->target); + KASSERT(sc->lun == sc_link->lun); + KASSERT(acb->flags != ACB_FREE); +#endif + + SBIC_DEBUG(ACBS, ("scsidone: (%d,%d)->(%d,%d)%02x\n", + sc_link->target, sc_link->lun, sc->target, sc->lun, status)); + + timeout_del(&acb->to); + + if (xs->error == XS_NOERROR) { + xs->status = status & SCSI_STATUS_MASK; + xs->resid = acb->dleft; + + switch (xs->status) { + case SCSI_CHECK: + case SCSI_TERMINATED: + /* XXX Need to read sense - return busy for now */ + /*FALLTHROUGH*/ + case SCSI_QUEUE_FULL: + case SCSI_BUSY: + xs->error = XS_BUSY; + break; + } + } + + ti = &sc->sc_tinfo[sc_link->target]; + li = TINFO_LUN(ti, sc_link->lun); + ti->cmds++; + if (xs->error == XS_SELTIMEOUT) { + /* Selection timeout -- discard this LUN if empty */ + if (li->untagged == NULL && li->used == 0) { + if (sc_link->lun < SBIC_NLUN) + ti->lun[sc_link->lun] = NULL; + free(li, M_DEVBUF); + } + } + + wd33c93_dequeue(sc, acb); + if (sc->sc_nexus == acb) { + sc->sc_state = SBIC_IDLE; + sc->sc_nexus = NULL; + sc->sc_flags = 0; + + if (!TAILQ_EMPTY(&sc->ready_list)) + wd33c93_sched(sc); + } + + /* place control block back on free list. */ + if ((xs->flags & SCSI_POLL) == 0) { + s = splbio(); + acb->flags = ACB_FREE; + pool_put(&wd33c93_pool, acb); + splx(s); + } + + scsi_done(xs); +} + +void +wd33c93_dequeue(struct wd33c93_softc *sc, struct wd33c93_acb *acb) +{ + struct wd33c93_tinfo *ti = &sc->sc_tinfo[acb->xs->sc_link->target]; + struct wd33c93_linfo *li; + int lun = acb->xs->sc_link->lun; + + li = TINFO_LUN(ti, lun); +#ifdef DIAGNOSTIC + if (li == NULL || li->lun != lun) + panic("wd33c93_dequeue: lun %d for ecb %p does not exist", + lun, acb); +#endif + if (li->untagged == acb) { + li->state = L_STATE_IDLE; + li->untagged = NULL; + } + if (acb->tag_type && li->queued[acb->tag_id] != NULL) { +#ifdef DIAGNOSTIC + if (li->queued[acb->tag_id] != NULL && + (li->queued[acb->tag_id] != acb)) + panic("wd33c93_dequeue: slot %d for lun %d has %p " + "instead of acb %p\n", acb->tag_id, + lun, li->queued[acb->tag_id], acb); +#endif + li->queued[acb->tag_id] = NULL; + li->used--; + } +} + + +int +wd33c93_wait(struct wd33c93_softc *sc, u_char until, int timeo, int line) +{ + u_char val; + + if (timeo == 0) + timeo = 1000000; /* some large value.. */ + GET_SBIC_asr(sc, val); + while ((val & until) == 0) { + if (timeo-- == 0) { + int csr; + GET_SBIC_csr(sc, csr); +#ifdef SBICDEBUG + printf("wd33c93_wait: TIMEO @%d with asr=0x%x csr=0x%x\n", + line, val, csr); +#ifdef DDB + Debugger(); +#endif +#endif + return(val); /* Maybe I should abort */ + break; + } + DELAY(1); + GET_SBIC_asr(sc, val); + } + return(val); +} + +int +wd33c93_abort(struct wd33c93_softc *sc, struct wd33c93_acb *acb, + const char *where) +{ + u_char csr, asr; + + GET_SBIC_asr(sc, asr); + GET_SBIC_csr(sc, csr); + + sc_print_addr(acb->xs->sc_link); + printf("ABORT in %s: csr=0x%02x, asr=0x%02x\n", where, csr, asr); + + acb->timeout = SBIC_ABORT_TIMEOUT; + acb->flags |= ACB_ABORT; + + /* + * Clean up chip itself + */ + if (sc->sc_nexus == acb) { + /* Reschedule timeout. */ + timeout_add_msec(&acb->to, acb->timeout); + + while (asr & SBIC_ASR_DBR) { + /* + * wd33c93 is jammed w/data. need to clear it + * But we don't know what direction it needs to go + */ + GET_SBIC_data(sc, asr); + printf("abort %s: clearing data buffer 0x%02x\n", + where, asr); + GET_SBIC_asr(sc, asr); + if (asr & SBIC_ASR_DBR) /* Not the read direction */ + SET_SBIC_data(sc, asr); + GET_SBIC_asr(sc, asr); + } + + sc_print_addr(acb->xs->sc_link); + printf("sending ABORT command\n"); + + WAIT_CIP(sc); + SET_SBIC_cmd(sc, SBIC_CMD_ABORT); + WAIT_CIP(sc); + + GET_SBIC_asr(sc, asr); + + sc_print_addr(acb->xs->sc_link); + if (asr & (SBIC_ASR_BSY|SBIC_ASR_LCI)) { + /* + * ok, get more drastic.. + */ + printf("Resetting bus\n"); + wd33c93_reset(sc); + } else { + printf("sending DISCONNECT to target\n"); + SET_SBIC_cmd(sc, SBIC_CMD_DISC); + WAIT_CIP(sc); + + do { + SBIC_WAIT (sc, SBIC_ASR_INT, 0); + GET_SBIC_asr(sc, asr); + GET_SBIC_csr(sc, csr); + SBIC_DEBUG(MISC, ("csr: 0x%02x, asr: 0x%02x\n", + csr, asr)); + } while ((csr != SBIC_CSR_DISC) && + (csr != SBIC_CSR_DISC_1) && + (csr != SBIC_CSR_CMD_INVALID)); + } + sc->sc_state = SBIC_ERROR; + sc->sc_flags = 0; + } + return SBIC_STATE_ERROR; +} + + +/* + * select the bus, return when selected or error. + * + * Returns the current CSR following selection and optionally MSG out phase. + * i.e. the returned CSR *should* indicate CMD phase... + * If the return value is 0, some error happened. + */ +u_char +wd33c93_selectbus(struct wd33c93_softc *sc, struct wd33c93_acb *acb) +{ + struct scsi_xfer *xs = acb->xs; + struct scsi_link *sc_link = xs->sc_link; + struct wd33c93_tinfo *ti; + u_char target, lun, asr, csr, id; + + KASSERT(sc->sc_state == SBIC_IDLE); + + target = sc_link->target; + lun = sc_link->lun; + ti = &sc->sc_tinfo[target]; + + sc->sc_state = SBIC_SELECTING; + sc->target = target; + sc->lun = lun; + + SBIC_DEBUG(PHASE, ("wd33c93_selectbus %d: ", target)); + + if ((xs->flags & SCSI_POLL) == 0) + timeout_add_msec(&acb->to, acb->timeout); + + /* + * issue select + */ + SBIC_TC_PUT(sc, 0); + SET_SBIC_selid(sc, target); + SET_SBIC_timeo(sc, SBIC_TIMEOUT(250, sc->sc_clkfreq)); + + GET_SBIC_asr(sc, asr); + if (asr & (SBIC_ASR_INT|SBIC_ASR_BSY)) { + /* This means we got ourselves reselected upon */ + SBIC_DEBUG(PHASE, ("WD busy (reselect?) ASR=%02x\n", asr)); + return 0; + } + + SET_SBIC_cmd(sc, SBIC_CMD_SEL_ATN); + WAIT_CIP(sc); + + /* + * wait for select (merged from separate function may need + * cleanup) + */ + do { + asr = SBIC_WAIT(sc, SBIC_ASR_INT | SBIC_ASR_LCI, 0); + if (asr & SBIC_ASR_LCI) { + QPRINTF(("late LCI: asr %02x\n", asr)); + return 0; + } + + /* Clear interrupt */ + GET_SBIC_csr (sc, csr); + + /* Reselected from under our feet? */ + if (csr == SBIC_CSR_RSLT_NI || csr == SBIC_CSR_RSLT_IFY) { + SBIC_DEBUG(PHASE, ("got reselected, asr %02x\n", asr)); + /* + * We need to handle this now so we don't lock up later + */ + wd33c93_nextstate(sc, acb, csr, asr); + return 0; + } + + /* Whoops! */ + if (csr == SBIC_CSR_SLT || csr == SBIC_CSR_SLT_ATN) { + panic("wd33c93_selectbus: target issued select!"); + return 0; + } + + } while (csr != (SBIC_CSR_MIS_2 | MESG_OUT_PHASE) && + csr != (SBIC_CSR_MIS_2 | CMD_PHASE) && + csr != SBIC_CSR_SEL_TIMEO); + + /* Anyone at home? */ + if (csr == SBIC_CSR_SEL_TIMEO) { + xs->error = XS_SELTIMEOUT; + SBIC_DEBUG(PHASE, ("-- Selection Timeout\n")); + return 0; + } + + SBIC_DEBUG(PHASE, ("Selection Complete\n")); + + /* Assume we're now selected */ + GET_SBIC_selid(sc, id); + if (id != target) { + /* Something went wrong - wrong target was select */ + printf("wd33c93_selectbus: wrong target selected;" + " WANTED %d GOT %d", target, id); + return 0; /* XXX: Need to call nexstate to handle? */ + } + + sc->sc_flags |= SBICF_SELECTED; + sc->sc_state = SBIC_CONNECTED; + + /* setup correct sync mode for this target */ + wd33c93_setsync(sc, ti); + + if (ti->flags & T_NODISC && sc->sc_disc == 0) + SET_SBIC_rselid (sc, 0); /* Not expecting a reselect */ + else + SET_SBIC_rselid (sc, SBIC_RID_ER); + + /* + * We only really need to do anything when the target goes to MSG out + * If the device ignored ATN, it's probably old and brain-dead, + * but we'll try to support it anyhow. + * If it doesn't support message out, it definately doesn't + * support synchronous transfers, so no point in even asking... + */ + if (csr == (SBIC_CSR_MIS_2 | MESG_OUT_PHASE)) { + if (ti->flags & T_NEGOTIATE) { + /* Initiate a SDTR message */ + SBIC_DEBUG(SYNC, ("Sending SDTR to target %d\n", id)); + if (ti->flags & T_WANTSYNC) { + ti->period = sc->sc_minsyncperiod; + ti->offset = sc->sc_maxoffset; + } else { + ti->period = 0; + ti->offset = 0; + } + /* Send Sync negotiation message */ + sc->sc_omsg[0] = MSG_IDENTIFY(lun, 0); /* No Disc */ + sc->sc_omsg[1] = MSG_EXTENDED; + sc->sc_omsg[2] = MSG_EXT_SDTR_LEN; + sc->sc_omsg[3] = MSG_EXT_SDTR; + if (ti->flags & T_WANTSYNC) { + sc->sc_omsg[4] = sc->sc_minsyncperiod; + sc->sc_omsg[5] = sc->sc_maxoffset; + } else { + sc->sc_omsg[4] = 0; + sc->sc_omsg[5] = 0; + } + wd33c93_xfout(sc, 6, sc->sc_omsg); + sc->sc_msgout |= SEND_SDTR; /* may be rejected */ + sc->sc_flags |= SBICF_SYNCNEGO; + } else { + if (sc->sc_nexus->tag_type != 0) { + /* Use TAGS */ + SBIC_DEBUG(TAGS, ("<select %d:%d TAG=%x>\n", + sc->target, sc->lun, + sc->sc_nexus->tag_id)); + sc->sc_omsg[0] = MSG_IDENTIFY(lun, 1); + sc->sc_omsg[1] = sc->sc_nexus->tag_type; + sc->sc_omsg[2] = sc->sc_nexus->tag_id; + wd33c93_xfout(sc, 3, sc->sc_omsg); + sc->sc_msgout |= SEND_TAG; + } else { + int no_disc; + + /* Setup LUN nexus and disconnect privilege */ + no_disc = xs->flags & SCSI_POLL || + ti->flags & T_NODISC; + SEND_BYTE(sc, MSG_IDENTIFY(lun, !no_disc)); + } + } + /* + * There's one interrupt still to come: + * the change to CMD phase... + */ + SBIC_WAIT(sc, SBIC_ASR_INT , 0); + GET_SBIC_csr(sc, csr); + } + + return csr; +} + +/* + * Information Transfer *to* a SCSI Target. + * + * Note: Don't expect there to be an interrupt immediately after all + * the data is transferred out. The WD spec sheet says that the Transfer- + * Info command for non-MSG_IN phases only completes when the target + * next asserts 'REQ'. That is, when the SCSI bus changes to a new state. + * + * This can have a nasty effect on commands which take a relatively long + * time to complete, for example a START/STOP unit command may remain in + * CMD phase until the disk has spun up. Only then will the target change + * to STATUS phase. This is really only a problem for immediate commands + * since we don't allow disconnection for them (yet). + */ +int +wd33c93_xfout(struct wd33c93_softc *sc, int len, void *bp) +{ + int wait = wd33c93_data_wait; + u_char asr, *buf = bp; + + QPRINTF(("wd33c93_xfout {%d} %02x %02x %02x %02x %02x " + "%02x %02x %02x %02x %02x\n", len, buf[0], buf[1], buf[2], + buf[3], buf[4], buf[5], buf[6], buf[7], buf[8], buf[9])); + + /* + * sigh.. WD-PROTO strikes again.. sending the command in one go + * causes the chip to lock up if talking to certain (misbehaving?) + * targets. Anyway, this procedure should work for all targets, but + * it's slightly slower due to the overhead + */ + + SET_SBIC_control(sc, SBIC_CTL_EDI | SBIC_CTL_IDI); + SBIC_TC_PUT (sc, (unsigned)len); + + WAIT_CIP (sc); + SET_SBIC_cmd (sc, SBIC_CMD_XFER_INFO); + + /* + * Loop for each byte transferred + */ + do { + GET_SBIC_asr (sc, asr); + + if (asr & SBIC_ASR_DBR) { + if (len) { + SET_SBIC_data (sc, *buf); + buf++; + len--; + } else { + SET_SBIC_data (sc, 0); + } + wait = wd33c93_data_wait; + } + } while (len && (asr & SBIC_ASR_INT) == 0 && wait-- > 0); + + QPRINTF(("wd33c93_xfout done: %d bytes remaining (wait:%d)\n", len, wait)); + + /* + * Normally, an interrupt will be pending when this routing returns. + */ + return(len); +} + +/* + * Information Transfer *from* a Scsi Target + * returns # bytes left to read + */ +int +wd33c93_xfin(struct wd33c93_softc *sc, int len, void *bp) +{ + int wait = wd33c93_data_wait; + u_char *buf = bp; + u_char asr; +#ifdef SBICDEBUG + u_char *obp = bp; +#endif + SET_SBIC_control(sc, SBIC_CTL_EDI | SBIC_CTL_IDI); + SBIC_TC_PUT (sc, (unsigned)len); + + WAIT_CIP (sc); + SET_SBIC_cmd (sc, SBIC_CMD_XFER_INFO); + + /* + * Loop for each byte transferred + */ + do { + GET_SBIC_asr (sc, asr); + + if (asr & SBIC_ASR_DBR) { + if (len) { + GET_SBIC_data (sc, *buf); + buf++; + len--; + } else { + u_char foo; + GET_SBIC_data (sc, foo); + } + wait = wd33c93_data_wait; + } + + } while ((asr & SBIC_ASR_INT) == 0 && wait-- > 0); + + QPRINTF(("wd33c93_xfin {%d} %02x %02x %02x %02x %02x %02x " + "%02x %02x %02x %02x\n", len, obp[0], obp[1], obp[2], + obp[3], obp[4], obp[5], obp[6], obp[7], obp[8], obp[9])); + + SBIC_TC_PUT (sc, 0); + + /* + * this leaves with one csr to be read + */ + return len; +} + + +/* + * Finish SCSI xfer command: After the completion interrupt from + * a read/write operation, sequence through the final phases in + * programmed i/o. + */ +void +wd33c93_xferdone(struct wd33c93_softc *sc) +{ + u_char phase, csr; + int s; + + QPRINTF(("{")); + s = splbio(); + + /* + * have the wd33c93 complete on its own + */ + SBIC_TC_PUT(sc, 0); + SET_SBIC_cmd_phase(sc, 0x46); + SET_SBIC_cmd(sc, SBIC_CMD_SEL_ATN_XFER); + + do { + SBIC_WAIT (sc, SBIC_ASR_INT, 0); + GET_SBIC_csr (sc, csr); + QPRINTF(("%02x:", csr)); + } while ((csr != SBIC_CSR_DISC) && + (csr != SBIC_CSR_DISC_1) && + (csr != SBIC_CSR_S_XFERRED)); + + sc->sc_flags &= ~SBICF_SELECTED; + sc->sc_state = SBIC_DISCONNECT; + + GET_SBIC_cmd_phase (sc, phase); + QPRINTF(("}%02x", phase)); + + if (phase == 0x60) + GET_SBIC_tlun(sc, sc->sc_status); + else + wd33c93_error(sc, sc->sc_nexus); + + QPRINTF(("=STS:%02x=\n", sc->sc_status)); + splx(s); +} + + +int +wd33c93_go(struct wd33c93_softc *sc, struct wd33c93_acb *acb) +{ + struct scsi_xfer *xs = acb->xs; + struct scsi_link *sc_link = xs->sc_link; + int i, dmaok; + u_char csr, asr; + + SBIC_DEBUG(ACBS, ("wd33c93_go(%d:%d)\n", sc_link->target, sc_link->lun)); + + sc->sc_nexus = acb; + + sc->target = sc_link->target; + sc->lun = sc_link->lun; + + sc->sc_status = STATUS_UNKNOWN; + sc->sc_daddr = acb->daddr; + sc->sc_dleft = acb->dleft; + + sc->sc_msgpriq = sc->sc_msgout = sc->sc_msgoutq = 0; + sc->sc_flags = 0; + + dmaok = wd33c93_dmaok(sc, xs); + + if (dmaok == 0) + sc->sc_flags |= SBICF_NODMA; + + SBIC_DEBUG(DMA, ("wd33c93_go dmago:%d(tcnt=%zx) dmaok=%d\n", + sc->target, sc->sc_tcnt, dmaok)); + + /* select the SCSI bus (it's an error if bus isn't free) */ + if ((csr = wd33c93_selectbus(sc, acb)) == 0) + return(0); /* Not done: needs to be rescheduled */ + + /* + * Lets cycle a while then let the interrupt handler take over. + */ + GET_SBIC_asr(sc, asr); + do { + QPRINTF(("go[0x%x] ", csr)); + + /* Handle the new phase */ + i = wd33c93_nextstate(sc, acb, csr, asr); + WAIT_CIP(sc); /* XXX */ + if (sc->sc_state == SBIC_CONNECTED) { + + GET_SBIC_asr(sc, asr); + + if (asr & SBIC_ASR_LCI) + printf("wd33c93_go: LCI asr:%02x csr:%02x\n", asr, csr); + + if (asr & SBIC_ASR_INT) + GET_SBIC_csr(sc, csr); + } + + } while (sc->sc_state == SBIC_CONNECTED && + asr & (SBIC_ASR_INT|SBIC_ASR_LCI)); + + QPRINTF(("> done i=%d stat=%02x\n", i, sc->sc_status)); + + if (i == SBIC_STATE_DONE) { + if (sc->sc_status == STATUS_UNKNOWN) { + printf("wd33c93_go: done & stat == UNKNOWN\n"); + return 1; /* Did we really finish that fast? */ + } + } + return 0; +} + + +int +wd33c93_intr(void *v) +{ + struct wd33c93_softc *sc = v; + u_char asr, csr; + int i; + + /* + * pending interrupt? + */ + GET_SBIC_asr (sc, asr); + if ((asr & SBIC_ASR_INT) == 0) + return(0); + + GET_SBIC_csr(sc, csr); + + do { + SBIC_DEBUG(INTS, ("intr[csr=0x%x]", csr)); + + i = wd33c93_nextstate(sc, sc->sc_nexus, csr, asr); + WAIT_CIP(sc); /* XXX */ + if (sc->sc_state == SBIC_CONNECTED) { + GET_SBIC_asr(sc, asr); + + if (asr & SBIC_ASR_LCI) + printf("wd33c93_intr: LCI asr:%02x csr:%02x\n", + asr, csr); + + if (asr & SBIC_ASR_INT) + GET_SBIC_csr(sc, csr); + } + } while (sc->sc_state == SBIC_CONNECTED && + asr & (SBIC_ASR_INT|SBIC_ASR_LCI)); + + SBIC_DEBUG(INTS, ("intr done. state=%d, asr=0x%02x\n", i, asr)); + + return(1); +} + +/* + * Complete current command using polled I/O. Used when interrupt driven + * I/O is not allowed (ie. during boot and shutdown) + * + * Polled I/O is very processor intensive + */ +int +wd33c93_poll(struct wd33c93_softc *sc, struct wd33c93_acb *acb) +{ + u_char asr, csr=0; + int i, count; + struct scsi_xfer *xs = acb->xs; + int s; + + SBIC_WAIT(sc, SBIC_ASR_INT, wd33c93_cmd_wait); + for (count = acb->timeout; count;) { + GET_SBIC_asr(sc, asr); + if (asr & SBIC_ASR_LCI) + printf("wd33c93_poll: LCI; asr:%02x csr:%02x\n", + asr, csr); + if (asr & SBIC_ASR_INT) { + GET_SBIC_csr(sc, csr); + sc->sc_flags |= SBICF_NODMA; + i = wd33c93_nextstate(sc, sc->sc_nexus, csr, asr); + WAIT_CIP(sc); /* XXX */ + } else { + DELAY(1000); + count--; + } + + if ((xs->flags & ITSDONE) != 0) { + s = splbio(); + acb->flags = ACB_FREE; + pool_put(&wd33c93_pool, acb); + splx(s); + + return (0); + } + + if (sc->sc_state == SBIC_IDLE) { + SBIC_DEBUG(ACBS, ("[poll: rescheduling] ")); + wd33c93_sched(sc); + } + } + return (1); +} + +static inline int +__verify_msg_format(u_char *p, int len) +{ + if (len == 1 && IS1BYTEMSG(p[0])) + return 1; + if (len == 2 && IS2BYTEMSG(p[0])) + return 1; + if (len >= 3 && ISEXTMSG(p[0]) && + len == p[1] + 2) + return 1; + return 0; +} + +/* + * Handle message_in phase + */ +int +wd33c93_msgin_phase(struct wd33c93_softc *sc, int reselect) +{ + int len; + u_char asr, csr, *msg; + + GET_SBIC_asr(sc, asr); + + SBIC_DEBUG(MSGS, ("wd33c93msgin asr=%02x\n", asr)); + + GET_SBIC_selid (sc, csr); + SET_SBIC_selid (sc, csr | SBIC_SID_FROM_SCSI); + + SBIC_TC_PUT(sc, 0); + + SET_SBIC_control(sc, SBIC_CTL_EDI | SBIC_CTL_IDI); + + msg = sc->sc_imsg; + len = 0; + + do { + /* Fetch the next byte of the message */ + RECV_BYTE(sc, *msg++); + len++; + + /* + * get the command completion interrupt, or we + * can't send a new command (LCI) + */ + SBIC_WAIT(sc, SBIC_ASR_INT, 0); + GET_SBIC_csr(sc, csr); + + if (__verify_msg_format(sc->sc_imsg, len)) + break; /* Complete message received */ + + /* + * Clear ACK, and wait for the interrupt + * for the next byte or phase change + */ + SET_SBIC_cmd(sc, SBIC_CMD_CLR_ACK); + SBIC_WAIT(sc, SBIC_ASR_INT, 0); + + GET_SBIC_csr(sc, csr); + } while (len < SBIC_MAX_MSGLEN); + + if (__verify_msg_format(sc->sc_imsg, len)) + wd33c93_msgin(sc, sc->sc_imsg, len); + + /* + * Clear ACK, and wait for the interrupt + * for the phase change + */ + SET_SBIC_cmd(sc, SBIC_CMD_CLR_ACK); + SBIC_WAIT(sc, SBIC_ASR_INT, 0); + + /* Should still have one CSR to read */ + return SBIC_STATE_RUNNING; +} + + +void wd33c93_msgin(struct wd33c93_softc *sc, u_char *msgaddr, int msglen) +{ + struct wd33c93_acb *acb = sc->sc_nexus; + struct wd33c93_tinfo *ti = &sc->sc_tinfo[sc->target]; + struct wd33c93_linfo *li; + u_char asr; + + switch (sc->sc_state) { + case SBIC_CONNECTED: + switch (msgaddr[0]) { + case MSG_MESSAGE_REJECT: + SBIC_DEBUG(MSGS, ("msgin: MSG_REJECT, " + "last msgout=%x\n", sc->sc_msgout)); + switch (sc->sc_msgout) { + case SEND_TAG: + printf("%s: tagged queuing rejected: " + "target %d\n", + sc->sc_dev.dv_xname, sc->target); + ti->flags &= ~T_TAG; + li = TINFO_LUN(ti, sc->lun); + if (acb->tag_type && + li->queued[acb->tag_id] != NULL) { + li->queued[acb->tag_id] = NULL; + li->used--; + } + acb->tag_type = acb->tag_id = 0; + li->untagged = acb; + li->state = L_STATE_BUSY; + break; + + case SEND_SDTR: + printf("%s: sync transfer rejected: target %d\n", + sc->sc_dev.dv_xname, sc->target); + + sc->sc_flags &= ~SBICF_SYNCNEGO; + ti->flags &= ~(T_NEGOTIATE | T_SYNCMODE); + wd33c93_setsync(sc, ti); + + case SEND_INIT_DET_ERR: + goto abort; + + default: + SBIC_DEBUG(MSGS, ("Unexpected MSG_REJECT\n")); + break; + } + sc->sc_msgout = 0; + break; + + case MSG_HEAD_OF_Q_TAG: + case MSG_ORDERED_Q_TAG: + case MSG_SIMPLE_Q_TAG: + printf("-- Out of phase TAG;" + "Nexus=%d:%d Tag=%02x/%02x\n", + sc->target, sc->lun, msgaddr[0], msgaddr[1]); + break; + + case MSG_DISCONNECT: + SBIC_DEBUG(MSGS, ("msgin: DISCONNECT")); + /* + * Mark the fact that all bytes have moved. The + * target may not bother to do a SAVE POINTERS + * at this stage. This flag will set the residual + * count to zero on MSG COMPLETE. + */ + if (sc->sc_dleft == 0) + acb->flags |= ACB_COMPLETE; + + if (acb->xs->flags & SCSI_POLL) + /* Don't allow disconnect in immediate mode */ + goto reject; + else { /* Allow disconnect */ + sc->sc_flags &= ~SBICF_SELECTED; + sc->sc_state = SBIC_DISCONNECT; + } + if ((acb->xs->sc_link->quirks & SDEV_AUTOSAVE) == 0) + break; + /*FALLTHROUGH*/ + + case MSG_SAVEDATAPOINTER: + SBIC_DEBUG(MSGS, ("msgin: SAVEDATAPTR")); + acb->daddr = sc->sc_daddr; + acb->dleft = sc->sc_dleft; + break; + + case MSG_RESTOREPOINTERS: + SBIC_DEBUG(MSGS, ("msgin: RESTOREPTR")); + sc->sc_daddr = acb->daddr; + sc->sc_dleft = acb->dleft; + break; + + case MSG_CMDCOMPLETE: + /* + * !! KLUDGE ALERT !! quite a few drives don't seem to + * really like the current way of sending the + * sync-handshake together with the ident-message, and + * they react by sending command-complete and + * disconnecting right after returning the valid sync + * handshake. So, all I can do is reselect the drive, + * and hope it won't disconnect again. I don't think + * this is valid behavior, but I can't help fixing a + * problem that apparently exists. + * + * Note: we should not get here on `normal' command + * completion, as that condition is handled by the + * high-level sel&xfer resume command used to walk + * thru status/cc-phase. + */ + SBIC_DEBUG(MSGS, ("msgin: CMD_COMPLETE")); + SBIC_DEBUG(SYNC, ("GOT MSG %d! target %d" + " acting weird.." + " waiting for disconnect...\n", + msgaddr[0], sc->target)); + + /* Check to see if wd33c93 is handling this */ + GET_SBIC_asr(sc, asr); + if (asr & SBIC_ASR_BSY) + break; + + /* XXX: Assume it works and set status to 00 */ + sc->sc_status = 0; + sc->sc_state = SBIC_CMDCOMPLETE; + break; + + case MSG_EXTENDED: + switch(msgaddr[2]) { + case MSG_EXT_SDTR: /* Sync negotiation */ + SBIC_DEBUG(MSGS, ("msgin: EXT_SDTR; " + "period %d, offset %d", + msgaddr[3], msgaddr[4])); + if (msgaddr[1] != 3) + goto reject; + + ti->period = + MAX(msgaddr[3], sc->sc_minsyncperiod); + ti->offset = MIN(msgaddr[4], sc->sc_maxoffset); + + /* + * <SGI, IBM DORS-32160, WA6A> will do nothing + * but attempt sync negotiation until it gets + * what it wants. To avoid an infinite loop set + * off by the identify request, oblige them. + */ + if ((sc->sc_flags&SBICF_SYNCNEGO) == 0 && + msgaddr[3] != 0) + ti->flags |= T_WANTSYNC; + + if (!(ti->flags & T_WANTSYNC)) + ti->period = ti->offset = 0; + + ti->flags &= ~T_NEGOTIATE; + + if (ti->offset == 0) + ti->flags &= ~T_SYNCMODE; /* Async */ + else + ti->flags |= T_SYNCMODE; /* Sync */ + + /* target initiated negotiation */ + if ((sc->sc_flags&SBICF_SYNCNEGO) == 0) + wd33c93_sched_msgout(sc, SEND_SDTR); + sc->sc_flags &= ~SBICF_SYNCNEGO; + + SBIC_DEBUG(SYNC, ("msgin(%d): SDTR(o=%d,p=%d)", + sc->target, ti->offset, + ti->period)); + wd33c93_setsync(sc, ti); + break; + + case MSG_EXT_WDTR: + SBIC_DEBUG(MSGS, ("msgin: EXT_WDTR rejected")); + goto reject; + + default: + sc_print_addr(acb->xs->sc_link); + printf("unrecognized MESSAGE EXTENDED;" + " sending REJECT\n"); + goto reject; + } + break; + + default: + sc_print_addr(acb->xs->sc_link); + printf("unrecognized MESSAGE; sending REJECT\n"); + + reject: + /* We don't support whatever this message is... */ + wd33c93_sched_msgout(sc, SEND_REJECT); + break; + } + break; + + case SBIC_IDENTIFIED: + /* + * IDENTIFY message was received and queue tag is expected now + */ + if ((msgaddr[0]!=MSG_SIMPLE_Q_TAG) || (sc->sc_msgify==0)) { + printf("%s: TAG reselect without IDENTIFY;" + " MSG %x; sending DEVICE RESET\n", + sc->sc_dev.dv_xname, msgaddr[0]); + goto reset; + } + SBIC_DEBUG(TAGS, ("TAG %x/%x\n", msgaddr[0], msgaddr[1])); + if (sc->sc_nexus) + printf("*TAG Recv with active nexus!!\n"); + wd33c93_reselect(sc, sc->target, sc->lun, + msgaddr[0], msgaddr[1]); + break; + + case SBIC_RESELECTED: + /* + * IDENTIFY message with target + */ + if (MSG_ISIDENTIFY(msgaddr[0])) { + SBIC_DEBUG(PHASE, ("IFFY[%x] ", msgaddr[0])); + sc->sc_msgify = msgaddr[0]; + } else { + printf("%s: reselect without IDENTIFY;" + " MSG %x;" + " sending DEVICE RESET\n", + sc->sc_dev.dv_xname, msgaddr[0]); + goto reset; + } + break; + + default: + printf("%s: unexpected MESSAGE IN. State=%d - Sending RESET\n", + sc->sc_dev.dv_xname, sc->sc_state); + reset: + wd33c93_sched_msgout(sc, SEND_DEV_RESET); + break; + abort: + wd33c93_sched_msgout(sc, SEND_ABORT); + break; + } +} + +void +wd33c93_sched_msgout(struct wd33c93_softc *sc, u_short msg) +{ + u_char asr; + + SBIC_DEBUG(SYNC,("sched_msgout: %04x\n", msg)); + sc->sc_msgpriq |= msg; + + /* Schedule MSGOUT Phase to send message */ + + WAIT_CIP(sc); + SET_SBIC_cmd(sc, SBIC_CMD_SET_ATN); + WAIT_CIP(sc); + GET_SBIC_asr(sc, asr); + if (asr & SBIC_ASR_LCI) { + printf("MSGOUT Failed!\n"); + } + SET_SBIC_cmd(sc, SBIC_CMD_CLR_ACK); + WAIT_CIP(sc); +} + +/* + * Send the highest priority, scheduled message + */ +void +wd33c93_msgout(struct wd33c93_softc *sc) +{ + struct wd33c93_tinfo *ti; + struct wd33c93_acb *acb = sc->sc_nexus; + + if (acb == NULL) + panic("MSGOUT with no nexus"); + + if (sc->sc_omsglen == 0) { + /* Pick up highest priority message */ + sc->sc_msgout = sc->sc_msgpriq & -sc->sc_msgpriq; + sc->sc_msgoutq |= sc->sc_msgout; + sc->sc_msgpriq &= ~sc->sc_msgout; + sc->sc_omsglen = 1; /* "Default" message len */ + switch (sc->sc_msgout) { + case SEND_SDTR: + ti = &sc->sc_tinfo[acb->xs->sc_link->target]; + sc->sc_omsg[0] = MSG_EXTENDED; + sc->sc_omsg[1] = MSG_EXT_SDTR_LEN; + sc->sc_omsg[2] = MSG_EXT_SDTR; + if (ti->flags & T_WANTSYNC) { + sc->sc_omsg[3] = ti->period; + sc->sc_omsg[4] = ti->offset; + } else { + sc->sc_omsg[3] = 0; + sc->sc_omsg[4] = 0; + } + sc->sc_omsglen = 5; + if ((sc->sc_flags & SBICF_SYNCNEGO) == 0) { + if (ti->flags & T_WANTSYNC) + ti->flags |= T_SYNCMODE; + else + ti->flags &= ~T_SYNCMODE; + wd33c93_setsync(sc, ti); + } + break; + case SEND_IDENTIFY: + if (sc->sc_state != SBIC_CONNECTED) { + printf("%s at line %d: no nexus\n", + sc->sc_dev.dv_xname, __LINE__); + } + sc->sc_omsg[0] = + MSG_IDENTIFY(acb->xs->sc_link->lun, 0); + break; + case SEND_TAG: + if (sc->sc_state != SBIC_CONNECTED) { + printf("%s at line %d: no nexus\n", + sc->sc_dev.dv_xname, __LINE__); + } + sc->sc_omsg[0] = acb->tag_type; + sc->sc_omsg[1] = acb->tag_id; + sc->sc_omsglen = 2; + break; + case SEND_DEV_RESET: + sc->sc_omsg[0] = MSG_BUS_DEV_RESET; + ti = &sc->sc_tinfo[sc->target]; + ti->flags &= ~T_SYNCMODE; + if ((ti->flags & T_NOSYNC) == 0) + /* We can re-start sync negotiation */ + ti->flags |= T_NEGOTIATE; + break; + case SEND_PARITY_ERROR: + sc->sc_omsg[0] = MSG_PARITY_ERROR; + break; + case SEND_ABORT: + sc->sc_flags |= SBICF_ABORTING; + sc->sc_omsg[0] = MSG_ABORT; + break; + case SEND_INIT_DET_ERR: + sc->sc_omsg[0] = MSG_INITIATOR_DET_ERR; + break; + case SEND_REJECT: + sc->sc_omsg[0] = MSG_MESSAGE_REJECT; + break; + default: + /* Wasn't expecting MSGOUT Phase */ + sc->sc_omsg[0] = MSG_NOOP; + break; + } + } + + wd33c93_xfout(sc, sc->sc_omsglen, sc->sc_omsg); +} + + +/* + * wd33c93_nextstate() + * return: + * SBIC_STATE_DONE == done + * SBIC_STATE_RUNNING == working + * SBIC_STATE_DISCONNECT == disconnected + * SBIC_STATE_ERROR == error + */ +int +wd33c93_nextstate(struct wd33c93_softc *sc, struct wd33c93_acb *acb, u_char csr, u_char asr) +{ + SBIC_DEBUG(PHASE, ("next[a=%02x,c=%02x]: ",asr,csr)); + + switch (csr) { + + case SBIC_CSR_XFERRED | CMD_PHASE: + case SBIC_CSR_MIS | CMD_PHASE: + case SBIC_CSR_MIS_1 | CMD_PHASE: + case SBIC_CSR_MIS_2 | CMD_PHASE: + + if (wd33c93_xfout(sc, acb->clen, &acb->cmd)) + goto abort; + break; + + case SBIC_CSR_XFERRED | STATUS_PHASE: + case SBIC_CSR_MIS | STATUS_PHASE: + case SBIC_CSR_MIS_1 | STATUS_PHASE: + case SBIC_CSR_MIS_2 | STATUS_PHASE: + + SET_SBIC_control(sc, SBIC_CTL_EDI | SBIC_CTL_IDI); + + /* + * this should be the normal i/o completion case. + * get the status & cmd complete msg then let the + * device driver look at what happened. + */ + wd33c93_xferdone(sc); + + wd33c93_dma_stop(sc); + + /* Fixup byte count to be passed to higher layer */ + acb->dleft = (acb->flags & ACB_COMPLETE) ? 0 : + sc->sc_dleft; + + /* + * Indicate to the upper layers that the command is done + */ + wd33c93_scsidone(sc, acb, sc->sc_status); + + return SBIC_STATE_DONE; + + + case SBIC_CSR_XFERRED | DATA_IN_PHASE: + case SBIC_CSR_MIS | DATA_IN_PHASE: + case SBIC_CSR_MIS_1 | DATA_IN_PHASE: + case SBIC_CSR_MIS_2 | DATA_IN_PHASE: + case SBIC_CSR_XFERRED | DATA_OUT_PHASE: + case SBIC_CSR_MIS | DATA_OUT_PHASE: + case SBIC_CSR_MIS_1 | DATA_OUT_PHASE: + case SBIC_CSR_MIS_2 | DATA_OUT_PHASE: + /* + * Verify that we expected to transfer data... + */ + if (acb->dleft <= 0) { + printf("next: DATA phase with xfer count == %zd, asr:0x%02x csr:0x%02x\n", + acb->dleft, asr, csr); + goto abort; + } + + /* + * Should we transfer using PIO or DMA ? + */ + if (acb->xs->flags & SCSI_POLL || + sc->sc_flags & SBICF_NODMA) { + /* Perfrom transfer using PIO */ + int resid; + + SBIC_DEBUG(DMA, ("PIO xfer: %d(%p:%zx)\n", sc->target, + sc->sc_daddr, sc->sc_dleft)); + + if (SBIC_PHASE(csr) == DATA_IN_PHASE) + /* data in */ + resid = wd33c93_xfin(sc, sc->sc_dleft, + sc->sc_daddr); + else /* data out */ + resid = wd33c93_xfout(sc, sc->sc_dleft, + sc->sc_daddr); + + sc->sc_daddr = (char *)sc->sc_daddr + + (acb->dleft - resid); + sc->sc_dleft = resid; + } else { + int datain = SBIC_PHASE(csr) == DATA_IN_PHASE; + + /* Perform transfer using DMA */ + wd33c93_dma_setup(sc, datain); + + SET_SBIC_control(sc, SBIC_CTL_EDI | SBIC_CTL_IDI | + sc->sc_dmamode); + + SBIC_DEBUG(DMA, ("DMA xfer: %d(%p:%zx)\n", sc->target, + sc->sc_daddr, sc->sc_dleft)); + + /* Setup byte count for transfer */ + SBIC_TC_PUT(sc, (unsigned)sc->sc_dleft); + + /* Start the transfer */ + SET_SBIC_cmd(sc, SBIC_CMD_XFER_INFO); + + /* Start the DMA chip going */ + sc->sc_tcnt = sc->sc_dmago(sc); + + /* Indicate that we're in DMA mode */ + sc->sc_flags |= SBICF_INDMA; + } + break; + + case SBIC_CSR_XFERRED | MESG_IN_PHASE: + case SBIC_CSR_MIS | MESG_IN_PHASE: + case SBIC_CSR_MIS_1 | MESG_IN_PHASE: + case SBIC_CSR_MIS_2 | MESG_IN_PHASE: + + wd33c93_dma_stop(sc); + + /* Handle a single message in... */ + return wd33c93_msgin_phase(sc, 0); + + case SBIC_CSR_MSGIN_W_ACK: + + /* + * We should never see this since it's handled in + * 'wd33c93_msgin_phase()' but just for the sake of paranoia... + */ + SET_SBIC_cmd(sc, SBIC_CMD_CLR_ACK); + + printf("Acking unknown msgin CSR:%02x",csr); + break; + + case SBIC_CSR_XFERRED | MESG_OUT_PHASE: + case SBIC_CSR_MIS | MESG_OUT_PHASE: + case SBIC_CSR_MIS_1 | MESG_OUT_PHASE: + case SBIC_CSR_MIS_2 | MESG_OUT_PHASE: + + /* + * Message out phase. ATN signal has been asserted + */ + wd33c93_dma_stop(sc); + wd33c93_msgout(sc); + return SBIC_STATE_RUNNING; + + case SBIC_CSR_DISC: + case SBIC_CSR_DISC_1: + SBIC_DEBUG(RSEL, ("wd33c93next target %d disconnected\n", + sc->target)); + wd33c93_dma_stop(sc); + + sc->sc_nexus = NULL; + sc->sc_state = SBIC_IDLE; + sc->sc_flags = 0; + + ++sc->sc_tinfo[sc->target].dconns; + ++sc->sc_disc; + + if (acb->xs->flags & SCSI_POLL || wd33c93_nodisc) + return SBIC_STATE_DISCONNECT; + + /* Try to schedule another target */ + wd33c93_sched(sc); + + return SBIC_STATE_DISCONNECT; + + case SBIC_CSR_RSLT_NI: + case SBIC_CSR_RSLT_IFY: + { + /* + * A reselection. + * Note that since we don't enable Advanced Features (assuming + * the WD chip is at least the 'A' revision), we're only ever + * likely to see the 'SBIC_CSR_RSLT_NI' status. But for the + * hell of it, we'll handle it anyway, for all the extra code + * it needs... + */ + u_char newtarget, newlun; + + if (sc->sc_flags & SBICF_INDMA) { + printf("**** RESELECT WHILE DMA ACTIVE!!! ***\n"); + wd33c93_dma_stop(sc); + } + + sc->sc_state = SBIC_RESELECTED; + GET_SBIC_rselid(sc, newtarget); + + /* check SBIC_RID_SIV? */ + newtarget &= SBIC_RID_MASK; + + if (csr == SBIC_CSR_RSLT_IFY) { + /* Read Identify msg to avoid lockup */ + GET_SBIC_data(sc, newlun); + WAIT_CIP(sc); + newlun &= SBIC_TLUN_MASK; + sc->sc_msgify = MSG_IDENTIFY(newlun, 0); + } else { + /* + * Need to read Identify message the hard way, assuming + * the target even sends us one... + */ + for (newlun = 255; newlun; --newlun) { + GET_SBIC_asr(sc, asr); + if (asr & SBIC_ASR_INT) + break; + DELAY(10); + } + + /* If we didn't get an interrupt, somethink's up */ + if ((asr & SBIC_ASR_INT) == 0) { + printf("%s: Reselect without identify? asr %x\n", + sc->sc_dev.dv_xname, asr); + newlun = 0; /* XXXX */ + } else { + /* + * We got an interrupt, verify that it's a + * change to message in phase, and if so + * read the message. + */ + GET_SBIC_csr(sc,csr); + + if (csr == (SBIC_CSR_MIS | MESG_IN_PHASE) || + csr == (SBIC_CSR_MIS_1 | MESG_IN_PHASE) || + csr == (SBIC_CSR_MIS_2 | MESG_IN_PHASE)) { + /* + * Yup, gone to message in. + * Fetch the target LUN + */ + sc->sc_msgify = 0; + wd33c93_msgin_phase(sc, 1); + newlun = sc->sc_msgify & SBIC_TLUN_MASK; + } else { + /* + * Whoops! Target didn't go to msg_in + * phase!! + */ + printf("RSLT_NI - not MESG_IN_PHASE %x\n", csr); + newlun = 0; /* XXXSCW */ + } + } + } + + /* Ok, we have the identity of the reselecting target. */ + SBIC_DEBUG(RSEL, ("wd33c93next: reselect from targ %d lun %d", + newtarget, newlun)); + wd33c93_reselect(sc, newtarget, newlun, 0, 0); + sc->sc_disc--; + + if (csr == SBIC_CSR_RSLT_IFY) + SET_SBIC_cmd(sc, SBIC_CMD_CLR_ACK); + break; + } + + default: + abort: + /* Something unexpected happend -- deal with it. */ + printf("next: aborting asr 0x%02x csr 0x%02x\n", asr, csr); + +#ifdef DDB + Debugger(); +#endif + + SET_SBIC_control(sc, SBIC_CTL_EDI | SBIC_CTL_IDI); + if (acb->xs) + wd33c93_error(sc, acb); + wd33c93_abort(sc, acb, "next"); + + if (sc->sc_flags & SBICF_INDMA) { + wd33c93_dma_stop(sc); + wd33c93_scsidone(sc, acb, STATUS_UNKNOWN); + } + return SBIC_STATE_ERROR; + } + return SBIC_STATE_RUNNING; +} + + +void +wd33c93_reselect(struct wd33c93_softc *sc, int target, int lun, int tag_type, int tag_id) +{ + + struct wd33c93_tinfo *ti; + struct wd33c93_linfo *li; + struct wd33c93_acb *acb; + + if (sc->sc_nexus) { + /* + * Whoops! We've been reselected with a + * command in progress! + * The best we can do is to put the current + * command back on the ready list and hope + * for the best. + */ + SBIC_DEBUG(RSEL, ("%s: reselect with active command\n", + sc->sc_dev.dv_xname)); + ti = &sc->sc_tinfo[sc->target]; + li = TINFO_LUN(ti, sc->lun); + li->state = L_STATE_IDLE; + + wd33c93_dequeue(sc, sc->sc_nexus); + TAILQ_INSERT_HEAD(&sc->ready_list, sc->sc_nexus, chain); + sc->sc_nexus->flags |= ACB_READY; + + sc->sc_nexus = NULL; + } + + /* Setup state for new nexus */ + acb = NULL; + sc->sc_flags = SBICF_SELECTED; + sc->sc_msgpriq = sc->sc_msgout = sc->sc_msgoutq = 0; + + ti = &sc->sc_tinfo[target]; + li = TINFO_LUN(ti, lun); + + if (li != NULL) { + if (li->untagged != NULL && li->state) + acb = li->untagged; + else if (tag_type != MSG_SIMPLE_Q_TAG) { + /* Wait for tag to come by during MESG_IN Phase */ + sc->target = target; /* setup I_T_L nexus */ + sc->lun = lun; + sc->sc_state = SBIC_IDENTIFIED; + return; + } else if (tag_type) + acb = li->queued[tag_id]; + } + + if (acb == NULL) { + printf("%s: reselect from target %d lun %d tag %x:%x " + "with no nexus; sending ABORT\n", + sc->sc_dev.dv_xname, target, lun, tag_type, tag_id); + goto abort; + } + + sc->target = target; + sc->lun = lun; + sc->sc_nexus = acb; + sc->sc_state = SBIC_CONNECTED; + + if (!wd33c93_dmaok(sc, acb->xs)) + sc->sc_flags |= SBICF_NODMA; + + /* Do an implicit RESTORE POINTERS. */ + sc->sc_daddr = acb->daddr; + sc->sc_dleft = acb->dleft; + + /* Set sync modes for new target */ + wd33c93_setsync(sc, ti); + + if (acb->flags & ACB_RESET) + wd33c93_sched_msgout(sc, SEND_DEV_RESET); + else if (acb->flags & ACB_ABORT) + wd33c93_sched_msgout(sc, SEND_ABORT); + return; + +abort: + wd33c93_sched_msgout(sc, SEND_ABORT); + return; + +} + +void +wd33c93_timeout(void *arg) +{ + struct wd33c93_acb *acb = arg; + struct scsi_xfer *xs = acb->xs; + struct scsi_link *sc_link = xs->sc_link; + struct wd33c93_softc *sc = sc_link->adapter_softc; + int s, asr; + + s = splbio(); + + GET_SBIC_asr(sc, asr); + + sc_print_addr(sc_link); + printf("%s: timed out; asr=0x%02x [acb %p (flags 0x%x, dleft %zx)], " + "<state %d, nexus %p, resid %lx, msg(q %x,o %x)>", + sc->sc_dev.dv_xname, asr, acb, acb->flags, acb->dleft, + sc->sc_state, sc->sc_nexus, (long)sc->sc_dleft, + sc->sc_msgpriq, sc->sc_msgout); + + if (asr & SBIC_ASR_INT) { + /* We need to service a missed IRQ */ + wd33c93_intr(sc); + } else { + (void) wd33c93_abort(sc, sc->sc_nexus, "timeout"); + } + splx(s); +} + + +void +wd33c93_watchdog(void *arg) +{ + struct wd33c93_softc *sc = arg; + struct wd33c93_tinfo *ti; + struct wd33c93_linfo *li; + int t, s, l; + /* scrub LUN's that have not been used in the last 10min. */ + time_t old = time_second - (10 * 60); + + for (t = 0; t < SBIC_NTARG; t++) { + ti = &sc->sc_tinfo[t]; + for (l = 0; l < SBIC_NLUN; l++) { + s = splbio(); + li = TINFO_LUN(ti, l); + if (li && li->last_used < old && + li->untagged == NULL && li->used == 0) { + ti->lun[li->lun] = NULL; + free(li, M_DEVBUF); + } + splx(s); + } + } + timeout_add_sec(&sc->sc_watchdog, 60); +} + + +#ifdef SBICDEBUG +void +wd33c93_hexdump(u_char *buf, int len) +{ + printf("{%d}:", len); + while (len--) + printf(" %02x", *buf++); + printf("\n"); +} + + +void +wd33c93_print_csr(u_char csr) +{ + switch (SCSI_PHASE(csr)) { + case CMD_PHASE: + printf("CMD_PHASE\n"); + break; + + case STATUS_PHASE: + printf("STATUS_PHASE\n"); + break; + + case DATA_IN_PHASE: + printf("DATAIN_PHASE\n"); + break; + + case DATA_OUT_PHASE: + printf("DATAOUT_PHASE\n"); + break; + + case MESG_IN_PHASE: + printf("MESG_IN_PHASE\n"); + break; + + case MESG_OUT_PHASE: + printf("MESG_OUT_PHASE\n"); + break; + + default: + switch (csr) { + case SBIC_CSR_DISC_1: + printf("DISC_1\n"); + break; + + case SBIC_CSR_RSLT_NI: + printf("RESELECT_NO_IFY\n"); + break; + + case SBIC_CSR_RSLT_IFY: + printf("RESELECT_IFY\n"); + break; + + case SBIC_CSR_SLT: + printf("SELECT\n"); + break; + + case SBIC_CSR_SLT_ATN: + printf("SELECT, ATN\n"); + break; + + case SBIC_CSR_UNK_GROUP: + printf("UNK_GROUP\n"); + break; + + default: + printf("UNKNOWN csr=%02x\n", csr); + } + } +} +#endif diff --git a/sys/dev/ic/wd33c93reg.h b/sys/dev/ic/wd33c93reg.h new file mode 100644 index 00000000000..e1f16ad11f9 --- /dev/null +++ b/sys/dev/ic/wd33c93reg.h @@ -0,0 +1,510 @@ +/* $OpenBSD: wd33c93reg.h,v 1.1 2012/03/28 20:44:23 miod Exp $ */ +/* $NetBSD: wd33c93reg.h,v 1.4 2009/02/12 06:24:45 rumble Exp $ */ + +/* + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Van Jacobson of Lawrence Berkeley Laboratory. + * + * 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. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#)scsireg.h 7.3 (Berkeley) 2/5/91 + */ + +/* + * Copyright (c) 2001 Wayne Knowles + * + * This code is derived from software contributed to Berkeley by + * Van Jacobson of Lawrence Berkeley Laboratory. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#)scsireg.h 7.3 (Berkeley) 2/5/91 + */ + +/* + * WD33C93 SCSI interface hardware description. + * + * Using parts of the Mach scsi driver for the 33C93 + */ + +#define SBIC_myid 0 +#define SBIC_cdbsize 0 +#define SBIC_control 1 +#define SBIC_timeo 2 +#define SBIC_cdb1 3 +#define SBIC_tsecs 3 +#define SBIC_cdb2 4 +#define SBIC_theads 4 +#define SBIC_cdb3 5 +#define SBIC_tcyl_hi 5 +#define SBIC_cdb4 6 +#define SBIC_tcyl_lo 6 +#define SBIC_cdb5 7 +#define SBIC_addr_hi 7 +#define SBIC_cdb6 8 +#define SBIC_addr_2 8 +#define SBIC_cdb7 9 +#define SBIC_addr_3 9 +#define SBIC_cdb8 10 +#define SBIC_addr_lo 10 +#define SBIC_cdb9 11 +#define SBIC_secno 11 +#define SBIC_cdb10 12 +#define SBIC_headno 12 +#define SBIC_cdb11 13 +#define SBIC_cylno_hi 13 +#define SBIC_cdb12 14 +#define SBIC_cylno_lo 14 +#define SBIC_tlun 15 +#define SBIC_cmd_phase 16 +#define SBIC_syn 17 +#define SBIC_count_hi 18 +#define SBIC_count_med 19 +#define SBIC_count_lo 20 +#define SBIC_selid 21 +#define SBIC_rselid 22 +#define SBIC_csr 23 +#define SBIC_cmd 24 +#define SBIC_data 25 +#define SBIC_queue_tag 26 +#define SBIC_aux_status 27 + +/* wd33c93_asr is addressed directly */ + +/* + * Register defines + */ + +/* + * Auxiliary Status Register + */ + +#define SBIC_ASR_INT 0x80 /* Interrupt pending */ +#define SBIC_ASR_LCI 0x40 /* Last command ignored */ +#define SBIC_ASR_BSY 0x20 /* Busy, only cmd/data/asr readable */ +#define SBIC_ASR_CIP 0x10 /* Busy, cmd unavail also */ +#define SBIC_ASR_xxx 0x0c +#define SBIC_ASR_PE 0x02 /* Parity error (even) */ +#define SBIC_ASR_DBR 0x01 /* Data Buffer Ready */ + +/* + * My ID register, and/or CDB Size + */ + +#define SBIC_ID_FS_8_10 0x00 /* Input clock is 8-10 MHz */ + /* 11 MHz is invalid */ +#define SBIC_ID_FS_12_15 0x40 /* Input clock is 12-15 MHz */ +#define SBIC_ID_FS_16_20 0x80 /* Input clock is 16-20 MHz */ +#define SBIC_ID_RAF 0x20 /* Enable Really Advanced Features */ +#define SBIC_ID_EHP 0x10 /* Enable host parity */ +#define SBIC_ID_EAF 0x08 /* Enable Advanced Features */ +#define SBIC_ID_MASK 0x07 +#define SBIC_ID_CBDSIZE_MASK 0x0f /* if unk SCSI cmd group */ + +/* + * Control register + */ + +#define SBIC_CTL_DMA 0x80 /* Single byte dma */ +#define SBIC_CTL_DBA_DMA 0x40 /* direct buffer access (bus master) */ +#define SBIC_CTL_BURST_DMA 0x20 /* continuous mode (8237) */ +#define SBIC_CTL_NO_DMA 0x00 /* Programmed I/O */ +#define SBIC_CTL_HHP 0x10 /* Halt on host parity error */ +#define SBIC_CTL_EDI 0x08 /* Ending disconnect interrupt */ +#define SBIC_CTL_IDI 0x04 /* Intermediate disconnect interrupt*/ +#define SBIC_CTL_HA 0x02 /* Halt on ATN */ +#define SBIC_CTL_HSP 0x01 /* Halt on SCSI parity error */ + +/* + * Timeout period register + * [val in msecs, input clk in 0.1 MHz] + */ + +#define SBIC_TIMEOUT(val,clk) ((((val) * (clk)) / 800) + 1) + +/* + * CDBn registers, note that + * cdb11 is used for status byte in target mode (send-status-and-cc) + * cdb12 sez if linked command complete, and w/flag if so + */ + +/* + * Target LUN register + * [holds target status when select-and-xfer] + */ + +#define SBIC_TLUN_VALID 0x80 /* did we receive an Identify msg */ +#define SBIC_TLUN_DOK 0x40 /* Disconnect OK */ +#define SBIC_TLUN_xxx 0x38 +#define SBIC_TLUN_MASK 0x07 + +/* + * Command Phase register + */ + +#define SBIC_CPH_MASK 0x7f /* values/restarts are cmd specific */ +#define SBIC_CPH(p) ((p) & SBIC_CPH_MASK) + +/* + * FIFO register + */ + +#define SBIC_FIFO_93_DEPTH 5 +#define SBIC_FIFO_93AB_DEPTH 12 + +/* + * maximum possible size in TC registers. Since this is 24 bit, it's easy + */ +#define SBIC_TC_MAX ((1 << 24) - 1) + +/* + * Synchronous xfer register + * + * NB: SBIC_SYN_FSS only valid on WD33C93B with 16-20MHz clock. + */ + +#define SBIC_SYN_OFF_MASK 0x0f +#define SBIC_SYN_93_MAX_OFFSET (SBIC_FIFO_93_DEPTH - 1) /* 4 is recommended */ +#define SBIC_SYN_93AB_MAX_OFFSET SBIC_FIFO_93AB_DEPTH +#define SBIC_SYN_PER_MASK 0x70 +#define SBIC_SYN_MIN_PERIOD 2 /* upto 8, encoded as 0 */ +#define SBIC_SYN_FSS 0x80 /* Enable Fast SCSI Transfers (10MB/s)*/ + +#define SBIC_SYN(o,p,f) \ + (((o) & SBIC_SYN_OFF_MASK) | (((p) << 4) & SBIC_SYN_PER_MASK) | \ + ((f) ? SBIC_SYN_FSS : 0)) + +/* + * Transfer count register + * optimal access macros depend on addressing + */ + +/* + * Destination ID (selid) register + */ + +#define SBIC_SID_SCC 0x80 /* Select command chaining (tgt) */ +#define SBIC_SID_DPD 0x40 /* Data phase direction (inittor) */ +#define SBIC_SID_FROM_SCSI 0x40 +#define SBIC_SID_TO_SCSI 0x00 +#define SBIC_SID_xxx 0x38 +#define SBIC_SID_IDMASK 0x07 + +/* + * Source ID (rselid) register + */ + +#define SBIC_RID_ER 0x80 /* Enable reselection */ +#define SBIC_RID_ES 0x40 /* Enable selection */ +#define SBIC_RID_DSP 0x20 /* Disable select parity */ +#define SBIC_RID_SIV 0x08 /* Source ID valid */ +#define SBIC_RID_MASK 0x07 + +/* + * Status register + */ + +#define SBIC_CSR_CAUSE 0xf0 +#define SBIC_CSR_RESET 0x00 /* chip was reset */ +#define SBIC_CSR_CMD_DONE 0x10 /* cmd completed */ +#define SBIC_CSR_CMD_STOPPED 0x20 /* interrupted or abrted*/ +#define SBIC_CSR_CMD_ERR 0x40 /* end with error */ +#define SBIC_CSR_BUS_SERVICE 0x80 /* REQ pending on the bus */ + + +#define SBIC_CSR_QUALIFIER 0x0f +/* Reset State Interrupts */ +#define SBIC_CSR_RESET 0x00 /* reset w/advanced features*/ +#define SBIC_CSR_RESET_AM 0x01 /* reset w/advanced features*/ +/* Successful Completion Interrupts */ +#define SBIC_CSR_TARGET 0x10 /* reselect complete */ +#define SBIC_CSR_INITIATOR 0x11 /* select complete */ +#define SBIC_CSR_WO_ATN 0x13 /* tgt mode completion */ +#define SBIC_CSR_W_ATN 0x14 /* ditto */ +#define SBIC_CSR_XLATED 0x15 /* translate address cmd */ +#define SBIC_CSR_S_XFERRED 0x16 /* initiator mode completion*/ +#define SBIC_CSR_XFERRED 0x18 /* phase in low bits */ +/* Paused or Aborted Interrupts */ +#define SBIC_CSR_MSGIN_W_ACK 0x20 /* (I) msgin, ACK asserted*/ +#define SBIC_CSR_SDP 0x21 /* (I) SDP msg received */ +#define SBIC_CSR_SEL_ABRT 0x22 /* sel/resel aborted */ +#define SBIC_CSR_XFR_PAUSED 0x23 /* (T) no ATN */ +#define SBIC_CSR_XFR_PAUSED_ATN 0x24 /* (T) ATN is asserted */ +#define SBIC_CSR_RSLT_AM 0x27 /* (I) lost selection (AM) */ +#define SBIC_CSR_MIS 0x28 /* (I) xfer aborted, ph mis */ +/* Terminated Interrupts */ +#define SBIC_CSR_CMD_INVALID 0x40 +#define SBIC_CSR_DISC 0x41 /* (I) tgt disconnected */ +#define SBIC_CSR_SEL_TIMEO 0x42 +#define SBIC_CSR_PE 0x43 /* parity error */ +#define SBIC_CSR_PE_ATN 0x44 /* ditto, ATN is asserted */ +#define SBIC_CSR_XLATE_TOOBIG 0x45 +#define SBIC_CSR_RSLT_NOAM 0x46 /* (I) lost sel, no AM mode */ +#define SBIC_CSR_BAD_STATUS 0x47 /* status byte was nok */ +#define SBIC_CSR_MIS_1 0x48 /* ph mis, see low bits */ +/* Service Required Interrupts */ +#define SBIC_CSR_RSLT_NI 0x80 /* reselected, no ify msg */ +#define SBIC_CSR_RSLT_IFY 0x81 /* ditto, AM mode, got ify */ +#define SBIC_CSR_SLT 0x82 /* selected, no ATN */ +#define SBIC_CSR_SLT_ATN 0x83 /* selected with ATN */ +#define SBIC_CSR_ATN 0x84 /* (T) ATN asserted */ +#define SBIC_CSR_DISC_1 0x85 /* (I) bus is free */ +#define SBIC_CSR_UNK_GROUP 0x87 /* strange CDB1 */ +#define SBIC_CSR_MIS_2 0x88 /* (I) ph mis, see low bits */ + +#define SBIC_PHASE(csr) SCSI_PHASE(csr) + +/* + * Command register (command codes) + */ + +#define SBIC_CMD_SBT 0x80 /* Single byte xfer qualifier */ +#define SBIC_CMD_MASK 0x7f + + /* Miscellaneous */ +#define SBIC_CMD_RESET 0x00 /* (DTI) lev I */ +#define SBIC_CMD_ABORT 0x01 /* (DTI) lev I */ +#define SBIC_CMD_DISC 0x04 /* ( TI) lev I */ +#define SBIC_CMD_SSCC 0x0d /* ( TI) lev I */ +#define SBIC_CMD_SET_IDI 0x0f /* (DTI) lev I */ +#define SBIC_CMD_XLATE 0x18 /* (DT ) lev II */ + + /* Initiator state */ +#define SBIC_CMD_SET_ATN 0x02 /* ( I) lev I */ +#define SBIC_CMD_CLR_ACK 0x03 /* ( I) lev I */ +#define SBIC_CMD_XFER_PAD 0x19 /* ( I) lev II */ +#define SBIC_CMD_XFER_INFO 0x20 /* ( I) lev II */ + + /* Target state */ +#define SBIC_CMD_SND_DISC 0x0e /* ( T ) lev II */ +#define SBIC_CMD_RCV_CMD 0x10 /* ( T ) lev II */ +#define SBIC_CMD_RCV_DATA 0x11 /* ( T ) lev II */ +#define SBIC_CMD_RCV_MSG_OUT 0x12 /* ( T ) lev II */ +#define SBIC_CMD_RCV 0x13 /* ( T ) lev II */ +#define SBIC_CMD_SND_STATUS 0x14 /* ( T ) lev II */ +#define SBIC_CMD_SND_DATA 0x15 /* ( T ) lev II */ +#define SBIC_CMD_SND_MSG_IN 0x16 /* ( T ) lev II */ +#define SBIC_CMD_SND 0x17 /* ( T ) lev II */ + + /* Disconnected state */ +#define SBIC_CMD_RESELECT 0x05 /* (D ) lev II */ +#define SBIC_CMD_SEL_ATN 0x06 /* (D ) lev II */ +#define SBIC_CMD_SEL 0x07 /* (D ) lev II */ +#define SBIC_CMD_SEL_ATN_XFER 0x08 /* (D I) lev II */ +#define SBIC_CMD_SEL_XFER 0x09 /* (D I) lev II */ +#define SBIC_CMD_RESELECT_RECV 0x0a /* (DT ) lev II */ +#define SBIC_CMD_RESELECT_SEND 0x0b /* (DT ) lev II */ +#define SBIC_CMD_WAIT_SEL_RECV 0x0c /* (DT ) lev II */ + + +#define PHASE_MASK 0x07 /* mask for psns/pctl phase */ +#define DATA_OUT_PHASE 0x00 +#define DATA_IN_PHASE 0x01 +#define CMD_PHASE 0x02 +#define STATUS_PHASE 0x03 +#define BUS_FREE_PHASE 0x04 +#define ARB_SEL_PHASE 0x05 /* Fuji chip combines bus arb with sel. */ +#define MESG_OUT_PHASE 0x06 +#define MESG_IN_PHASE 0x07 + +#define SCSI_PHASE(reg) ((reg) & PHASE_MASK) + +#define SCSI_STATUS_MASK 0x3e /* Mask unused bits in status byte */ + +/* approximate, but we won't do SBT on selects */ +#define wd33c93_isa_select(cmd) (((cmd) > 0x5) && ((cmd) < 0xa)) + +#define PAD(n) char n; +#define SBIC_MACHINE_DMA_MODE SBIC_CTL_DMA + +/* + * WD33C93 has two registers: + * ASR - r : Aux Status Register, w : desired register no + * DATA - rw: register value + * + * We access them via separate handles because some people *cough*SGI*cough* + * like to keep them apart. + */ + +#define wd33c93_read_reg(sc,regno,val) \ + do { \ + bus_space_write_1((sc)->sc_regt,(sc)->sc_asr_regh, 0, (regno)); \ + (val) = bus_space_read_1((sc)->sc_regt,(sc)->sc_data_regh, 0); \ + } while (0) + +#define wd33c93_write_reg(sc,regno,val) \ + do { \ + bus_space_write_1((sc)->sc_regt, (sc)->sc_asr_regh, 0, (regno)); \ + bus_space_write_1((sc)->sc_regt, (sc)->sc_data_regh, 0, (val)); \ + } while (0) + +#define SET_SBIC_myid(sc,val) wd33c93_write_reg(sc,SBIC_myid,val) +#define GET_SBIC_myid(sc,val) wd33c93_read_reg(sc,SBIC_myid,val) +#define SET_SBIC_cdbsize(sc,val) wd33c93_write_reg(sc,SBIC_cdbsize,val) +#define GET_SBIC_cdbsize(sc,val) wd33c93_read_reg(sc,SBIC_cdbsize,val) +#define SET_SBIC_control(sc,val) wd33c93_write_reg(sc,SBIC_control,val) +#define GET_SBIC_control(sc,val) wd33c93_read_reg(sc,SBIC_control,val) +#define SET_SBIC_timeo(sc,val) wd33c93_write_reg(sc,SBIC_timeo,val) +#define GET_SBIC_timeo(sc,val) wd33c93_read_reg(sc,SBIC_timeo,val) +#define SET_SBIC_cdb1(sc,val) wd33c93_write_reg(sc,SBIC_cdb1,val) +#define GET_SBIC_cdb1(sc,val) wd33c93_read_reg(sc,SBIC_cdb1,val) +#define SET_SBIC_cdb2(sc,val) wd33c93_write_reg(sc,SBIC_cdb2,val) +#define GET_SBIC_cdb2(sc,val) wd33c93_read_reg(sc,SBIC_cdb2,val) +#define SET_SBIC_cdb3(sc,val) wd33c93_write_reg(sc,SBIC_cdb3,val) +#define GET_SBIC_cdb3(sc,val) wd33c93_read_reg(sc,SBIC_cdb3,val) +#define SET_SBIC_cdb4(sc,val) wd33c93_write_reg(sc,SBIC_cdb4,val) +#define GET_SBIC_cdb4(sc,val) wd33c93_read_reg(sc,SBIC_cdb4,val) +#define SET_SBIC_cdb5(sc,val) wd33c93_write_reg(sc,SBIC_cdb5,val) +#define GET_SBIC_cdb5(sc,val) wd33c93_read_reg(sc,SBIC_cdb5,val) +#define SET_SBIC_cdb6(sc,val) wd33c93_write_reg(sc,SBIC_cdb6,val) +#define GET_SBIC_cdb6(sc,val) wd33c93_read_reg(sc,SBIC_cdb6,val) +#define SET_SBIC_cdb7(sc,val) wd33c93_write_reg(sc,SBIC_cdb7,val) +#define GET_SBIC_cdb7(sc,val) wd33c93_read_reg(sc,SBIC_cdb7,val) +#define SET_SBIC_cdb8(sc,val) wd33c93_write_reg(sc,SBIC_cdb8,val) +#define GET_SBIC_cdb8(sc,val) wd33c93_read_reg(sc,SBIC_cdb8,val) +#define SET_SBIC_cdb9(sc,val) wd33c93_write_reg(sc,SBIC_cdb9,val) +#define GET_SBIC_cdb9(sc,val) wd33c93_read_reg(sc,SBIC_cdb9,val) +#define SET_SBIC_cdb10(sc,val) wd33c93_write_reg(sc,SBIC_cdb10,val) +#define GET_SBIC_cdb10(sc,val) wd33c93_read_reg(sc,SBIC_cdb10,val) +#define SET_SBIC_cdb11(sc,val) wd33c93_write_reg(sc,SBIC_cdb11,val) +#define GET_SBIC_cdb11(sc,val) wd33c93_read_reg(sc,SBIC_cdb11,val) +#define SET_SBIC_cdb12(sc,val) wd33c93_write_reg(sc,SBIC_cdb12,val) +#define GET_SBIC_cdb12(sc,val) wd33c93_read_reg(sc,SBIC_cdb12,val) +#define SET_SBIC_tlun(sc,val) wd33c93_write_reg(sc,SBIC_tlun,val) +#define GET_SBIC_tlun(sc,val) wd33c93_read_reg(sc,SBIC_tlun,val) +#define SET_SBIC_cmd_phase(sc,val) wd33c93_write_reg(sc,SBIC_cmd_phase,val) +#define GET_SBIC_cmd_phase(sc,val) wd33c93_read_reg(sc,SBIC_cmd_phase,val) +#define SET_SBIC_syn(sc,val) wd33c93_write_reg(sc,SBIC_syn,val) +#define GET_SBIC_syn(sc,val) wd33c93_read_reg(sc,SBIC_syn,val) +#define SET_SBIC_count_hi(sc,val) wd33c93_write_reg(sc,SBIC_count_hi,val) +#define GET_SBIC_count_hi(sc,val) wd33c93_read_reg(sc,SBIC_count_hi,val) +#define SET_SBIC_count_med(sc,val) wd33c93_write_reg(sc,SBIC_count_med,val) +#define GET_SBIC_count_med(sc,val) wd33c93_read_reg(sc,SBIC_count_med,val) +#define SET_SBIC_count_lo(sc,val) wd33c93_write_reg(sc,SBIC_count_lo,val) +#define GET_SBIC_count_lo(sc,val) wd33c93_read_reg(sc,SBIC_count_lo,val) +#define SET_SBIC_selid(sc,val) wd33c93_write_reg(sc,SBIC_selid,val) +#define GET_SBIC_selid(sc,val) wd33c93_read_reg(sc,SBIC_selid,val) +#define SET_SBIC_rselid(sc,val) wd33c93_write_reg(sc,SBIC_rselid,val) +#define GET_SBIC_rselid(sc,val) wd33c93_read_reg(sc,SBIC_rselid,val) +#define SET_SBIC_csr(sc,val) wd33c93_write_reg(sc,SBIC_csr,val) +#define GET_SBIC_csr(sc,val) wd33c93_read_reg(sc,SBIC_csr,val) +#define SET_SBIC_cmd(sc,val) wd33c93_write_reg(sc,SBIC_cmd,val) +#define GET_SBIC_cmd(sc,val) wd33c93_read_reg(sc,SBIC_cmd,val) +#define SET_SBIC_data(sc,val) wd33c93_write_reg(sc,SBIC_data,val) +#define GET_SBIC_data(sc,val) wd33c93_read_reg(sc,SBIC_data,val) +#define SET_SBIC_queue_tag(sc,val) wd33c93_write_reg(sc,SBIC_queue_tag,val) +#define GET_SBIC_queue_tag(sc,val) wd33c93_read_reg(sc,SBIC_queue_tag,val) + +#define SBIC_TC_PUT(sc,val) \ + do { \ + wd33c93_write_reg(sc,SBIC_count_hi,((val)>>16)); \ + bus_space_write_1((sc)->sc_regt, (sc)->sc_data_regh, 0, \ + (val)>>8); \ + bus_space_write_1((sc)->sc_regt, (sc)->sc_data_regh, 0, \ + (val)); \ + } while (0) + +#define SBIC_TC_GET(sc,val) \ + do { \ + wd33c93_read_reg(sc,SBIC_count_hi,(val)); \ + (val) = ((val)<<8) | bus_space_read_1((sc)->sc_regt, \ + (sc)->sc_data_regh, 0); \ + (val) = ((val)<<8) | bus_space_read_1((sc)->sc_regt, \ + (sc)->sc_data_regh, 0); \ + } while (0) + +#define SBIC_LOAD_COMMAND(sc,cmd,cmdsize) \ + do { \ + int n = (cmdsize) - 1; \ + char *ptr = (char *)(cmd); \ + wd33c93_write_reg(regs, SBIC_cdb1, *ptr++); \ + while(n-- > 0) \ + bus_space_write_1((sc)->sc_regt, (sc)->sc_data_regh, \ + 0, *ptr++); /* XXX write_multi */ \ + } while (0) + +#define GET_SBIC_asr(sc,val) \ + do { \ + (val) = bus_space_read_1((sc)->sc_regt,(sc)->sc_asr_regh, 0); \ + } while (0) + + +#define WAIT_CIP(sc) \ + do { \ + while (bus_space_read_1((sc)->sc_regt,(sc)->sc_asr_regh, \ + 0) & SBIC_ASR_CIP) \ + /*nop*/; \ + } while (0) + +/* + * transmit a byte in programmed I/O mode + */ +#define SEND_BYTE(sc, ch) \ + do { \ + WAIT_CIP(sc); \ + SET_SBIC_cmd(sc, SBIC_CMD_SBT | SBIC_CMD_XFER_INFO); \ + SBIC_WAIT(sc, SBIC_ASR_DBR, 0); \ + SET_SBIC_data(sc, ch); \ + } while (0) + +/* + * receive a byte in programmed I/O mode + */ +#define RECV_BYTE(sc, ch) \ + do { \ + WAIT_CIP(sc); \ + SET_SBIC_cmd(sc, SBIC_CMD_SBT | SBIC_CMD_XFER_INFO); \ + SBIC_WAIT(sc, SBIC_ASR_DBR, 0); \ + GET_SBIC_data(sc, ch); \ + } while (0) diff --git a/sys/dev/ic/wd33c93var.h b/sys/dev/ic/wd33c93var.h new file mode 100644 index 00000000000..45a24bcebc0 --- /dev/null +++ b/sys/dev/ic/wd33c93var.h @@ -0,0 +1,262 @@ +/* $OpenBSD: wd33c93var.h,v 1.1 2012/03/28 20:44:23 miod Exp $ */ +/* $NetBSD: wd33c93var.h,v 1.10 2009/05/12 14:25:18 cegger Exp $ */ + +/* + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Van Jacobson of Lawrence Berkeley Laboratory. + * + * 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. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#)scsivar.h 7.1 (Berkeley) 5/8/90 + */ + +#define SBIC_NTARG 8 +#define SBIC_NLUN 8 +#define SBIC_NTAGS 256 + +#define SBIC_MAX_MSGLEN 8 + +#define SBIC_ABORT_TIMEOUT 2000 /* time to wait for abort */ +#define SBIC_SENSE_TIMEOUT 1000 /* time to wait for sense */ + +/* + * ACB. Holds additional information for each SCSI command Comments: We + * need a separate scsi command block because we may need to overwrite it + * with a request sense command. Basically, we refrain from fiddling with + * the scsi_xfer struct (except do the expected updating of return values). + * We'll generally update: xs->{flags,resid,error,sense,status} and + * occasionally xs->retries. + */ +struct wd33c93_acb { + TAILQ_ENTRY(wd33c93_acb) chain; + struct scsi_xfer *xs; /* SCSI xfer ctrl block from above */ + int flags; /* Status */ +#define ACB_FREE 0x00 +#define ACB_ACTIVE 0x01 +#define ACB_READY 0x02 /* ACB is on ready list */ +#define ACB_DONE 0x04 +#define ACB_SENSE 0x08 /* ACB Requesting sense */ +#define ACB_COMPLETE 0x10 /* Disconnected at end of xfer */ +#define ACB_RESET 0x20 /* Require Reset */ +#define ACB_ABORT 0x40 /* Require Abort */ + int timeout; + struct timeout to; + + struct scsi_generic cmd; /* SCSI command block */ + char *daddr; /* kva for data */ + int clen; + size_t dleft; /* bytes remaining */ + u_char tag_type; /* TAG Type (0x20-0x22, 0=No Tags) */ + u_char tag_id; /* TAG id number */ +}; + +/* + * Some info about each (possible) target on the SCSI bus. This should + * probably have been a "per target+lunit" structure, but we'll leave it at + * this for now. Is there a way to reliably hook it up to sc->fordriver?? + */ + +struct wd33c93_linfo { + int lun; + LIST_ENTRY(wd33c93_linfo) link; + time_t last_used; + u_char used; /* # slots in use */ + u_char avail; /* where to start scanning */ + u_char state; +#define L_STATE_IDLE 0 +#define L_STATE_BUSY 1 +#define L_STATE_ESTAT 2 + struct wd33c93_acb *untagged; + struct wd33c93_acb *queued[SBIC_NTAGS]; +}; + +struct wd33c93_tinfo { + int cmds; /* # of commands processed */ + int dconns; /* # of disconnects */ + + u_char flags; +#define T_NEED_RESET 0x01 /* Should send a BUS_DEV_RESET */ +#define T_NEGOTIATE 0x02 /* (Re)Negotiate synchronous options */ +#define T_BUSY 0x04 /* Target is busy */ +#define T_SYNCMODE 0x08 /* SYNC mode has been negotiated */ +#define T_NOSYNC 0x10 /* Force ASYNC mode */ +#define T_NODISC 0x20 /* Don't allow disconnect */ +#define T_TAG 0x40 /* Turn on TAG QUEUEs */ +#define T_WANTSYNC 0x80 /* Negotiatious should aim for sync */ + u_char period; /* Period suggestion */ + u_char offset; /* Offset suggestion */ + struct wd33c93_linfo *lun[SBIC_NLUN]; /* LUN list for this target */ +}; + +/* Look up a lun in a tinfo */ +#define TINFO_LUN(t, l) ((t)->lun[(l)]) + +struct wd33c93_softc { + struct device sc_dev; + + struct timeout sc_watchdog; + struct scsi_link sc_link; + void *sc_driver; /* driver specific field */ + + int target; /* Currently active target */ + int lun; /* Currently active LUN */ + + /* WD33c93 registers */ + bus_space_tag_t sc_regt; + bus_space_handle_t sc_asr_regh; + bus_space_handle_t sc_data_regh; + + /* Data about the current nexus (updated for every cmd switch) */ + void * sc_daddr; /* Current data pointer */ + size_t sc_dleft; /* Data left to transfer */ + ssize_t sc_tcnt; /* number of bytes transfered */ + + /* Lists of command blocks */ + TAILQ_HEAD(acb_list, wd33c93_acb) ready_list; + + struct wd33c93_acb *sc_nexus; /* current command */ + struct wd33c93_tinfo sc_tinfo[8]; + + u_short sc_state; + u_short sc_status; + int sc_disc; /* current # of active nexus's */ + int sc_flags; + + /* Message stuff */ + u_short sc_msgify; /* Last IDENTIFY message */ + u_short sc_msgout; /* Current message out */ + u_short sc_msgpriq; /* mesg_out queue (bitmap) */ + u_short sc_msgoutq; /* mesg_out queue */ + + u_char sc_imsg[SBIC_MAX_MSGLEN]; + u_char sc_omsg[SBIC_MAX_MSGLEN]; + u_char sc_imsglen; + u_char sc_omsglen; + + /* Static hardware attributes supplied by attachment */ + int sc_id; /* SCSI ID for controller */ + int sc_clkfreq; /* wd33c93 clk freq * 10 MHz */ + uint8_t sc_dmamode; /* One of SBIC_CTL_*DMA */ + + /* Static hardware attributes derived by wd33c93_attach() */ + int sc_chip; /* Chip variation */ + int sc_rev; /* Chip revision */ + int sc_cfflags; /* Copy of config flags */ + int sc_maxxfer; /* Maximum transfer size */ + uint8_t sc_maxoffset; /* Maximum sync offset (bytes) */ + uint8_t sc_minsyncperiod; /* Minimum supported sync xfer period */ + uint8_t sc_syncperiods[7]; /* Sync transfer periods (4ns units) */ + uint8_t sc_fsyncperiods[3]; /* Sync transfer periods for Fast SCSI*/ + + int (*sc_dmasetup)(struct wd33c93_softc *, void **, size_t *, int, + size_t *); + int (*sc_dmago)(struct wd33c93_softc *); + void (*sc_dmastop)(struct wd33c93_softc *); + void (*sc_reset)(struct wd33c93_softc *); +}; + +/* values for sc_flags */ +#define SBICF_SELECTED 0x01 /* bus is in selected state. */ +#define SBICF_NODMA 0x02 /* Polled transfer */ +#define SBICF_INDMA 0x04 /* DMA I/O in progress */ +#define SBICF_SYNCNEGO 0x08 /* Sync negotiation in progress */ +#define SBICF_ABORTING 0x10 /* Aborting */ + +/* values for sc_state */ +#define SBIC_UNINITIALIZED 0 /* Driver not initialized */ +#define SBIC_IDLE 1 /* waiting for something to do */ +#define SBIC_SELECTING 2 /* SCSI command is arbiting */ +#define SBIC_RESELECTED 3 /* Has been reselected */ +#define SBIC_IDENTIFIED 4 /* Has gotten IFY but not TAG */ +#define SBIC_CONNECTED 5 /* Actively using the SCSI bus */ +#define SBIC_DISCONNECT 6 /* MSG_DISCONNECT received */ +#define SBIC_CMDCOMPLETE 7 /* MSG_CMDCOMPLETE received */ +#define SBIC_ERROR 8 /* Error has occurred */ +#define SBIC_SELTIMEOUT 9 /* Select Timeout */ +#define SBIC_CLEANING 10 /* Scrubbing ACB's */ +#define SBIC_BUSRESET 11 /* SCSI RST has been issued */ + +/* values for sc_msgout */ +#define SEND_DEV_RESET 0x0001 +#define SEND_PARITY_ERROR 0x0002 +#define SEND_INIT_DET_ERR 0x0004 +#define SEND_REJECT 0x0008 +#define SEND_IDENTIFY 0x0010 +#define SEND_ABORT 0x0020 +#define SEND_WDTR 0x0040 +#define SEND_SDTR 0x0080 +#define SEND_TAG 0x0100 + +/* WD33c93 chipset revisions - values for sc_rev */ +#define SBIC_CHIP_UNKNOWN 0 +#define SBIC_CHIP_WD33C93 1 +#define SBIC_CHIP_WD33C93A 2 +#define SBIC_CHIP_WD33C93B 3 + +#define SBIC_CHIP_LIST {"UNKNOWN", "WD33C93", "WD33C93A", "WD33C93B"} + +/* macros for sc_cfflags */ +#define CFFLAGS_NODISC(_cf, _t) ((_cf) & (1 << ( 0 + (_t)))) +#define CFFLAGS_NOSYNC(_cf, _t) ((_cf) & (1 << ( 8 + (_t)))) +#define CFFLAGS_NOTAGS(_cf, _t) ((_cf) & (1 << (16 + (_t)))) + +/* + * States returned by our state machine + */ +#define SBIC_STATE_ERROR -1 +#define SBIC_STATE_DONE 0 +#define SBIC_STATE_RUNNING 1 +#define SBIC_STATE_DISCONNECT 2 + +#define DEBUG_ACBS 0x01 +#define DEBUG_INTS 0x02 +#define DEBUG_CMDS 0x04 +#define DEBUG_MISC 0x08 +#define DEBUG_TRAC 0x10 +#define DEBUG_RSEL 0x20 +#define DEBUG_PHASE 0x40 +#define DEBUG_DMA 0x80 +#define DEBUG_CCMDS 0x100 +#define DEBUG_MSGS 0x200 +#define DEBUG_TAGS 0x400 +#define DEBUG_SYNC 0x800 + +#ifdef SBICDEBUG +extern int wd33c93_debug_flags; +#define SBIC_DEBUG(level, str) \ + do { \ + if (wd33c93_debug & __CONCAT(DEBUG_,level)) \ + printf str; \ + } while (0) +#else +#define SBIC_DEBUG(level, str) +#endif + +void wd33c93_scsi_cmd(struct scsi_xfer *); +void wd33c93_attach(struct wd33c93_softc *, struct scsi_adapter *); +int wd33c93_intr(void *); diff --git a/sys/dev/ic/z8530reg.h b/sys/dev/ic/z8530reg.h index b07c6249914..4bf7ca41a4f 100644 --- a/sys/dev/ic/z8530reg.h +++ b/sys/dev/ic/z8530reg.h @@ -1,5 +1,5 @@ -/* $OpenBSD: z8530reg.h,v 1.6 2003/10/21 18:58:50 jmc Exp $ */ -/* $NetBSD: z8530reg.h,v 1.7 1996/10/23 00:32:31 gwr Exp $ */ +/* $OpenBSD: z8530reg.h,v 1.7 2012/03/28 20:44:23 miod Exp $ */ +/* $NetBSD: z8530reg.h,v 1.12 2005/12/11 12:21:29 christos Exp $ */ /* * Copyright (c) 1992, 1993 @@ -162,6 +162,8 @@ #define ZSWR1_TIE 0x02 /* transmit interrupt enable */ #define ZSWR1_SIE 0x01 /* external/status interrupt enable */ +#define ZSWR1_IMASK 0x1F /* mask of all itr. enable bits. */ + /* HSIS compat */ #define ZSWR1_REQ_ENABLE (ZSWR1_REQ_WAIT | ZSWR1_REQ_TX) @@ -184,6 +186,7 @@ #define ZSWR3_HUNT 0x10 /* enter hunt mode */ #define ZSWR3_RXCRC_ENABLE 0x08 /* enable recv crc calculation */ #define ZSWR3_ADDR_SEARCH_MODE 0x04 /* address search mode (SDLC only) */ +#define ZSWR3_SDLC_SHORT_ADDR 0x02 /* short address mode (SDLC only) */ #define ZSWR3_SYNC_LOAD_INH 0x02 /* sync character load inhibit */ #define ZSWR3_RX_ENABLE 0x01 /* receiver enable */ |