diff options
author | Miod Vallat <miod@cvs.openbsd.org> | 2012-03-28 20:44:24 +0000 |
---|---|---|
committer | Miod Vallat <miod@cvs.openbsd.org> | 2012-03-28 20:44:24 +0000 |
commit | 6ea0ed8392999d052b79785548a577d7e55b7184 (patch) | |
tree | b4c5fb05563150bb09cc3d203971a18a2b5277bc /sys/dev | |
parent | b71835f84a40d614f56816274c2400a719e82600 (diff) |
Work in progress support for the SGI Indigo, Indigo 2 and Indy systems
(IP20, IP22, IP24) in 64-bit mode, adapated from NetBSD. Currently limited
to headless operation, input and video drivers will get ported soon.
Should work on all R4000, R4440 and R5000 based systems. L2 cache on R5000SC
Indy not supported yet (coming soon), R4600 not supported yet either (coming
soon as well).
Tested to boot multiuser on: Indigo2 R4000SC, Indy R4000PC, Indy R4000SC,
Indy R5000SC, Indigo2 R4400SC. There are still glitches in the Ethernet driver
which are being looked at.
Expansion support is limited to the GIO E++ board; GIO boards with PCI-GIO
bridges not ported yet due to the lack of hardware, and this kind of driver
does not port blindly.
Most of this work comes from NetBSD, polishing and integration work, as well
as putting as many ``R4x00 in 64-bit mode'' erratas as necessary, by yours
truly.
More work is coming, as well as trying to get some easy way to boot install
kernels (as older PROM can only boot ECOFF binaries, which won't do for the
kernel).
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 */ |