Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Linux Kernel Patch v2.0, patch-2.0.37 (00/45)

26 views
Skip to first unread message

Thomas...@ciw.uni-karlsruhe.de

unread,
Jun 16, 1999, 3:00:00 AM6/16/99
to
Archive-name: v2.0/patch-2.0.37/part00

lines added deleted
linux/CREDITS : 64 21 5
linux/Documentation/Changes : 8 1 1
linux/Documentation/CodingStyle : 18 3 2
linux/Documentation/Configure.help : 726 428 155
linux/Documentation/README.DAC960 : 222 222 0
linux/Documentation/ide.txt : 145 135 0
linux/Documentation/isdn/README : 12 3 3
linux/Documentation/modules.txt : 8 1 1
linux/Documentation/more-than-900MB-RAM.txt : 40 40 0
linux/Documentation/networking/net-modules.txt : 8 1 1
linux/Documentation/paride.txt : 109 35 9
linux/Documentation/udma.txt : 663 663 0
linux/MAINTAINERS : 57 19 7
linux/Makefile : 25 10 2
linux/README : 29 6 10
linux/arch/alpha/Makefile : 11 2 2
linux/arch/alpha/defconfig : 16 1 2
linux/arch/i386/boot/setup.S : 47 25 2
linux/arch/i386/config.in : 37 24 0
linux/arch/i386/defconfig : 13 6 1
linux/arch/i386/kernel/Makefile : 11 5 0
linux/arch/i386/kernel/apm.c : 1269 1269 0
linux/arch/i386/kernel/bios32.c : 8 1 1
linux/arch/i386/kernel/head.S : 96 40 10
linux/arch/i386/kernel/hexify.c : 17 2 4
linux/arch/i386/kernel/process.c : 13 3 3
linux/arch/i386/kernel/setup.c : 38 7 8
linux/arch/i386/kernel/time.c : 7 1 0
linux/arch/i386/mm/init.c : 61 20 16
linux/arch/mips/defconfig : 7 0 1
linux/drivers/block/Config.in : 35 15 0
linux/drivers/block/DAC960.c : 1980 1980 0
linux/drivers/block/DAC960.h : 1565 1565 0
linux/drivers/block/Makefile : 26 12 0
linux/drivers/block/README.smart2 : 85 85 0
linux/drivers/block/TODO.smart2 : 20 20 0
linux/drivers/block/cpqarray.c : 1662 1662 0
linux/drivers/block/cpqarray.h : 98 98 0
linux/drivers/block/floppy.c : 343 93 36
linux/drivers/block/genhd.c : 102 47 4
linux/drivers/block/hd.c : 7 1 0
linux/drivers/block/ida_cmd.h : 338 338 0
linux/drivers/block/ida_ioctl.h : 80 80 0
linux/drivers/block/ide.c : 327 144 66
linux/drivers/block/ide.h : 14 1 2
linux/drivers/block/ll_rw_blk.c : 212 89 17
linux/drivers/block/paride/Config.in : 7 1 0
linux/drivers/block/paride/Makefile : 15 9 0
linux/drivers/block/paride/friq.c : 282 282 0
linux/drivers/block/paride/frpw.c : 36 10 1
linux/drivers/block/paride/jumbo : 15 4 4
linux/drivers/block/paride/on26.c : 56 16 5
linux/drivers/block/paride/paride.c : 25 8 1
linux/drivers/block/paride/pseudo.h : 70 11 9
linux/drivers/block/paride/pt.c : 8 1 1
linux/drivers/block/proc_array.c : 119 119 0
linux/drivers/block/triton.c : 675 379 183
linux/drivers/cdrom/sbpcd.c : 30 6 3
linux/drivers/char/Config.in : 27 5 9
linux/drivers/char/Makefile : 7 0 1
linux/drivers/char/apm_bios.c : 1269 0 1269
linux/drivers/char/cyclades.c : 264 77 42
linux/drivers/char/isicom.c : 15 2 0
linux/drivers/char/keyboard.c : 15 7 2
linux/drivers/char/random.c : 17 10 0
linux/drivers/char/selection.h : 25 4 3
linux/drivers/char/serial.c : 608 407 72
linux/drivers/char/tga.c : 19 1 5
linux/drivers/char/tty_io.c : 44 21 2
linux/drivers/isdn/isdn_net.c : 61 16 13
linux/drivers/isdn/isdn_ppp.c : 34 7 3
linux/drivers/net/3c59x.c : 1845 481 519
linux/drivers/net/Makefile : 10 2 2
linux/drivers/net/README.rcpci : 79 79 0
linux/drivers/net/Space.c : 7 1 0
linux/drivers/net/at1700.c : 22 0 9
linux/drivers/net/de4x5.c : 94 20 8
linux/drivers/net/de4x5.h : 7 1 0
linux/drivers/net/depca.c : 631 293 120
linux/drivers/net/dgrs.c : 12 2 1
linux/drivers/net/dummy.c : 18 5 0
linux/drivers/net/eepro100.c : 1091 335 268
linux/drivers/net/epic100.c : 279 52 60
linux/drivers/net/eql.c : 20 2 2
linux/drivers/net/eth16i.c : 8 1 1
linux/drivers/net/lance.c : 55 16 8
linux/drivers/net/ne.c : 34 4 3
linux/drivers/net/ni52.c : 12 2 1
linux/drivers/net/pi2.c : 8 1 1
linux/drivers/net/ppp.c : 8 1 1
linux/drivers/net/pt.c : 8 1 1
linux/drivers/net/rcif.h : 145 66 2
linux/drivers/net/rclanmtl.c : 2311 2311 0
linux/drivers/net/rclanmtl.h : 637 637 0
linux/drivers/net/rcmtl.c : 2058 0 2058
linux/drivers/net/rcmtl.h : 580 0 580
linux/drivers/net/rcpci45.c : 2113 968 845
linux/drivers/net/rtl8139.c : 1328 457 339
linux/drivers/net/sdla.c : 52 7 4
linux/drivers/net/skeleton.c : 15 0 9
linux/drivers/net/tulip.c : 1874 565 552
linux/drivers/net/wavelan.c : 275 93 36
linux/drivers/net/wavelan.h : 16 3 0
linux/drivers/net/wavelan.p.h : 112 31 28
linux/drivers/pci/pci.c : 173 50 8
linux/drivers/scsi/ChangeLog.ncr53c8xx : 1410 262 1131
linux/drivers/scsi/Config.in : 72 20 11
linux/drivers/scsi/Makefile : 100 71 0
linux/drivers/scsi/README.aic7xxx : 150 56 26
linux/drivers/scsi/README.ncr53c8xx : 526 154 148
linux/drivers/scsi/README.tmscsim : 418 418 0
linux/drivers/scsi/RELEASE_NOTES.DAC960 : 74 74 0
linux/drivers/scsi/TRIPACE.REL : 21 21 0
linux/drivers/scsi/aha1542.c : 21 4 4
linux/drivers/scsi/aic7xxx.c : 1802 565 460
linux/drivers/scsi/aic7xxx_proc.c : 229 78 91
linux/drivers/scsi/atp870u.c : 2029 2029 0
linux/drivers/scsi/atp870u.h : 64 64 0
linux/drivers/scsi/dc390.h : 167 24 112
linux/drivers/scsi/hosts.c : 95 53 0
linux/drivers/scsi/i60uscsi.c : 956 956 0
linux/drivers/scsi/i60uscsi.h : 572 572 0
linux/drivers/scsi/i91uscsi.c : 2808 2808 0
linux/drivers/scsi/i91uscsi.h : 857 857 0
linux/drivers/scsi/ini9100u.c : 1104 1104 0
linux/drivers/scsi/ini9100u.h : 345 345 0
linux/drivers/scsi/inia100.c : 953 953 0
linux/drivers/scsi/inia100.h : 503 503 0
linux/drivers/scsi/megaraid.c : 1929 715 581
linux/drivers/scsi/megaraid.h : 318 130 114
linux/drivers/scsi/ncr53c8xx.c : 10085 3659 3176
linux/drivers/scsi/ncr53c8xx.h : 458 110 161
linux/drivers/scsi/pci2000.c : 716 716 0
linux/drivers/scsi/pci2000.h : 226 226 0
linux/drivers/scsi/pci2220i.c : 819 819 0
linux/drivers/scsi/pci2220i.h : 345 345 0
linux/drivers/scsi/psi240i.c : 717 717 0
linux/drivers/scsi/psi240i.h : 344 344 0
linux/drivers/scsi/psi_chip.h : 195 194 0
linux/drivers/scsi/psi_dale.h : 187 187 0
linux/drivers/scsi/psi_roy.h : 337 337 0
linux/drivers/scsi/scsi.c : 14 2 0
linux/drivers/scsi/scsi_syms.c : 22 2 3
linux/drivers/scsi/scsicam.c : 37 4 5
linux/drivers/scsi/scsiiom.c : 2403 958 781
linux/drivers/scsi/seagate.c : 8 1 1
linux/drivers/scsi/sym53c416.c : 805 805 0
linux/drivers/scsi/sym53c416.h : 91 91 0
linux/drivers/scsi/tmscsim.c : 3552 1795 1129
linux/drivers/scsi/tmscsim.h : 667 214 193
linux/drivers/scsi/tripace.c : 1562 1562 0
linux/drivers/scsi/tripace.h : 57 57 0
linux/drivers/scsi/tripace_mcode.h : 483 483 0
linux/drivers/sound/audio.c : 9 3 0
linux/fs/Config.in : 72 33 26
linux/fs/Makefile : 14 8 0
linux/fs/autofs/root.c : 30 10 0
linux/fs/ext2/fsync.c : 22 9 0
linux/fs/ioctl.c : 92 35 27
linux/fs/isofs/inode.c : 69 22 7
linux/fs/locks.c : 174 65 27
linux/fs/ncpfs/Config.in : 9 9 0
linux/fs/ncpfs/Makefile : 9 2 1
linux/fs/ncpfs/dir.c : 274 185 17
linux/fs/ncpfs/inode.c : 128 66 7
linux/fs/ncpfs/ioctl.c : 259 239 0
linux/fs/ncpfs/ncplib_kernel.c : 393 243 25
linux/fs/ncpfs/ncplib_kernel.h : 41 22 0
linux/fs/ncpfs/ncpsign_kernel.c : 125 125 0
linux/fs/ncpfs/ncpsign_kernel.h : 16 16 0
linux/fs/ncpfs/sock.c : 30 9 1
linux/fs/nls.c : 9 3 0
linux/fs/nls_iso8859_15.c : 268 268 0
linux/fs/open.c : 10 4 0
linux/fs/proc/array.c : 63 1 49
linux/fs/read_write.c : 8 1 1
linux/fs/select.c : 11 1 3
linux/include/asm-alpha/ioctls.h : 8 2 0
linux/include/asm-i386/bugs.h : 58 39 0
linux/include/asm-i386/ioctls.h : 8 2 0
linux/include/asm-i386/page.h : 23 4 1
linux/include/asm-i386/pgtable.h : 59 19 3
linux/include/asm-i386/processor.h : 12 2 3
linux/include/asm-i386/system.h : 8 1 1
linux/include/linux/apm_bios.h : 25 2 3
linux/include/linux/blk.h : 25 11 1
linux/include/linux/blkdev.h : 21 9 0
linux/include/linux/cyclades.h : 90 30 5
linux/include/linux/fd.h : 8 1 1
linux/include/linux/hdreg.h : 71 45 4
linux/include/linux/icmp.h : 13 3 0
linux/include/linux/in.h : 9 3 0
linux/include/linux/major.h : 20 10 0
linux/include/linux/ncp_fs.h : 68 40 2
linux/include/linux/ncp_fs_sb.h : 20 7 0
linux/include/linux/ncp_mount.h : 32 8 5
linux/include/linux/nls.h : 14 2 0
linux/include/linux/pci.h : 143 48 2
linux/include/linux/proc_fs.h : 21 7 0
linux/include/linux/serial.h : 50 37 0
linux/include/linux/tasks.h : 8 1 1
linux/include/linux/via_ide_dma.h : 162 162 0
linux/include/linux/wireless.h : 49 15 3
linux/include/net/ip_masq.h : 13 7 0
linux/include/scsi/scsicam.h : 6 2 0
linux/init/main.c : 99 41 2
linux/kernel/ksyms.c : 8 2 0
linux/kernel/panic.c : 17 4 0
linux/kernel/sched.c : 64 50 1
linux/kernel/sys.c : 37 10 0
linux/net/appletalk/ddp.c : 48 10 3
linux/net/bridge/br.c : 77 22 11
linux/net/bridge/br_tree.c : 11 5 0
linux/net/ipv4/Config.in : 23 17 0
linux/net/ipv4/arp.c : 17 4 2
linux/net/ipv4/igmp.c : 24 8 3
linux/net/ipv4/ip_masq.c : 1949 1722 3
linux/net/ipv4/ip_sockglue.c : 47 21 7
linux/net/ipv4/rarp.c : 17 4 0
linux/net/netlink.c : 15 2 0
linux/net/netrom/af_netrom.c : 18 8 0
linux/net/netsyms.c : 28 8 0
linux/scripts/Menuconfig : 28 15 0
linux/scripts/tkgen.c : 91 19 5
linux/scripts/tkparse.c : 22 9 0
linux/scripts/tkparse.h : 7 1 0
--
Thomas Koenig, Thomas...@ciw.uni-karlsruhe.de, ig...@dkauni2.bitnet.
The joy of engineering is to find a straight line on a double
logarithmic diagram.

Thomas...@ciw.uni-karlsruhe.de

unread,
Jun 16, 1999, 3:00:00 AM6/16/99
to
Archive-name: v2.0/patch-2.0.37/part01

#!/bin/sh
# This is a shell archive
# To extract the files from this archive, save it to a file, remove
# everything above the "!/bin/sh" line above, and type "sh file_name".
# existing files will NOT be overwritten unless -c is specified
#
# This is part 01 of a 45 - part archive
# do not concatenate these parts, unpack them in order with /bin/sh
#
if test -r _shar_seq_.tmp; then
echo 'Must unpack archives in sequence!'
echo Please unpack part `cat _shar_seq_.tmp` next
exit 1
fi
# ============= patch-2.0.37 ==============
if test -f 'patch-2.0.37' -a X"$1" != X"-c"; then
echo 'x - skipping patch-2.0.37 (File already exists)'
rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting patch-2.0.37 (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'patch-2.0.37' &&
diff -u --recursive --new-file v2.0.36/linux/CREDITS linux/CREDITS
--- v2.0.36/linux/CREDITS Sun Nov 15 21:51:46 1998
+++ linux/CREDITS Sun Jun 13 10:20:59 1999
@@ -557,6 +557,14 @@
X S: Atlanta, Georgia 30332
X S: USA
X
+N: John Hardin
+E: jha...@wolfenet.com
+W: http://www.wolfenet.com/~jhardin/
+D: IPSec and PPTP masquerade
+S: 17014 Broadway ave.
+S: Snohomish, WA 98296-8031
+S: USA
+
X N: Angelo Haritsis
X E: a...@doc.ic.ac.uk
X D: kernel patches (serial, watchdog)
@@ -796,11 +804,11 @@
X D: for Menuconfig's lxdialog.
X
X N: Volker Lendecke
-E: lend...@namu01.Num.Math.Uni-Goettingen.de
+E: v...@kki.org
X D: Kernel smbfs (to mount WfW, NT and OS/2 network drives.)
X D: NCP filesystem support (to mount NetWare volumes)
-S: Innersteweg 11
-S: 37081 Goettingen
+S: Von Ossietzky Str. 12
+S: 37085 Goettingen
X S: Germany
X
X N: Kevin Lentin
@@ -1192,10 +1200,12 @@
X
X N: Stephen Rothwell
X E: Stephen....@canb.auug.org.au
+W: http://www.canb.auug.org.au/~sfr
+P: 1024/BD8C7805 CD A4 9D 01 10 6E 7E 3B 91 88 FA D9 C8 40 AA 02
X D: Boot/setup/build work for setup > 2K
X D: Author, APM driver
-S: 59 Bugden Avenue
-S: Gowrie ACT 2904
+S: 66 Maltby Circuit
+S: Wanniassa ACT 2903
X S: Australia
X
X N: Gerard Roudier
@@ -1245,6 +1255,11 @@
X S: B2240 Zandhoven
X S: Belgium
X
+N: Henning P. Schmiedehausen
+E: h...@tanstaafl.de
+D: added PCI support to the serial driver
+S: Buckenhof, Germany
+
X N: Martin Schulze
X E: jo...@linux.de
X W: http://home.pages.de/~joey/
@@ -1641,6 +1656,7 @@
X E: l...@dandelion.com
X W: http://www.dandelion.com/Linux/
X D: BusLogic SCSI driver
+D: Mylex DAC960 PCI RAID driver
X D: Miscellaneous kernel fixes
X S: 3078 Sulphur Spring Court
X S: San Jose, California 95148
diff -u --recursive --new-file v2.0.36/linux/Documentation/Changes linux/Documentation/Changes
--- v2.0.36/linux/Documentation/Changes Sun Nov 15 21:51:46 1998
+++ linux/Documentation/Changes Sun Jun 13 10:20:59 1999
@@ -513,7 +513,7 @@
X as well. APM, which is primarily of use in laptops, provides access to
X battery status information and may help to conserve battery power. The
X support files can be found in
-ftp://tsx-11.mit.edu/pub/linux/packages/laptops/apm/apmd-2.4.tar.gz
+http://www.worldvisions.ca/~apenwarr/apmd/
X
X iBCS and Dosemu
X ===============
diff -u --recursive --new-file v2.0.36/linux/Documentation/CodingStyle linux/Documentation/CodingStyle
--- v2.0.36/linux/Documentation/CodingStyle Sun Nov 15 10:49:21 1998
+++ linux/Documentation/CodingStyle Tue Dec 29 11:57:33 1998
@@ -8,7 +8,7 @@
X at least consider the points made here.
X
X First off, I'd suggest printing out a copy of the GNU coding standards,
-and NOT read it. Burn them, it's a great symbolic gesture.
+and NOT reading it. Burn them, it's a great symbolic gesture.
X
X Anyway, here goes:
X
@@ -59,7 +59,8 @@
X Heretic people all over the world have claimed that this inconsistency
X is ... well ... inconsistent, but all right-thinking people know that
X (a) K&R are _right_ and (b) K&R are right. Besides, functions are
-special anyway (you can't nest them in C).
+special anyway (you can't nest them in C (well, you can in gcc, actually,
+but this is horribly nonstandard, so we will ignore it)).
X
X Note that the closing brace is empty on a line of its own, _except_ in
X the cases where it is followed by a continuation of the same statement,
diff -u --recursive --new-file v2.0.36/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v2.0.36/linux/Documentation/Configure.help Sun Nov 15 21:51:46 1998
+++ linux/Documentation/Configure.help Sun Jun 13 10:20:59 1999
@@ -58,6 +58,29 @@
X you say Y here, you will be offered the choice of using features or
X drivers that are currently considered to be in the alpha-test phase.
X
+Symmetric Multi Processing
+CONFIG_SMP
+ This enables support for systems with more than one CPU. If you have a
+ system with only one CPU, like most personal computers, say N. If you
+ have a system with more than one CPU, say Y.
+
+ A non-SMP kernel will run on any machine, but will use only one CPU of
+ a multi-CPU machine. An SMP kernel will run on many, but not all,
+ single-CPU machines. On a single-CPU machine, a non-SMP kernel
+ will run faster than an SMP kernel.
+
+ People using multiprocessor machines should also say Y to "Enhanced
+ Real Time Clock Support", below. The "Advanced Power Management"
+ code will be disabled in an SMP kernel.
+
+ If you don't know what to do here, say N.
+
+ See also: Documentation/SMP.txt, Documentation/smp.tex,
+ Documentation/smp.txt, and Documentation/IO-APIC.txt. Also see the
+ SMP-FAQ on the WWW at http://www.irisa.fr/prive/mentre/smp-faq/ (to
+ browse the WWW, you need to have access to a machine on the Internet
+ that has a program like lynx or netscape).
+
X Kernel math emulation
X CONFIG_MATH_EMULATION
X Linux can emulate a math coprocessor (used for floating point
@@ -79,6 +102,14 @@
X arch/i386/math-emu/README. If you are not sure, say Y; apart from
X resulting in a 45kB bigger kernel, it won't hurt.
X
+Max physical memory
+CONFIG_MAX_MEMSIZE
+ Linux/x86 can use up to ~3.5 gigabytes of physical memory. Default
+ is maximum 950 megabyte physical memory, this is enough for most
+ systems. (if you have more than 900MB RAM, see
+ Documentation/more-than-900MB-RAM.txt how to configure this option. Do
+ not change this value if you have less than 950MB RAM!)
+
X Normal floppy disk support
X CONFIG_BLK_DEV_FD
X If you want to use your floppy disk drive(s) under Linux, say Y.
@@ -165,6 +196,15 @@
X addresses. Normally, just say N here; you will then use the new
X driver for all 4 interfaces.
X
+Use multi-mode by default
+CONFIG_IDEDISK_MULTI_MODE
+ If you get this error, try to enable this option.
+
+ hda: set_multmode: status=0x51 { DriveReady SeekComplete Error }
+ hda: set_multmode: error=0x04 { DriveStatusError }
+
+ If in doubt, say N.
+
X Include IDE/ATAPI CDROM support
X CONFIG_BLK_DEV_IDECD
X If you have a CDROM drive using the ATAPI protocol, say Y. ATAPI is
@@ -320,6 +360,12 @@
X Documentation/modules.txt.
X It's pretty unlikely that you have one of these: say N.
X
+Mylex DAC960/DAC1100 PCI RAID Controller support
+CONFIG_BLK_DEV_DAC960
+ This driver adds support for the Mylex DAC960, AcceleRAID, and
+ eXtremeRAID PCI RAID controllers. See README.DAC960 for further
+ information about this driver.
+
X Parallel port IDE device support
X CONFIG_PARIDE
X There are many external CD-ROM and disk devices that connect through
@@ -483,6 +529,16 @@
X be called fit3.o. You must also have a high-level driver for the
X type of device that you want to support.
X
+Freecom IQ ASIC-2 protocol
+CONFIG_PARIDE_FRIQ
+ This option enables support for version 2 of the Freecom IQ parallel
+ port IDE adapter. This adapter is used by the Maxell Superdisk
+ drive. If you chose to build PARIDE support into your kernel, you
+ may answer Y here to build in the protocol driver, otherwise you
+ should answer M to build it as a loadable module. The module will be
+ called friq.o. You must also have a high-level driver for the type
+ of device that you want to support.
+
X FreeCom power protocol
X CONFIG_PARIDE_FRPW
X This option enables support for the Freecom power parallel port IDE
@@ -828,15 +884,33 @@
X certain BIOSes if your computer uses a PCI bus system. This is
X recommended; say Y.
X
-Intel 82371 PIIX (Triton I/II) DMA support
+Generic IDE (U)DMA support
X CONFIG_BLK_DEV_TRITON
- If your PCI system uses an IDE hard drive (as opposed to SCSI, say)
- and includes the Intel Triton I/II IDE interface chipset (i82371FB,
+ If your PCI system uses an EIDE hard disk (as opposed to SCSI, say)
+ and includes one of the Intel (U)DMA IDE Southbridge ICs (i82371FB,
X i82371SB or i82371AB), you will want to enable this option to allow
- use of bus-mastering DMA data transfers. Read the comments at the
- beginning of drivers/block/triton.c and Documentation/ide.txt.
+ use of bus-mastering DMA data transfers. This increases transfer
+ rates and reduces latencies and CPU utilization. Read the comments in
+ Documentation/ide.txt and Documentation/udma.txt.
X Check the file Documentation/Changes for location and latest version
- of the hdparm utility. It is safe to say Y to this question.
+ of the hdparm utility. There are now several more chipsets added, to
+ include offboard PCI-IDE-UDMA cards and newer SiS and VIA chipsets.
+ It is safe to say Y to this question, as long as your PCI bus is
+ operating within specs (33MHz recommended).
+
+Boot off-board chipsets first support
+CONFIG_BLK_DEV_OFFBOARD
+ Normally, IDE controllers built into the motherboard (on-board
+ controllers) are assigned to ide0 and ide1 while those on add-in
+ PCI cards (off-board controllers) are relegated to ide2 and ide3.
+ Saying Y to here will reverse the situation, with off-board
+ controllers on ide0/1 and on-board controllers on ide2/3. This
+ can improve the usability of some boot managers such as LILO
+ when booting from a drive on an off-board controller.
+ Note that this will rearrange the order of the hd* devices and
+ may require modification of fstab and other files.
+ Check the file Documentation/udma.txt
+ If in doubt, say N.
X
X System V IPC
X CONFIG_SYSVIPC
@@ -956,6 +1030,7 @@
X the other hand, if you use a compiler before gcc 2.7 (say "gcc -v"
X to find out), then you have to say "386" or "486" here even if
X running on a Pentium or PPro machine.
+
X If you don't know what to do, say "386".
X
X Compile the kernel into the ELF object format
@@ -1199,6 +1274,65 @@
X IP always defragment.
X If you want this, say Y.
X
+IP: MS PPTP masq support (EXPERIMENTAL)
+CONFIG_IP_MASQUERADE_PPTP
+ Support for masquerading of the GRE data channel portion of the PPTP
+ Virtual Private Network protocol.
+ If you are masquerading a PPTP client or server you need to enable
+ this in addition to regular IP Masquerade.
+ See http://www.wolfenet.com/~jhardin/ip_masq_pptp.html for more details.
+
+IP: MS PPTP Call ID masq support (EXPERIMENTAL)
+CONFIG_IP_MASQUERADE_PPTP_MULTICLIENT
+ Enabling this adds code to masquerade PPTP Call IDs, which allows
+ more than one masqueraded client to access the same server.
+ This only needs to be enabled if you are masquerading more than one
+ client, and if those clients will try to access the same PPTP server
+ at the same time.
+ You do NOT need to enable this if you are masquerading a PPTP
+ server, regardless of how many clients will be accessing it.
+
+IP: MS PPTP masq debugging
+DEBUG_IP_MASQUERADE_PPTP
+ Enables PPTP Masquerade debugging messages. This should be disabled
+ for normal use once you have PPTP masq working, as it will cause
+ your system logs to quickly grow rather large. Enable verbose
+ debugging for more detailed information.
+
+IP: IPSEC ESP & ISAKMP masq support (EXPERIMENTAL)
+CONFIG_IP_MASQUERADE_IPSEC
+ Support for limited masquerading of the IPSEC ESP network encryption
+ and ISAKMP key-exchange protocols.
+ If you are masquerading an IPSEC client you need to enable this in
+ addition to regular IP Masquerade.
+ Note that this may not successfully masquerade all types of
+ IPSEC-based encryption, as some options in the protocol offer a
+ cryptographic checksum across the IP addresses, which prevents the
+ masqueraded packets from being accepted.
+
+IP: IPSEC masq table lifetime (minutes)
+CONFIG_IP_MASQUERADE_IPSEC_EXPIRE
+ After a period of inactivity IPSEC masq table entries expire and are
+ removed. When this happens inbound traffic can no longer be routed
+ to the masqueraded host until new outbound traffic creates a new
+ masq table entry.
+ For greatest reliability, your IPSEC rekey interval should be less
+ than the table entry lifetime. If your rekey interval is greater
+ than thirty minutes you will improve security by reducing it to
+ thirty minutes. If you don't want to do that, then increase the masq
+ table entry lifetime. Note that doing this will increase the clutter
+ in the IPSEC masq table, as old table entries will persist for this
+ many minutes after a rekey.
+ The minimum lifetime is 15 minutes. Decreasing the lifetime will
+ interfere with sessions that are idle for long periods of time.
+
+IP: IPSEC masq debugging
+DEBUG_IP_MASQUERADE_IPSEC
+ Enables IPSEC Masquerade debugging messages. This should be disabled
+ for normal use once you have IPSEC masq working, as it will cause
+ your system logs to quickly grow rather large. Enable verbose
+ debugging for more detailed information.
+
X IP: ipautofw masquerading (EXPERIMENTAL)
X CONFIG_IP_MASQUERADE_IPAUTOFW
X Richard Lynch's ipautofw allows masquerading to work with protocols
@@ -1622,66 +1756,102 @@
X Adaptec AIC7xxx chipset SCSI controller support
X CONFIG_SCSI_AIC7XXX
X This is support for the various aic7xxx based Adaptec SCSI
- controllers. These include the 274x EISA cards, 284x VLB cards,
- 294x PCI cards, 394x PCI cards, 3985 PCI card, and several versions
- of the Adaptec built-in SCSI controllers on various PC motherboards.
+ controllers. These include the 274x EISA cards; 284x VLB cards; 2902,
+ 2910, 293x, 294x, 394x, 3985 and several other PCI and motherboard based
+ SCSI controllers from Adaptec. It does not support the AAA-13x RAID
+ controllers from Adaptec, nor will it likely ever support them. It
+ does not support the 2920 cards from Adaptec that use the Future Domain
+ SCSI controller chip. For those cards, you need the "Future Domain
+ 16xx SCSI support" driver.
+
+ In general, if the controller is based on an Adaptec SCSI controller
+ chip from the aic777x series or the aic78xx series, it should work. The
+ only exception is the 7810 which is specifically not supported (that's the
+ RAID controller chip on the AAA-13x cards).
+
X Information on the configuration options for this controller can be
- found by checking the README.aic7xxx file, usually in
- /usr/src/linux/drivers/scsi.
+ found by checking the help file for each of the available
+ configuration options. You should read drivers/scsi/README.aic7xxx
+ at a minimum before contacting the maintainer with any questions.
+ The SCSI-HOWTO, available via FTP (user: anonymous) at
+ ftp://metalab.unc.edu/pub/Linux/docs/HOWTO can also be of great help.
+
+ If you want to compile this driver as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want),
+ say M here and read Documentation/modules.txt. The module will be
+ called aic7xxx.o.
+
+Enable or Disable Tagged Command Queueing by default
+CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT
+ This option causes the aic7xxx driver to attempt to use tagged command
+ queueing on any devices that claim to support it. If this is set to yes,
+ you can still turn off TCQ on troublesome devices with the use of the
+ tag_info boot parameter. See /usr/src/linux/drivers/scsi/README.aic7xxx
+ for more information on that and other aic7xxx setup commands. If this
+ option is turned off, you may still enable TCQ on known good devices by
+ use of the tag_info boot parameter.
+
+ If you are unsure about your devices then it is safest to say N here.
+
+ However, TCQ can increase performance on some hard drives by as much
+ as 50% or more, so I would recommend that if you say N here, that you
+ at least read the README.aic7xxx file so you will know how to enable
+ this option manually should your drives prove to be safe in regards
+ to TCQ.
+
+ Conversely, certain drives are known to lock up or cause bus resets when
+ TCQ is enabled on them. If you have a Western Digital Enterprise SCSI
+ drive for instance, then don't even bother to enable TCQ on it as the
+ drive will become unreliable, and it will actually reduce performance.
+
+Default number of TCQ commands per device
+CONFIG_AIC7XXX_CMDS_PER_DEVICE
+ Specify the number of commands you would like to allocate per SCSI
+ device when Tagged Command Queueing (TCQ) is enabled on that device.
+
+ Reasonable figures are in the range of 8 to 24 commands per device,
+ but depending on hardware could be increased or decreased from that
+ figure. If the number is too high for any particular device, the
+ driver will automatically compensate usually after only 10 minutes
+ of uptime. It will not hinder performance if some of your devices
+ eventually have their command depth reduced, but is a waste of memory
+ if all of your devices end up reducing this number down to a more
+ reasonable figure.
+
+ NOTE: Certain very broken drives are known to lock up when given more
+ commands than they like to deal with. Quantum Fireball drives are the
+ most common in this category. For the Quantum Fireball drives I would
+ suggest no more than 8 commands per device.
X
-Override driver defaults for commands per LUN
-CONFIG_OVERRIDE_CMDS
- Use this option to allow you to override the default maximum number
- of commands that a single device on the aic7xxx controller is
- allowed to have active at one time. This option only effects tagged
- queueing capable devices. The driver uses a "failsafe" value of 8
- by default. This is much lower than many devices can handle, but
- left in place for safety sake.
- NOTE: This does not actually enabled tagged queueing on any
- particular device. The driver has changed in this respect. Please
- see the file README.aic7xxx in /usr/src/linux/drivers/scsi for more
- information on how to get particular devices to use tagged command
- queueing.
- Default: N
-
-Maximum number of commands per LUN
-CONFIG_AIC7XXX_CMDS_PER_LUN
- Specify the maximum number of commands per lun you would like to
- allocate per device. Reasonable figures are in the range of 14 to
- 32 commands per device, but depending on hardware could be increased
- or decreased from that figure. If the number is too high for any
- particular device, the driver will automatically compensate usually
- after only 10 minutes of uptime and will issue a message to alert
- you to the fact that the number of commands for that device has been
- reduced. It will not hinder performance if a portion of your
- devices eventually have their commands per lun reduced, but is a
- waste of memory if all of your devices end up reducing this number
- down to a more reasonable figure. Default: 24
+ Default: 8
X
X Collect statistics to report in /proc
X CONFIG_AIC7XXX_PROC_STATS
X This option tells the driver to keep track of how many commands have
X been sent to each particular device and report that information to
- the user via the /proc/scsi/aic7xxx/x file, where x is the number
- of the aic7xxx controller you want the information on. This adds
- a small amount of overhead to each and every SCSI command the
- aic7xxx driver handles, so if you aren't really interested in this
- information, it is best to leave it disabled. Default: N
+ the user via the /proc/scsi/aic7xxx/n file, where n is the number of
+ the aic7xxx controller you want the information on. This adds a
+ small amount of overhead to each and every SCSI command the aic7xxx
+ driver handles, so if you aren't really interested in this
+ information, it is best to leave it disabled. This will only work if
+ you also say Y to "/proc filesystem support", below.
+
+ If unsure, say N.
X
X Delay in seconds after SCSI bus reset
X CONFIG_AIC7XXX_RESET_DELAY
X This sets how long the driver will wait after resetting the SCSI bus
X before attempting to communicate with the devices on the SCSI bus
- again. This delay will be used during the reset phase at bootup
- time as well as after any reset that might occur during normal
- operation. Reasonable numbers range anywhere from 5 to 15 seconds
- depending on your devices. DAT tape drives are notorious for needing
- more time after a bus reset to be ready for the next command, but
- most hard drives and CD-ROM devices are ready in only a few seconds.
- This option has a maximum upper limit of 20 seconds to avoid bad
- interactions between the aic7xxx driver and the rest of the Linux
- kernel. The default value has been reduced. If this doesn't work
- with your hardware, try increasing this value. Default: 5
+ again. This delay will be used during the reset phase at bootup time
+ as well as after any reset that might occur during normal operation.
+ Reasonable numbers range anywhere from 5 to 15 seconds depending on
+ your devices. DAT tape drives are notorious for needing more time
+ after a bus reset to be ready for the next command, but most hard
+ drives and CD-ROM devices are ready in only a few seconds. This
+ option has a maximum upper limit of 20 seconds to avoid bad
+ interactions between the aic7xxx driver and the rest of the linux
+ kernel. The default value has been reduced to 5 seconds. If this
+ doesn't work with your hardware, try increasing this value.
X
X BusLogic SCSI support
X CONFIG_SCSI_BUSLOGIC
@@ -1833,43 +2003,50 @@
X CONFIG_SCSI_NCR53C8XX
X This is the BSD ncr driver adapted to Linux for the NCR53C8XX family
X of PCI-SCSI controllers. This driver supports parity checking,
- tagged command queuing, fast SCSI II transfer up to 10 MB/s with
- narrow SCSI devices and 20 MB/s with wide SCSI devices.
- Support of Ultra SCSI data transfers with NCR53C860 and NCR53C875
- controllers has been recently added to the driver.
+ tagged command queuing and fast synchronous data transfers up to 80
+ MB/s with wide FAST-40 LVD devices and controllers.
+ The NCR53C860 and NCR53C875 support FAST-20 transfers. The NCR53C895
+ supports FAST-40 transfers with Ultra2 LVD devices.
+ If you have a SYM53C896 PCI-SCSI controller, you may want to use the new
+ improved driver available at ftp://ftp.tux.org/pub/roudier/896/.
X Please read drivers/scsi/README.ncr53c8xx for more information.
- Linux/i386 and Linux/Alpha are supported by this driver.
-
+
X Synchronous data transfers frequency
X CONFIG_SCSI_NCR53C8XX_SYNC
- SCSI-2 specifications allow SCSI devices to negotiate a synchronous
- transfer period of 25 nano-seconds or more.
- The transfer period value is 4 times the agreed transfer period.
- So, data can be transferred at a 10 MHz frequency, allowing 10
- MB/second throughput with 8 bits SCSI-2 devices and 20 MB/second
- with wide16 devices. This frequency can be used safely with
- differential devices but may cause problems with singled-ended
- devices.
- Specify 0 if you want to only use asynchronous data transfers.
- Otherwise, specify a value between 5 and 10. Commercial O/Ses
- generally use 5 Mhz frequency for synchronous transfers. It is a
- reasonable default value.
- However, a flawless singled-ended SCSI bus supports 10 MHz data
- transfers. Regardless the value chosen in the Linux configuration,
- the synchronous period can be changed after boot-up through the
- /proc/scsi file system. The generic command is:
- echo "setsync #target period" >/proc/scsi/ncr53c8xx/0
- Use a 25 ns period for 10 Mhz synchronous data transfers.
- If you don't know what to do now, go with the default.
+ The SCSI Parallel Interface-2 Standard defines 4 classes of transfer
+ rates: FAST-5, FAST-10, FAST-20 and FAST-40. The numbers are
+ respectively the maximum data transfer rates in mega-transfers per
+ second for each class. For example, a FAST-20 Wide 16 device is able
+ to transfer data at 20 million 16 bit packets per second for a total
+ rate of 40 MB/s.
+ You may specify 0 if you want to only use asynchronous data
+ transfers. This is the safest and slowest option. Otherwise, specify
+ a value between 5 and 40, depending on the capability of your SCSI
+ controller. The higher the number, the faster the data transfer.
+ Note that 40 should normally be ok since the driver decreases the
+ value automatically according to the controller's capabilities.
+ Your answer to this question is ignored for controllers with NVRAM,
+ since the driver will get this information from the user set-up. It
+ also can be overridden using a boot setup option, as follows
+ (example): 'ncr53c8xx=sync:12' will allow the driver to negotiate
+ for FAST-20 synchronous data transfer (20 mega-transfers per
+ second).
+ The normal answer therefore is not to go with the default but to
+ select the maximum value 40 allowing the driver to use the maximum
+ value supported by each controller. If this causes problems with
+ your SCSI devices, you should come back and decrease the value.
+ There is no safe option other than using good cabling, right
+ terminations and SCSI conformant devices.
X
X Use normal IO
X CONFIG_SCSI_NCR53C8XX_IOMAPPED
- This option allows you to force the driver to use normal IO.
- Memory mapped IO has less latency than normal IO and works for most
- Intel-based hardware.
- Under Linux/Alpha only normal IO is currently supported by the
- driver and so, this option has no effect.
- The normal answer therefore is N.
+ If you say Y here, the driver will use normal IO, as opposed to
+ memory mapped IO. Memory mapped IO has less latency than normal IO
+ and works for most Intel-based hardware. Under Linux/Alpha only
+ normal IO is currently supported by the driver and so, this option
+ has no effect on those systems.
+ The normal answer therefore is N; try Y only if you encounter SCSI
+ related problems.
X
X Not allow targets to disconnect
X CONFIG_SCSI_NCR53C8XX_NO_DISCONNECT
@@ -1877,70 +2054,61 @@
X device of yours to not support properly the target-disconnect
X feature. In that case, you would say Y here. In general however, to
X not allow targets to disconnect is not reasonable if there is more
- than 1 device on a SCSI bus. The normal answer therefore is N.
+ than 1 device on a SCSI bus. The normal answer therefore is N.
X
-Enable tagged command queuing
-CONFIG_SCSI_NCR53C8XX_TAGGED_QUEUE
- This option allows you to enable tagged command queuing support at
- Linux start-up. Some SCSI devices do not properly support this
- feature. The suggested method is to say N here and to use the
- "settags" control command after boot-up to enable this feature:
- echo "settags 2 4" >/proc/scsi/ncr53c8xx/0
- asks the driver to use up to 4 concurrent tagged commands for target
- 2 of controller 0.
- See the file drivers/scsi/README.ncr53c8xx for more information.
- WARNING! If you say Y here, then you have to say N to "not allow
- targets to disconnect", above.
- The safe answer therefore is N.
- The normal answer therefore is Y.
+Default tagged command queue depth
+CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS
+ "Tagged command queuing" is a feature of SCSI-2 which improves
+ performance: the host adapter can send several SCSI commands to a
+ device's queue even if previous commands haven't finished yet. Some
+ SCSI devices don't implement this properly; if you want to disable
+ this feature, enter 0 or 1 here (it doesn't matter which).
+ The default value is 8 and should be supported by most hard disks.
+ This value can be overridden from the boot command line using the
+ 'tags' option as follows (example):
+ 'ncr53c8xx=tags:4/t2t3q16/t0u2q10' will set default queue depth to
+ 4, set queue depth to 16 for target 2 and target 3 on controller 0
+ and set queue depth to 10 for target 0 / lun 2 on controller 1.
+ The normal answer therefore is to go with the default 8 and to use
+ a boot command line option for devices that need to use a different
+ command queue depth.
+ There is no safe option other than using good SCSI devices.
X
X Maximum number of queued commands
X CONFIG_SCSI_NCR53C8XX_MAX_TAGS
X This option allows you to specify the maximum number of commands
- that can be queued to a device, when tagged command queuing is
- possible. The default value is 4. Minimum is 2, maximum is 12. The
- normal answer therefore is the default one.
-
-Detect and read serial NVRAM
-CONFIG_SCSI_NCR53C8XX_NVRAM_DETECT
- Enable support for reading the serial NVRAM data on Symbios and
- some Symbios compatible cards, and Tekram DC390W/U/F cards. Useful
- for systems with more than one Symbios compatible controller where
- at least one has a serial NVRAM, or for a system with a mixture of
- Symbios and Tekram cards. Enables setting the boot order of host
- adaptors to something other than the default order or "reverse
- probe" order. Also enables Symbios and Tekram cards to be
- distinguished so CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT may be set in
- a system with a mixture of Symbios and Tekram cards so the Symbios
- cards can make use of the full range of Symbios features,
- differential, led pin, without causing problems for the Tekram
- card(s).
- (added by Richard Waltham: dorm...@farsrobt.demon.co.uk)
- Also enables setting host and targets SCSI features as defined in
- the user setup for each host using a serial NVRAM (added by the
- maintainer).
- The default answer is N, the normal answer should be Y.
- Read drivers/scsi/README.ncr53c8xx for more information.
+ that can be queued to any device, when tagged command queuing is
+ possible. The default value is 32. Minimum is 2, maximum is 64.
+ Modern hard disks are able to support 64 tags and even more, but
+ donnot seem to be faster when more than 32 tags are being used.
+ So, the normal answer here is to go with the default value 32 unless
+ you are using very large hard disks with large cache (>= 1 MB) that
+ are able to take advantage of more than 32 tagged commands.
+ There is no safe option and the default answer is recommended.
X
X Assume boards are SYMBIOS compatible
X CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT
X This option allows you to enable some features depending on GPIO
- wiring. These General Purpose Input/Output pins can be used for
+ wiring. These General Purpose Input/Output pins can be used for
X vendor specific features or implementation of the standard SYMBIOS
- features. Genuine SYMBIOS boards use GPIO0 in output for controller
- LED and GPIO3 bit as a flag indicating singled-ended/differential
- interface.
- If all the boards of your system are genuine SYMBIOS boards or use
- BIOS and drivers from SYMBIOS, you would want to enable this option.
- The driver behaves correctly on my system with this option enabled.
- (SDMS 4.0 + Promise SCSI ULTRA 875 rev 0x3 + ASUS SC200 810A rev
- 0x12). This option must be set to N if your system has at least one
- 53C8XX based SCSI board with a vendor-specific BIOS (example: Tekram
- DC-390/U/W/F). If unsure, say N.
- However, if all your non Symbios compatible boards have NVRAM,
- setting option CONFIG_SCSI_NCR53C8XX_NVRAM_DETECT allows the driver
- to distinguish Symbios compatible boards from other ones. So,
- you can answer Y if all non Symbios compatible boards have NVRAM.
+ features. Genuine SYMBIOS controllers use GPIO0 in output for
+ controller LED and GPIO3 bit as a flag indicating
+ singled-ended/differential interface. The Tekram DC-390U/F boards
+ uses a different GPIO wiring.
+ Your answer to this question is ignored if all your controllers have
+ NVRAM, since the driver is able to detect the board type from the
+ NVRAM format.
+ If all the controllers in your system are genuine SYMBIOS boards or
+ use BIOS and drivers from SYMBIOS, you would want to say Y here,
+ otherwise N. N is the safe answer.
+
+Enable profiling statistics gathering
+CONFIG_SCSI_NCR53C8XX_PROFILE
+ This option allows you to enable profiling information gathering.
+ These statistics are not very accurate due to the low frequency
+ of the kernel clock (100 Hz on i386) and have performance impact
+ on systems that use very fast devices.
+ The normal answer therefore is N.
X
X Always IN2000 SCSI support
X CONFIG_SCSI_IN2000
@@ -2055,21 +2223,59 @@
X and removed from the running kernel whenever you want), say M here
X and read Documentation/modules.txt.
X
-Tekram DC390(T) (AMD PCscsi) SCSI support
+Tekram DC390(T) and Am53/79C974 (PCscsi) SCSI support
X CONFIG_SCSI_DC390T
- This driver supports the Tekram DC390(T) PCI SCSI Hostadapter with
- the Am53C974A chip, and perhaps other cards using the same chip.
- This driver does _not_ support the DC390W/U/F adaptor with the
- NCR/Symbios chips.
+ This driver supports PCI SCSI host adapters based on the Am53C974A
+ chip, e.g. Tekram DC390(T), DawiControl 2974 and some onboard
+ PCscsi/PCnet (Am53/79C974) solutions.
+ Documentation can be found in linux/drivers/scsi/README.tmscsim.
+ Note that this driver does NOT support Tekram DC390W/U/F, which are
+ based on NCR/Symbios chips. Use the NCR53C8XX driver for those.
+ Also note, that there is another generic Am53C974 driver.
+ If you want to compile this driver as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want),
+ say M here and read Documentation/modules.txt. The module will be
+ called tmscsim.o.
+
+Skip support for other Am53/79C974 based SCSI adapters
+CONFIG_SCSI_DC390T_NOGENSUPP
+ Normally, the DC390(T) SCSI driver relies on the DC390 EEPROM to get
+ initial values for its settings, such as speed, termination, etc.
+ If it can't find this EEPROM, it will use defaults or the user
+ supplied boot/module parameters. For details on driver configuration
+ see linux/drivers/scsi/README.tmscsim.
+ With this option set, if no EEPROM is found, the driver gives up and
+ thus only supports Tekram DC390(T) adapters. This can be useful if
+ you have a DC390(T) and another Am53C974 based adapter, which, for
+ some reason, you want to drive with the other AM53C974 driver.
+ If unsure, say N.
+
+Symbios Logic sym53c416 support
+CONFIG_SCSI_SYM53C416
+ This is support for the sym53c416 SCSI host adapter. This is the
+ SCSI adapter that comes with some hp scanners. This driver requires that
+ the sym53c416 is configured first using some sort of pnp configuration
+ program (e.g. isapnp). After doing so it should be loaded as a module
+ using insmod. The parameters of the configured card(s) should be passed
+ to the driver. The format is:
+
+ insmod sym53c416 sym53c416=<base>,<irq> [sym53c416_1=<base>,<irq>]
+
+ There is support for up to four adapters. If you want to compile this
+ driver as a module ( = code which can be inserted in and removed from
+ the running kernel whenever you want), say M here and read
+ Documentation/modules.txt.
X
X AM53/79C974 PCI SCSI support
X CONFIG_SCSI_AM53C974
X This is support for the AM53/79C974 SCSI host adapters. Please read
X drivers/scsi/README.AM53C974 for details. Also, the SCSI-HOWTO,
X available via FTP (user: anonymous) at
- sunsite.unc.edu:/pub/Linux/docs/HOWTO, is for you.
- Use the native DC390 driver if you've got a Tekram DC390(T) PCI-SCSI
- host adapter.
+ ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO, is for you.
+ Note that there is another driver for AM53C974 based adapters: The
+ Tekram DC390(T) driver.
+ If you want to compile this driver as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want),
X
X GDT SCSI Disk Array Controller support
X CONFIG_SCSI_GDTH
@@ -2106,6 +2312,17 @@
X Winbond xxx837
X National Semiconductor PC87306 (early revisions)
X
+Initio INI-A100U2W SCSI support
+CONFIG_SCSI_INIA100
+ This is support for the Initio INI-A100U2W SCSI host adapter.
+ Please read the SCSI-HOWTO, available via FTP (user anonymous) at
+ ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
+
+ If you want to compile this as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want),
+ say M here and read Documenation/modules.txt. The module will be
+ called a100u2w.o
+
X Network device support?
X CONFIG_NETDEVICES
X You can say N here in case you don't intend to connect to any other
@@ -3840,15 +4057,61 @@
X NCP filesystem support (to mount NetWare volumes)
X CONFIG_NCP_FS
X NCP (NetWare Core Protocol) is a protocol that runs over IPX and is
- used by Novel NetWare clients to talk to file servers. It is to IPX
- what NFS is to TCP/IP, if that helps. Enabling this option allows
- you to mount NetWare file server volumes and to access them just
- like any other Unix directory. For details, please read the file
+ used by Novell NetWare clients to talk to file servers. It is to IPX
+ what NFS is to TCP/IP, if that helps. Saying Y here allows you to
+ mount NetWare file server volumes and to access them just like any
+ other Unix directory. For details, please read the file
X Documentation/filesystems/ncpfs.txt in the kernel source and the
- IPX-HOWTO on sunsite.unc.edu:/pub/Linux/docs/howto. If you want to
- compile this as a module ( = code which can be inserted in and
- removed from the running kernel whenever you want), say M here and
- read Documentation/modules.txt.
+ IPX-HOWTO on ftp://sunsite.unc.edu:/pub/Linux/docs/howto.
+ You do not have to say Y here if you want your Linux box to act as a
+ file *server* for Novell NetWare clients.
+ General information about how to connect Linux, Windows machines and
+ Macs is on the WWW at http://www.eats.com/linux_mac_win.html (to
+ browse the WWW, you need to have access to a machine on the Internet
+ that has a program like lynx or netscape).
+ If you want to compile this as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want),
+ say M here and read Documentation/modules.txt. The module will be
+ called ncpfs.o. Say N unless you are connected to a Novell network.
+
+Packet signatures
+CONFIG_NCPFS_PACKET_SIGNING
+ NCP allows packets to be signed for stronger security. If you want
+ security, say Y. Normal users can leave it off. To be able to use
+ packet signing you must use ncpfs > 2.0.12.
+
+Proprietary file locking
+CONFIG_NCPFS_IOCTL_LOCKING
+ Allows locking of records on remote volumes. Say N unless you have
+ special applications which are able to utilize this locking scheme.
+
+Clear remove/delete inhibit when needed
+CONFIG_NCPFS_STRONG
+ Allows manipulation of files flagged as Delete or Rename Inhibit. To
+ use this feature you must mount volumes with the ncpmount parameter
+ "-s" (ncpfs-2.0.12 and newer). Say Y unless you are not mounting
+ volumes with -f 444.
+
+Use NFS namespace when available
+CONFIG_NCPFS_NFS_NS
+ Allows you to utilize NFS namespace on NetWare servers. It brings
+ you case sensitive filenames. Say Y. You can disable it at
+ mount-time with the `-N nfs' parameter of ncpmount.
+
+Use OS2/LONG namespace when available
+CONFIG_NCPFS_OS2_NS
+ Allows you to utilize OS2/LONG namespace on NetWare servers.
+ Filenames in this namespace are limited to 255 characters, they are
+ case insensitive, and case in names is preserved. Say Y. You can
+ disable it at mount time with the -N os2 parameter of ncpmount.
+
+Allow mounting of volume subdirectories
+CONFIG_NCPFS_MOUNT_SUBDIR
+ Allows you to mount not only whole servers or whole volumes, but
+ also subdirectories from a volume. It can be used to reexport data
+ and so on. There is no reason to say N, so Y is recommended unless
+ you count every byte.
+ To utilize this feature you must use ncpfs-2.0.12 or newer.
X
X Amiga FFS filesystem support (EXPERIMENTAL)
X CONFIG_AFFS_FS
@@ -4693,6 +4956,16 @@
X registers in the chips up correctly as the specification and Intel
X rules require. If you have a PPro or later SMP and one or more CPU's
X report a value of about 2-3 bogomips enable this.
+
+Nemory configuration
+CONFIG_MEM_STD
+ There are three memory configurations available. The standard
+ configuration allows use of just under 1GB of RAM with 3GB of
+ virtual space per process. The enterprise configuration allows
+ 2Gigabytes of physical memory but limits the per process address
+ space to 2Gigabytes. The custom option allows you to specify the
+ split subject to kernel constraints. If you don't know how it works
+ don't pick it.
X
X # need an empty line after last entry, for sed script in Configure.
X
diff -u --recursive --new-file v2.0.36/linux/Documentation/README.DAC960 linux/Documentation/README.DAC960
--- v2.0.36/linux/Documentation/README.DAC960 Wed Dec 31 16:00:00 1969
+++ linux/Documentation/README.DAC960 Sun Jun 13 10:20:59 1999
@@ -0,0 +1,222 @@
+ Mylex DAC960 PCI RAID Controller Driver for Linux
+
+ Version 2.0.0 for Linux 2.0.36
+ Version 2.1.0 for Linux 2.1.130
+
+ BETA TEST RELEASE 3
+
+ 23 November 1998
+
+ Leonard N. Zubkoff
+ Dandelion Digital
+ l...@dandelion.com
+
+ Copyright 1998 by Leonard N. Zubkoff <l...@dandelion.com>
+
+
+ INTRODUCTION
+
+Mylex, Inc. designs and manufactures a variety of high performance PCI RAID
+controllers based on the Intel i960 processor. Mylex Corporation is located at
+34551 Ardenwood Blvd., Fremont, California 94555, USA and can be reached at
+510/796-6100 or on the World Wide Web at http://www.mylex.com. Mylex RAID
+Technical Support can be reached by electronic mail at sup...@mylex.com, by
+Voice at 510/608-2400, or by FAX at 510/745-7715. Contact information for
+offices in Europe and Japan is available on the Web site.
+
+The latest information on Linux support for DAC960 PCI RAID Controllers, as
+well as the most recent release of this driver, will always be available from
+my Linux Home Page at URL "http://www.dandelion.com/Linux/".
+
+Bug reports should be sent via electronic mail to "l...@dandelion.com". Please
+include with the bug report the complete configuration messages reported by the
+driver at startup, along with any subsequent system messages relevant to the
+controller's operation, and a detailed description of your system's hardware
+configuration.
+
+Please consult the DAC960 documentation for detailed information regarding
+installation and configuration of the controllers. This document primarily
+provides information specific to the Linux DAC960 support.
+
+
+ DRIVER FEATURES
+
+The DAC960 is supported solely as a high performance RAID controller, not as an
+interface to arbitrary SCSI devices. The Linux DAC960 driver operates at the
+block device level, the same level as the SCSI and IDE drivers. Unlike other
+RAID controllers currently supported on Linux, the DAC960 driver is not
+dependent on the SCSI subsystem, and hence avoids all the complexity and
+unnecessary code that would be associated with an implementation as a SCSI
+driver. The DAC960 driver is designed for as high a performance as possible
+with no compromises or extra code for compatibility with lower performance
+devices.
+
+The DAC960 driver is architected to support up to 8 controllers per system.
+Each DAC960 controller can support up to 45 disk drives on 3 channels. The
+drives installed on a controller are divided into one or more "Drive Groups",
+and then each Drive Group is subdivided further into 1 to 32 "Logical Drives".
+Each Logical Drive has a specific RAID Level and caching policy associated with
+it, and it appears to Linux as a single block device. Logical Drives are
+further subdivided into up to 7 partitions through the normal Linux and PC disk
+partitioning schemes. Logical Drives are also known as "System Drives", and
+Drive Groups are also called "Packs". Both terms are in use in the Mylex
+documentation; I have chosen to standardize on the more generic "Logical Drive"
+and "Drive Group".
+
+DAC960 RAID disk devices are named in the style of the Device File System
+(DEVFS). The device corresponding to Logical Drive D on Controller C is
+referred to as /dev/rd/cCdD, and the partitions are called /dev/rd/cCdDp1
+through /dev/rd/cCdDp7. For example, partition 3 of Logical Drive 5 on
+Controller 2 is referred to as /dev/rd/c2d5p3. Note that unlike with SCSI
+disks the device names will not change in the event of a disk drive failure.
+The DAC960 driver is assigned major numbers 48 - 55 with one major number per
+controller. The 8 bits of minor number are divided into 5 bits for the Logical
+Drive and 3 bits for the partition.
+
+
+ SUPPORTED DAC960 PCI RAID CONTROLLERS
+
+The following list comprises the supported DAC960 PCI RAID Controllers as of
+the date of this document. It is recommended that anyone purchasing a Mylex
+PCI RAID Controller not in the following table contact the author beforehand to
+verify that it is or will be supported.
+
+AcceleRAID 250 (DAC960PTL-1)
+ Uses onboard Symbios SCSI chips on certain motherboards
+ Also includes one onboard Wide Ultra-2/LVD SCSI channel
+ 66MHz Intel i960RD RISC Processor
+ 4MB/8MB/16MB/32MB/64MB/128MB ECC EDO Memory
+
+AcceleRAID 200 (DAC960PTL-0)
+ Uses onboard Symbios SCSI chips on certain motherboards
+ Includes no onboard SCSI channels
+ 66MHz Intel i960RD RISC Processor
+ 4MB/8MB/16MB/32MB/64MB/128MB ECC EDO Memory
+
+DAC960PJ 1/2/3 Wide Ultra SCSI-3 Channels
+ 66MHz Intel i960RD RISC Processor
+ 4MB/8MB/16MB/32MB/64MB/128MB ECC EDO Memory
+
+DAC960PG 1/2/3 Wide Ultra SCSI-3 Channels
+ 33MHz Intel i960RP RISC Processor
+ 4MB/8MB ECC EDO Memory
+
+DAC960PU 1/2/3 Wide Ultra SCSI-3 Channels
+ Intel i960CF RISC Processor
+ 2MB/4MB/8MB/16MB/32MB EDRAM or DRAM Memory (max 8MB EDRAM)
+
+DAC960PD 1/2/3 Wide Fast SCSI-2 Channels
+ Intel i960CF RISC Processor
+ 2MB/4MB/8MB/16MB/32MB EDRAM or DRAM Memory (max 8MB EDRAM)
+
+DAC960PL 1/2/3 Wide Fast SCSI-2 Channels
+ Intel i960 RISC Processor
+ 2MB/4MB/8MB/16MB/32MB DRAM Memory
+
+For the DAC960PJ and DAC960PG, firmware version 4.06-0-00 or above is required.
+This firmware version is available from http://www.dandelion.com/Linux/ and
+will eventually be available from http://www.mylex.com as well. It has been
+released by Mylex and is provided with new controllers, but it has not yet
+appeared on their support web pages as of the date of this document.
+
+For the DAC960PU, DAC960PD, and DAC960PL, firmware version 3.51-0-04 or above
+required. This firmware version is available from http://www.mylex.com.
+
+Note that earlier revisions of the DAC960PU, DAC960PD, and DAC960PL controllers
+were delivered with version 2.xx firmware. Version 2.xx firmware is not
+supported by this driver and no support is envisioned. Contact Mylex RAID
+Technical Support to inquire about upgrading controllers with version 2.xx
+firmware to version 3.51-0-04. Upgrading to version 3.xx firmware requires
+installation of higher capacity Flash ROM chips, and not all DAC960PD and
+DAC960PL controllers can be upgraded.
+
+Please note that not all SCSI disk drives are suitable for use with DAC960
+controllers, and only particular firmware versions of any given model may
+actually function correctly. Similarly, not all motherboards have a BIOS that
+properly initializes the AcceleRAID 250, AcceleRAID 200, DAC960PJ, and DAC960PG
+because the Intel i960RD/RP is a multi-function device. If in doubt, contact
+Mylex RAID Technical Support (sup...@mylex.com) to verify compatibility.
+
+
+ CONTROLLER CONFIGURATION AND STATUS MONITORING
+
+The DAC960 Online Configuration Utilities are not yet available on Linux but
+will hopefully be supported in the future. The AcceleRAID 250, AcceleRAID 200,
+DAC960PJ, and DAC960PG controllers can generally be configured using the DAC960
+Configuration Utility included in the controller's BIOS ROM and available via
+Alt-R during BIOS initialization. Older DAC960 controllers required the DACCF
+utility that runs from a DOS boot disk.
+
+The status of each DAC960 controller is queried every 7 seconds by the Linux
+driver to verify that no problems have been detected, and any changes in status
+are reported through appropriate kernel messages. The following log excerpt
+details the process of the controller automatically rebuilding onto a spare
+drive when a disk drive failed. In this example, 4 drives in a SAF-TE
+enclosure were grouped into a Drive Group which was then divided into 3 Logical
+Drives configured as RAID-5, RAID-5, and RAID-6. An additional identical drive
+was installed as a "Standby" or "Hot Spare" to provide for automatic
+rebuilding. The first two messages are the result of the standby drive being
+removed, the third message is a result of it being reinstalled, and the
+remaining messages are the result of the first drive being removed to force an
+automatic rebuild.
+
+DAC960#0: Physical Drive 0:4 killed because it was removed
+DAC960#0: Physical Drive 0:4 is now DEAD
+DAC960#0: Physical Drive 0:4 is now STANDBY
+DAC960#0: Logical Drive 0 (/dev/rd/c0d0) is now CRITICAL
+DAC960#0: Logical Drive 1 (/dev/rd/c0d1) is now CRITICAL
+DAC960#0: Logical Drive 2 (/dev/rd/c0d2) is now CRITICAL
+DAC960#0: Physical Drive 0:0 killed because of timeout on SCSI command
+DAC960#0: Physical Drive 0:0 is now DEAD
+DAC960#0: Physical Drive 0:0 killed because it was removed
+DAC960#0: Physical Drive 0:4 is now WRITE-ONLY
+DAC960#0: REBUILD IN PROGRESS: Logical Drive 0 (/dev/rd/c0d0) 9% completed
+DAC960#0: REBUILD IN PROGRESS: Logical Drive 0 (/dev/rd/c0d0) 45% completed
+DAC960#0: REBUILD IN PROGRESS: Logical Drive 0 (/dev/rd/c0d0) 90% completed
+DAC960#0: REBUILD IN PROGRESS: Logical Drive 1 (/dev/rd/c0d1) 28% completed
+DAC960#0: REBUILD IN PROGRESS: Logical Drive 1 (/dev/rd/c0d1) 66% completed
+DAC960#0: REBUILD IN PROGRESS: Logical Drive 2 (/dev/rd/c0d2) 62% completed
+DAC960#0: REBUILD IN PROGRESS: Logical Drive 2 (/dev/rd/c0d2) 82% completed
+DAC960#0: REBUILD COMPLETED SUCCESSFULLY
+DAC960#0: Logical Drive 0 (/dev/rd/c0d0) is now ONLINE
+DAC960#0: Logical Drive 1 (/dev/rd/c0d1) is now ONLINE
+DAC960#0: Logical Drive 2 (/dev/rd/c0d2) is now ONLINE
+DAC960#0: Physical Drive 0:4 is now ONLINE
+
+
+ DRIVER INSTALLATION
+
+This distribution was prepared for Linux kernel version 2.0.36 or 2.1.130.
+
+To install the DAC960 RAID driver, you may use the following commands,
+replacing "/usr/src" with wherever you keep your Linux kernel source tree:
+
+ cd /usr/src
+ tar -xvzf DAC960-2.0.0-Beta3.tar.gz (or DAC960-2.1.0-Beta3.tar.gz)
+ mv README.DAC960 DAC960.[ch] linux/drivers/block
+ patch -p0 < DAC960.patch
+ cd linux
+ make config
+ make depend
+ make zImage (or bzImage)
+
+Then install "arch/i386/boot/zImage" or "arch/i386/boot/bzImage" as your
+standard kernel, run lilo if appropriate, and reboot.
+
+To create the necessary devices in /dev, the "make_rd" script included in
+"DAC960-Utilities.tar.gz" from http://www.dandelion.com/Linux/ may be used.
+Also included in this archive are patches to LILO 20 and FDISK v2.8 that add
+DAC960 support, along with statically linked executables of LILO and FDISK.
+This modified version of LILO will allow booting from a DAC960 controller
+and/or mounting the root file system from a DAC960. Unfortunately, installing
+directly onto a DAC960 will be problematic until the various Linux distribution
+vendors update their installation utilities.
+
+
+ DAC960 ANNOUNCEMENTS MAILING LIST
+
+The DAC960 Announcements Mailing List provides a forum for informing Linux
+users of new driver releases and other announcements regarding Linux support
+for DAC960 PCI RAID Controllers. To join the mailing list, send a message to
+"dac960-anno...@dandelion.com" with the line "subscribe" in the
+message body.
diff -u --recursive --new-file v2.0.36/linux/Documentation/ide.txt linux/Documentation/ide.txt
--- v2.0.36/linux/Documentation/ide.txt Sun Nov 15 10:49:23 1998
+++ linux/Documentation/ide.txt Sun Jun 13 10:20:59 1999
@@ -5,6 +5,9 @@
X Gadi Oxman <ga...@netvision.net.il> -- tapes, disks, whatever
X Scott Snyder <sny...@fnald0.fnal.gov> -- cdroms, ATAPI, audio
X
+UDMA support was added for various chipsets, from kernel 2.0.35 on. Check
+the udma.txt file in this directory for details.
+
X +-----------------------------------------------------------------+
X | The hdparm utility for controlling various IDE features is |
X | packaged separately. Look for it on popular linux FTP sites. |
@@ -483,3 +486,135 @@
X For really high end systems, go for fast/wide 7200rpm SCSI. But it'll cost ya!
X
X ml...@pobox.com
+================================================================================
+
+DMA Bus Master transfer
+-----------------------
+The triton.c driver provides support for the DMA Bus Mastering functions of
+the Intel PCI Triton I/II chipsets (i82371FB or i82371SB).
+
+Pretty much the same code will work for the OPTi "Viper" chipset. Look for
+DMA support for this in linux kernel 2.1.xx, when it appears.
+
+DMA is currently supported only for hard disk drives (not cdroms).
+
+Support for cdroms will likely be added at a later date, after broader
+experience has been obtained with hard disks.
+
+Up to four drives may be enabled for DMA, and the motherboard chipset will
+(hopefully) arbitrate the PCI bus among them. Note that the i82371 chip
+provides a single "line buffer" for the BM IDE function, so performance of
+multiple (two) drives doing DMA simultaneously will suffer somewhat, as they
+contest for that resource bottleneck. This is handled transparently inside
+the i82371 chip.
+
+The SiS 5513 controller has two completely independent IDE controller units,
+each with a 64-byte line buffer (same size as the Intel); there is no
+bottleneck in simultaneous (U)DMA transfers for this resource. The 5513 is
+built-in the SiS 5571, 5598 and 5591 chipsets.
+
+The VIA chipsets like the Intel have a single 64 byte line buffer, but it
+can be split 1/2-1/2 or 1/4-3/4 between both channels.
+
+By default, DMA support is prepared for use, but is currently enabled only
+for drives which support multi-word DMA mode2 (mword2), or which are
+recognized as "good" (see table below). Drives with only mode0 or mode1
+(single or multi) DMA should also work with this chipset/driver (eg.
+MC2112A) but are not enabled by default. Use "hdparm -i" to view modes
+supported by a given drive.
+
+The hdparm-3.3 (patched) utility can be used to manually enable /disable DMA
+support, but must be (re-)compiled against this kernel version or later.
+
+Michel Aubry has produced a patch against hdparm-3.3 to support UDMA.
+
+To enable DMA, use "hdparm -d1 /dev/hd?" on a per-drive basis after booting.
+If problems arise, ide.c will disable DMA operation after a few retries.
+This error recovery mechanism works and has been extremely well exercised.
+
+IDE drives, depending on their vintage, may support several different modes
+of DMA operation. The boot-time modes are indicated with a "*" in the
+"hdparm -I" listing, and can be changed with *knowledgeable* use of the
+"hdparm -X" feature (X32 for DMA 0, X33 for DMA 1, X34 for DMA 2, X64 for
+UDMA 0, X65 for UDMA 1 and X66 for UDMA 2).
+
+Testing was done with an ASUS P55TP4XE/100 system and the following drives:
+
+ Quantum Fireball 1080A (1Gig w/83kB buffer), DMA mode2, PIO mode4.
+ - DMA mode2 works well (7.4MB/sec), despite the tiny on-drive buffer.
+ - This drive also does PIO mode4, at about the same speed as DMA mode2.
+ An awesome drive for the price!
+
+ Fujitsu M1606TA (1Gig w/256kB buffer), DMA mode2, PIO mode4.
+ - DMA mode2 gives horrible performance (1.6MB/sec), despite the good
+ size of the on-drive buffer and a boasted 10ms average access time.
+ - PIO mode4 was better, but peaked at a mere 4.5MB/sec.
+
+ Micropolis MC2112A (1Gig w/508kB buffer), drive pre-dates EIDE and ATA2.
+ - DMA works fine (2.2MB/sec), probably due to the large on-drive buffer.
+ - This older drive can also be tweaked for fastPIO (3.7MB/sec) by using
+ maximum clock settings (5,4) and setting all flags except prefetch.
+
+ Western Digital AC31000H (1Gig w/128kB buffer), DMA mode1, PIO mode3.
+ - DMA does not work reliably. The drive appears to be somewhat tardy
+ in deasserting DMARQ at the end of a sector. This is evident in
+ the observation that WRITEs work most of the time, depending on
+ cache-buffer occupancy, but multi-sector reads seldom work.
+
+Testing was done with a Gigabyte GA-586 ATE system and the following drive:
+(Uwe Bonnes - b...@elektron.ikp.physik.th-darmstadt.de)
+
+ Western Digital AC31600H (1.6Gig w/128kB buffer), DMA mode2, PIO mode4.
+ - much better than its 1Gig cousin, this drive is reported to work
+ very well with DMA (7.3MB/sec).
+
+Other drives:
+
+ Maxtor 7540AV (515Meg w/32kB buffer), DMA modes mword0/sword2, PIO mode3.
+ - a budget drive, with budget performance, around 3MB/sec.
+
+ Western Digital AC2850F (814Meg w/64kB buffer), DMA mode1, PIO mode3.
+ - another "caviar" drive, similar to the AC31000, except that this one
+ worked with DMA in at least one system. Throughput is about 3.8MB/sec
+ for both DMA and PIO.
+
+ Conner CFS850A (812Meg w/64kB buffer), DMA mode2, PIO mode4.
+ - like most Conner models, this drive proves that even a fast interface
+ cannot improve slow media. Both DMA and PIO peak around 3.5MB/sec.
+
+ Maxtor 71260AT (1204Meg w/256kB buffer), DMA mword0/sword2, PIO mode3.
+ - works with DMA, on some systems (but not always on others, eg. Dell),
+ giving 3-4MB/sec performance, about the same as mode3.
+
+ IBM DHEA 36480 (6197Meg w/476kB buffer), DMA mode2, PIO mode4, UDMA mode2
+ - works with DMA and UDMA on systems that support it. This drive and its
+ larger 8.4GB cousin provide throughput of 9.8MB/sec under UDMA.
+
+If you have any drive models to add, email your results to: ml...@pobox.com
+Keep an eye on /var/adm/messages for "DMA disabled" messages.
+
+Some people have reported trouble with Intel Zappa motherboards.
+This can be fixed by upgrading the AMI BIOS to version 1.00.04.BS0,
SHAR_EOF
true || echo 'restore of patch-2.0.37 failed'
fi
echo 'End of part 01'
echo 'File patch-2.0.37 is continued in part 02'
echo 02 > _shar_seq_.tmp
exit 0

Thomas...@ciw.uni-karlsruhe.de

unread,
Jun 16, 1999, 3:00:00 AM6/16/99
to
Archive-name: v2.0/patch-2.0.37/part02

#!/bin/sh
# this is part 02 of a 45 - part archive


# do not concatenate these parts, unpack them in order with /bin/sh

# file patch-2.0.37 continued
if test ! -r _shar_seq_.tmp; then
echo 'Please unpack part 1 first!'
exit 1
fi
(read Scheck
if test "$Scheck" != 02; then
echo Please unpack part "$Scheck" next!
exit 1
else
exit 0
fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.0.37'
else
echo 'x - continuing with patch-2.0.37'


sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.0.37' &&

+available from ftp://ftp.intel.com/pub/bios/10004bs0.exe
+(thanks to Glen Morrell <gl...@spin.Stanford.edu> for researching this).
+
+And, yes, Intel Zappa boards really *do* use the Triton IDE ports.
+
+Changes by Michel Aubry, Andre Hedrick and Andrew D. Balsa, June 1998:
+ a) Added support for non-Intel chipsets that support Bus Mastering DMA.
+ b) Added support for UDMA (33Mb/s) drives and controllers. Note that UDMA
+ support must be enabled in the BIOS, and that both the hard disk drive
+ _and_ the chipset must support UDMA.
+ On the IBM DHEA-36480 drive, transfer rates go from 7.76Mb/s to 9.76Mb/s,
+ a 25% improvement with zero cost (DMA mode2 to UDMA mode2).
+
+Extra UDMA PCI controller card support by Andre M. Hedrick, June 1998:
+ - PDC20246 Promise Ultra33 UDMA.
+ - AEC6210 Artop Electronics Corp. ACARD
+ sold under SIIG CN2449 UltraIDE Pro.
+ - HPT343 Triones Technologies (HighPoint Technologies) Inc.
+ future support -- nonbooting cards, need MNDA approval for
+ information release.
+ sold under Digital Research DRIDEUDMA.
+
+For more information on UDMA support, check /Documentation/udma.txt.
diff -u --recursive --new-file v2.0.36/linux/Documentation/isdn/README linux/Documentation/isdn/README
--- v2.0.36/linux/Documentation/isdn/README Sun Nov 15 21:51:46 1998
+++ linux/Documentation/isdn/README Sun Jun 13 10:20:59 1999
@@ -335,9 +335,9 @@
X "manual" is a dial mode created to prevent the unexpected dialouts.
X In this mode, the interface will never make any connections on its
X own. You must explicitly initiate a connection with "isdnctrl dial
- isdn0". You _must_ also hangup the line explicitly as well! There
- is NO timeout in this mode. Use "isdnctrl hangup isdn0" to end the
- connection.
+ sdn0". However, after an idle time of no traffic as configured for
+ the huptimeout value with isdnctrl, the connection _will_ be ended.
+ If you don't want any automatic hangup, set the huptimeout value to 0.
X "manual" is the default.
X
X j) Setup the interface with ifconfig as usual, and set a route to it.
diff -u --recursive --new-file v2.0.36/linux/Documentation/modules.txt linux/Documentation/modules.txt
--- v2.0.36/linux/Documentation/modules.txt Sun Jun 9 08:01:04 1996
+++ linux/Documentation/modules.txt Tue Dec 29 11:58:25 1998
@@ -22,7 +22,7 @@
X make config
X make dep
X make clean
- make zImage or make zlilo
+ make zImage or make bzImage or make zlilo
X
X In "make config", you select what you want to include in the "resident"
X kernel and what features you want to have available as loadable modules.
diff -u --recursive --new-file v2.0.36/linux/Documentation/more-than-900MB-RAM.txt linux/Documentation/more-than-900MB-RAM.txt
--- v2.0.36/linux/Documentation/more-than-900MB-RAM.txt Wed Dec 31 16:00:00 1969
+++ linux/Documentation/more-than-900MB-RAM.txt Sun Jun 13 10:20:59 1999
@@ -0,0 +1,40 @@
+
+This document describes how to configure the Linux kernel to
+support more than 950MB physical RAM on x86 systems:
+
+you only have to change the 'Max physical memory in MB' kernel
+config option to get everything working. If you have less than
+900M RAM, dont touch the default setting, this option buys you
+nothing at all! The option is in 'General setup':
+
+ [ ] Kernel math emulation
+ (1800) Max physical memory in MB
+ [*] Networking support
+ [ ] Limit memory to low 16MB
+
+the unit of CONFIG_MAX_MEMSIZE is 'megabytes', ie. a value of
+'1024' means '1024 MBytes'. Unless in 2.1 there is no restriction
+on the value of CONFIG_MAX_MEMSIZE!
+
+IMPORTANT: the value of CONFIG_MAX_MEMSIZE should be about 128M
+more than the amount of physical RAM (or 1024 if RAM is less than
+900M), because the kernel needs some space for it's own memory
+mappings. The kernel enforces this 128M window by clipping away
+from the end of phsyical memory if necessary. (in this case that
+chunk of physical memory is not used by Linux!) So configure this
+option carefully, and look at 'free' output and boot messages
+wether all RAM is correctly detected and configured.
+
+A system with 2G physical memory should use a value of ~2400, a
+system with 3.8G memory should use something like 3900. A bit of
+experimentation with the limit wont hurt, the kernel needs a ~128M
+window for vmalloc() plus PCI space uses up some memory too, thus
+physical addresses above FD000000 should rather be kept free.
+
+if the BIOS does not report correct memory size, use the mem= boot
+commandline option to override it.
+
+feel free to report any problems/suggestions to:
+
+ Ingo Molnar <mi...@redhat.com>
+
diff -u --recursive --new-file v2.0.36/linux/Documentation/networking/net-modules.txt linux/Documentation/networking/net-modules.txt
--- v2.0.36/linux/Documentation/networking/net-modules.txt Thu Apr 11 23:49:29 1996
+++ linux/Documentation/networking/net-modules.txt Tue Dec 29 11:58:25 1998
@@ -15,7 +15,7 @@
X the less user needs to know, the better. (There are things that
X driver developer can use, others should not confuse themselves.)
X
- In many cases it is highly preferred that insmod:ing is done
+ In many cases it is highly preferred that insmoding is done
X ONLY with defining an explicit address for the card, AND BY
X NOT USING AUTO-PROBING!
X
diff -u --recursive --new-file v2.0.36/linux/Documentation/paride.txt linux/Documentation/paride.txt
--- v2.0.36/linux/Documentation/paride.txt Sun Nov 15 21:51:46 1998
+++ linux/Documentation/paride.txt Sun Jun 13 10:20:59 1999
@@ -64,6 +64,7 @@
X SyQuest EZ-135, EZ-230 & SparQ drives
X Avatar Shark
X Imation Superdisk LS-120
+ Maxell Superdisk LS-120
X FreeCom Power CD
X Hewlett-Packard 5GB and 8GB tape drives
X Hewlett-Packard 7100 and 7200 CD-RW drives
@@ -98,6 +99,7 @@
X epia Shuttle EPIA (UK)
X fit2 FIT TD-2000 (US)
X fit3 FIT TD-3000 (US)
+ friq Freecom IQ cable (DE)
X frpw Freecom Power (DE)
X kbic KingByte KBIC-951A and KBIC-971A (TW)
X ktti KT Technology PHd adapter (SG)
@@ -133,10 +135,12 @@
X MicroSolutions 8000t tape pt bpck
X SyQuest EZ, SparQ pd epat
X Imation Superdisk pf epat
+ Maxell Superdisk pf friq
X Avatar Shark pd epat
X FreeCom CD-ROM pcd frpw
X Hewlett-Packard 5GB Tape pt epat
- Hewlett-Packard 7100/7200 pg epat
+ Hewlett-Packard 7200e (CD) pcd epat
+ Hewlett-Packard 7200e (CD-R) pg epat
X
X 2.1 Configuring built-in drivers
X
@@ -315,7 +319,6 @@
X partitioned. Consequently, the pf driver does not support partitioned
X media. This may be changed in a future version of the driver.
X
-
X 2.5 Using the pt driver
X
X The pt driver for parallel port ATAPI tape drives is a minimal driver.
@@ -323,27 +326,29 @@
X For best performance, a block size of 32KB should be used. You will
X probably want to set the parallel port delay to 0, if you can.
X
-
X 2.6 Using the pg driver
X
X The pg driver can be used in conjunction with the cdrecord program
-to create CD-ROMs. Please get cdrecord version 1.6.1a3 or later
-from ftp://ftp.fokus.gmd.de/pub/unix/cdrecord/ (you may have to look
-in the alpha subdirectory). To record CD-R media your parallel port
-should ideally be set to EPP mode, and the "port delay" should be
-set to 0. With those settings it is possible to record at 2x speed
-without any buffer underruns. If you cannot get the driver to work
+to create CD-ROMs. Please get cdrecord version 1.6.1 or later
+from ftp://ftp.fokus.gmd.de/pub/unix/cdrecord/ . To record CD-R media
+your parallel port should ideally be set to EPP mode, and the "port delay"
+should be set to 0. With those settings it is possible to record at 2x
+speed without any buffer underruns. If you cannot get the driver to work
X in EPP mode, try to use "bidirectional" or "PS/2" mode and 1x speeds only.
X
X
X 3. Troubleshooting
X
+3.1 Use EPP mode if you can
+
X The most common problems that people report with the PARIDE drivers
X concern the parallel port CMOS settings. At this time, none of the
X PARIDE protocol modules support ECP mode, or any ECP combination modes.
X If you are able to do so, please set your parallel port into EPP mode
X using your CMOS setup procedure.
X
+3.2 Check the port delay
+
X Some parallel ports cannot reliably transfer data at full speed. To
X offset the errors, the PARIDE protocol modules introduce a "port
X delay" between each access to the i/o ports. Each protocol sets
@@ -357,6 +362,25 @@
X read the comments at the beginning of the driver source files in
X linux/drivers/block/paride.
X
+3.3 Some drives need a printer reset
+
+There appear to be a number of "noname" external drives on the market
+that do not always power up correctly. We have noticed this with some
+drives based on OnSpec and older Freecom adapters. In these rare cases,
+the adapter can often be reinitialised by issuing a "printer reset" on
+the parallel port. As the reset operation is potentially disruptive in
+multiple device environments, the PARIDE drivers will not do it
+automatically. You can however, force a printer reset by doing:
+
+ insmod lp
+ rmmod lp
+
+If you have one of these marginal cases, you should probably build
+your paride drivers as modules, and arrange to do the printer reset
+before loading the PARIDE drivers.
+
+3.4 Use the verbose option and dmesg if you need help
+
X While a lot of testing has gone into these drivers to make them work
X as smoothly as possible, problems will arise. If you do have problems,
X please check all the obvious things first: does the drive work in
@@ -383,6 +407,8 @@
X of two ways. Either send it directly to the author of the PARIDE suite,
X by e-mail to gr...@torque.net, or join the linux-parport mailing list
X and post your report there.
+
+3.5 For more information or help
X
X You can join the linux-parport mailing list by sending a mail message
X to
diff -u --recursive --new-file v2.0.36/linux/Documentation/udma.txt linux/Documentation/udma.txt
--- v2.0.36/linux/Documentation/udma.txt Wed Dec 31 16:00:00 1969
+++ linux/Documentation/udma.txt Sun Jun 13 10:20:59 1999
@@ -0,0 +1,663 @@
+UDMA information for kernels 2.0.35+
+
+Version 0.4 - July 98
+by Andrew D. Balsa <andre...@altern.org>
+
+If you are in a hurry, skip to the "How does one use UDMA support?" section.
+
+If you need troubleshooting advice, check the "Unreliable drive +
+motherboard + driver combination" section.
+
+Support for UDMA is based on previous work by Kim-Hoe Pang and Christian
+Brunner, posted on the Linux Kernel mailing list around September 1997.
+Additional code was provided by Michel Aubry (VIA support) and Andre Hedrick
+(support for various PCI UDMA controller cards). The code base is Mark
+Lord's triton.c driver.
+
+Check the Linux UDMA mini-HOWTO by Brion Vibber first! It is the only Linux
+specific document available on the subject.
+
+Technical references:
+a) The Intel 82371AB data sheet, available in PDF format.
+b) The SiS 5598 and 5591 data sheets, available in Microsoft Word format. :(
+c) The VIA 82C586, 82C586A and 82C586B data sheets, in PDF format.
+d) Small Form Factor document SFF 8038I v1.0. This is the original document
+ that describes the DMA mode 2 protocol. Available in PDF format.
+e) The ATA/ATAPI-4 Working Draft, revision 17. This is document
+ d1153r17.pdf (in PDF format), available from the main IDE technical
+ reference site, ftp://fission.dt.wdc.com/pub/standards. This draft
+ describes the Ultra DMA protocol and timings.
+
+A somewhat less technical, but still very informative document is the
+Enhanced IDE/Fast-ATA/ATA-2 FAQ, by John Wehman and Peter den Haan. Check
+the Web page at http://come.to/eide.
+
+**************************************************************************
+
+Files changed
+-------------
+
+Here is the set of files from Linux kernels 2.0.32/2.0.34 modified to enable
+UDMA transfers on motherboard chipsets that support it. For each file, there
+is a small explanation of the changes.
+
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+The following changes do not affect performance or stability of the IDE
+driver in any way.
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+/drivers/block/triton.c
+
+ - removed some Intel specific timing stuff. This should not affect
+driver operation or performance. This is the only file that is heavily
+modified; the Promise and Artop code is by Andre Hedrick, the VIA code
+by Michel Aubry.
+
+/drivers/block/ide.c
+
+ - added UDMA drive reporting during driver initialization, at the end
+of routine do_identify (single line mod).
+
+ - added data for SiS 5513 and VIA VP-1 chipset in routine probe_for_hwifs
+(single line mods). Each new UDMA capable chipset will have to be added to
+this list (a single line is needed each time). Notice that you don't even
+need the motherboard chipset's data sheets to find the needed information.
+You just have to identify the IDE controller. You can do this by checking
+/proc/pci, and then comparing the IDE controller signature with that
+available from the Linux kernel.
+
+As it stands in this patched version, routine probe_for_hwifs supports the
+following chipsets: Intel FX, HX, VX, TX, LX and SiS 5513 (which is
+integrated in the SiS 5571, 5598 and 5591 chips). The VIA-VP1
+chipset is supported for DMA mode 2 transfers, but compatibility has not
+been tested with this driver. The VIA MVP-3 is reported OK with UDMA.
+
+/drivers/block/ide.h
+
+ - added flag using_udma in struct ide_drive_s (single line mod).
+
+Small changes to the tape and ide-floppy code, and additions to pci.h and
+pci.c for the extra PCI UDMA controller devices.
+
+
+Tested configurations
+---------------------
+
+UDMA support has been thoroughly tested on the following configurations:
+
+Intel TX motherboard, PCI bus at 33 and 37.5MHz. (ASUS TX-97E)
+
+SiS 5598 motherboards, PCI bus at 33 and 37.5MHz. (Chaintech P5-SDA; ASUS
+SP-97V at 33MHz only)
+
+IBM DeskStar 6.4Gb and 8.4Gb drives. Samsung UDMA hard disk proved
+unreliable under Linux _and_ Windows95 (so it was not a driver problem).
+Other UDMA drives not tested.
+
+libc5 and gcc2.7.2. Also tested under libc6 (RedHat 5.0).
+
+6x86MX processor running at 166MHz or 187.5MHz.
+
+DANGER: EIDE drives do not accept a PCI bus at 41.5MHz (83MHz / 2). Trying
+to run DMA Mode 2 or UDMA at these PCI bus clocks will result in crashes and
+loss of data. If your FSB runs at > 75MHz you MUST set the PCI bus for
+asynchronous 33MHz operation. YOU HAVE BEEN WARNED.
+
+Andre Hedrick Tests [IMPORTANT: those are SMP configurations]
+-------------------------------------------------------------
+
+Test I
+------
+
+Tyan Tomcat III bios v4.01 SMP Dual P5 200 w/ Artop AEC6210 w/ DMA2 drives
+
+Intel MultiProcessor Specification v1.4
+ Virtual Wire compatibility mode.
+OEM ID: OEM00000 Product ID: PROD00000000 APIC at: 0xFEE00000
+Processor #0 Pentium(tm) APIC version 17
+Processor #1 Pentium(tm) APIC version 17
+I/O APIC #2 Version 17 at 0xFEC00000.
+Processors: 2
+
+Linux version 2.0.34 (root@Zosma) (gcc version 2.8.1) #1 Mon Jun 8 16:40:25 CDT
+Booting processor 1 stack 00002000: Calibrating delay loop.. ok - 79.67
+BogoMIPSTotal of 2 processors activated (159.33 BogoMIPS).
+Starting kswapd v 1.4.2.2
+
+ide: DMA Bus Mastering IDE controller on PCI bus 0 function 57
+ide: ports are not enabled (BIOS)
+ide: AEC6210 ROM enabled but no address
+ide: UDMA Bus Mastering IDE controller on PCI bus 0 function 160
+ide: timings == 04010401
+ ide0: BM-DMA at 0x6700-0x6707
+ ide1: BM-DMA at 0x6708-0x670f
+hda: Maxtor 72004 AP, 1916MB w/128kB Cache, CHS=973/64/63, DMA
+hdb: Maxtor 71626 A, 1554MB w/64kB Cache, CHS=789/64/63, DMA
+hdc: IOMEGA ZIP 100 ATAPI, ATAPI FLOPPY drive
+hdd: HP COLORADO 5GB, ATAPI TAPE drive
+ide-tape: Sorry, DRQ types other than Accelerated DRQ
+ide-tape: are still not supported by the driver
+ide-tape: the tape is not supported by this version of the driver
+ide2: ports already in use, skipping probe
+ide0 at 0x6300-0x6307,0x6402 on irq 11
+ide1 at 0x6500-0x6507,0x6602 on irq 11 (shared with ide0)
+scsi0 : ncr53c8xx - revision 2.5f.1
+
+Test II
+-------
+
+SuperMicro P6DNF SMP Dual P6 233 w/ Artop AEC6210 and Promise Ultra33
+
+Intel MultiProcessor Specification v1.4
+ Virtual Wire compatibility mode.
+OEM ID: INTEL Product ID: 440FX APIC at: 0xFEE00000
+Processor #0 Pentium(tm) Pro APIC version 17
+Processor #1 Pentium(tm) Pro APIC version 17
+I/O APIC #2 Version 17 at 0xFEC00000.
+Processors: 2
+
+Linux version 2.0.34 (root@Orion) (gcc version 2.8.1) #1 Wed Jun 17 01:13:15 CDT 1998
+Booting processor 1 stack 00002000: Calibrating delay loop.. ok - 232.65 BogoMIPS
+Total of 2 processors activated (464.49 BogoMIPS).
+
+ide: Intel 82371 (single FIFO) DMA Bus Mastering IDE
+ Controller on PCI bus 0 function 57
+ide: ports are not enabled (BIOS)
+ide: AEC6210 ROM enabled at 0xfebf8000
+ide: PCI UDMA Bus Mastering IDE
+ Controller on PCI bus 0 function 160
+ide: timings == 04010401
+ ide0: BM-DMA at 0xef90-0xef97
+ ide1: BM-DMA at 0xef98-0xef9f
+hda: QUANTUM FIREBALL ST3.2A, 3079MB w/81kB Cache, CHS=782/128/63, UDMA
+hdb: QUANTUM FIREBALL ST6.4A, 6149MB w/81kB Cache, CHS=784/255/63, UDMA
+hdc: IOMEGA ZIP 100 ATAPI, ATAPI FLOPPY drive
+hdd: CD-ROM CDU611, ATAPI CDROM drive
+ide2: ports already in use, skipping probe
+ide0 at 0xeff0-0xeff7,0xefe6 on irq 10
+ide1 at 0xefa8-0xefaf,0xefe2 on irq 10 (shared with ide0)
+
+Test III
+--------
+
+Same kernel above but with Promise Ultra33
+
+ide: Intel 82371 (single FIFO) DMA Bus Mastering IDE
+ Controller on PCI bus 0 function 57
+ide: ports are not enabled (BIOS)
+ide: PDC20246 ROM enabled at 0xfebd0000
+ide: PCI UDMA Bus Mastering IDE
+ Controller on PCI bus 0 function 160
+ide: timings == 000003ee
+ ide0: BM-DMA at 0xef80-0xef87
+ ide1: BM-DMA at 0xef88-0xef8f
+hda: QUANTUM FIREBALL ST3.2A, 3079MB w/81kB Cache, CHS=782/128/63, UDMA
+hdb: QUANTUM FIREBALL ST6.4A, 6149MB w/81kB Cache, CHS=784/255/63, UDMA
+hdc: IOMEGA ZIP 100 ATAPI, ATAPI FLOPPY drive
+hdd: CD-ROM CDU611, ATAPI CDROM drive
+ide2: ports already in use, skipping probe
+ide0 at 0xeff0-0xeff7,0xefe6 on irq 10
+ide1 at 0xefa8-0xefaf,0xebe6 on irq 10 (shared with ide0)
+
+All tests cases yield this problem, IOMEGA ZIP 100 ATAPI FW 23.D
+I have a patch fix for 2.1.99->106 similar for FW 21.D drives.
+
+ide-floppy: hdc: I/O error, pc = 5a, key = 5, asc = 24, ascq = 0
+ide-floppy: Can't get drive capabilities
+
+Note that both AEC6210 and PDC20246 have onboard bios that auto-config.
+
+
+What UDMA support does
+----------------------
+
+ - It enables UDMA transfers on the Intel TX chipset.
+ - It enables DMA mode2 transfers on the SiS 5571 and VIA VP-1
+ (82C586) chipsets.
+ - It enables DMA mode2 and UDMA mode2 transfers on the SiS 5598 and
+ SiS 5591 chipsets, and the VIA VP3 and MVP-3.
+ - With single line mods for each new chipset, it will support any DMA
+ mode2 and/or UDMA capable chipset compatible with document
+ SFF 8038I v1.0.
+ - Supports a variety of PCI UDMA controller cards.
+
+
+Support for other chipsets
+--------------------------
+
+It is relatively easy to add support for other chipsets. Some chipsets are
+entirely integrated (e.g. the SiS 5598 chipset has various devices in a
+single chip), others are divided into a Northbridge (CPU to PCI circuitry,
+L2 cache control, etc) and Southbridge (PCI to IDE bus mastering interface,
+USB, etc). We are dealing here with the Southbridge, specifically with the
+IDE bus master PCI device. If the data sheet says the device is SFF 8038I
+v1.0 compatible, then the registers have a more or less standard layout and
+this driver should work with the below changes:
+
+1) Check that the chipset is correctly identified by /proc/pci. Search for
+the line that identifies a bus-mastering IDE controller device.
+
+2) If the chipset is not correctly identified (new chipsets are not in
+kernels up to 2.0.33), you will need to edit /include/linux/pci.h and
+/drivers/pci/pci.c. This is actually quite easy, requiring a single line in
+each of these files.
+
+3) Now add a single line to ide.c, in routine probe_for_hwifs.
+
+4) Test and report results; when troubleshooting, please check first that
+you have the latest BIOS for your motherboard.
+
+
+HOW does UDMA mode2 work?
+-------------------------
+
+Well, actually, the excellent triton.c driver written by Mark Lord is a
+generic DMA transfer hard disk driver. It does not depend on any chipset
+feature or transfer mode (i.e. it will work with DMA mode 2, UDMA and other
+future DMA modes with little or no changes). BTW in late 2.1.x kernels the
+driver was renamed ide-dma.c, to indicate that it is independent of the
+chipset used.
+
+(Note: triton is the "old" name for the Intel FX chipset, for which Mark
+Lord wrote the driver initially.)
+
+The Intel chipset specific parts were slightly changed in the triton.c
+driver. These are only used to gather information for driver testing, and
+actually do not affect the operation or performance of the driver, so the
+changes are (well, should be) relatively inocuous.
+
+The real work involved in setting up the chips for DMA transfers is done
+mostly by the BIOS of each motherboard. Now of course one hopes that the
+BIOS has been correctly programmed...
+
+For example, the ASUS SP-97V motherboard with its original BIOS (Rev. 1.03)
+would malfunction with the modified Linux driver in both DMA mode 2 and UDMA
+modes; it would work well using PIO mode 4, or under Windows 95 in all
+modes. I downloaded the latest BIOS image (Rev. 1.06) from the ASUS Web site
+and flashed the BIOS EPROM with the latest BIOS revision. It has been
+working perfectly ever since (at 66 MHz bus speeds).
+
+What this tells us is that the BIOS sets up the DMA controller with specific
+timing parameters (active pulse and recovery clock cycles). My initial BIOS
+revision probably had bad timings. Since the Windows 95 driver sets up those
+timings by itself (i.e. it does not depend on the BIOS to setup the hard
+disk controller timing parameters), I initially had problems only with the
+Linux driver, while Windows 95 worked well.
+
+So, let me state this again: this Linux (U)DMA driver depends on the BIOS for
+correct (U)DMA controller setup. If you have problems, first check that you
+have the latest BIOS revision for your specific motherboard.
+
+OTOH Michel Aubry's code for the VIA Apollo chipset has complete support for
+setting up the timing parameters. Check the triton.c source code for
+details.
+
+New BIOS revisions can be downloaded from your motherboard manufacturer's
+Web site. Flashing a new BIOS image is a simple operation but one must
+strictly follow the steps explained on the motherboard manual.
+
+Late Award BIOS revisions seem stable with respect to UDMA. Anything with a
+date of 1998 should be fine.
+
+
+Features missing from the present UDMA support code
+---------------------------------------------------
+
+It does not set UDMA transfer parameters (the driver assumes the BIOS has
+correctly setup all timing parameters) in the various chipsets. This
+requires access to a complete set of data sheets for the various chipsets,
+and testing on a variety of configurations, so it's not exactly within the
+reach of a humble Linux hacker. IMHO this is best left to the guys at Award
+and AMI (the BIOS guys), and to the motherboard engineers.
+
+Basically, UDMA transfers depend on two timing parameters:
+ 1) The pulse width of the active strobe signal for data transfers
+(usually described as the active pulse width).
+ 2) The delay between the negation of the DMA READY signal to the
+assertion of STOP when the IDE controller wants to stop a read operation
+(usually described as the recovery time).
+
+Both timing parameters can be set individually for each hard disk (up to two
+hard disks per channel).
+
+Knowing which registers must hold this data and the appropriate values, one
+could program the Linux triton.c driver to setup the IDE controller device,
+without relying on BIOS settings. However, some chipsets allow setting other
+timing parameters, and the required code would quickly increase to a
+not-so-easy-to-manage size. Better keep it simple, IMHO.
+
+It seems Mark Lord has devised a neat way to do this in the ide-dma driver
+included in late kernels 2.1.x: each chipset has an entry in a table, with
+safe timing values. The chipset is also identified when the driver is
+loaded.
+
+
+How does one use UDMA support?
+------------------------------
+
+1) Backup your data or you will be sorry. Now do "hdparm -t -T
+/dev/hda". Write a small note with the transfer rates you see.
+
+2) Reboot. Press [Del] to launch the CMOS SETUP routine, go to the
+CHIPSET SPECIFIC or PERIPHERALS SETUP menus, and enable UDMA transfers
+for your hard disk drives which are UDMA capable, or leave the fields in
+the default "AUTO" value. Enable both IDE channels even if you have just
+one IDE drive (default setting).
+
+3) Boot Linux, compile the kernel with the TRITON support enabled. Install
+the new kernel (the lilo thingy). Reboot Linux.
+
+4) Watch for the drive parameters message when the kernel loads (or type
+"dmesg | more" after login). After the Cyl, Heads, Sect parameters you
+should see "DMA" or "UDMA" depending on your hard disk drive and chipset
+capabilities.
+
+Here is what I get with UDMA enabled in the BIOS of my SiS 5598 based
+configuration, with an IBM UDMA capable hard disk as hda:
+
+...
+ide: DMA Bus Mastering IDE controller on PCI bus 0 function 9
+ ide0: BM-DMA at 0x4000-0x4007
+ ide1: BM-DMA at 0x4008-0x400f
+hda: IBM-DHEA-36480, 6197MB w/476kB Cache, LBA, CHS=790/255/63, UDMA
+...
+
+If I disable UDMA in the BIOS, I get:
+
+...
+ide: DMA Bus Mastering IDE controller on PCI bus 0 function 9
+ ide0: BM-DMA at 0x4000-0x4007
+ ide1: BM-DMA at 0x4008-0x400f
+hda: IBM-DHEA-36480, 6197MB w/476kB Cache, LBA, CHS=790/255/63, DMA
+...
+
+5) Again, do "hdparm -t -T /dev/hda". Smile. Test your setup by copying
+a few large files around or doing some large compilation (e.g. the Linux
+kernel itself).
+
+
+Performance issues
+------------------
+
+1) Sustained transfer rates.
+
+Here is some data gathered after extensive testing, using the hdparm utility
+(also written by Mark Lord):
+
+PIO mode 4 transfer rates under Linux: +/- 5.2MB/s
+
+DMA mode 2 transfer rates under Linux: +/- 7.2MB/s
+
+UDMA mode 2 transfer rates under Linux: +/- 9.8MB/s
+
+Data gathered on a Chaintech SiS 5598 motherboard, 6x86MX @ 187.5MHz, Linux
+2.0.32/2.0.33 with patched triton.c driver as explained above, IBM DeskStar
+6.4GB hard disk (IBM-DHEA-36480).
+
+The integrated video hardware in the SiS 5598 chip was disabled (a standard
+PCI video board was used); enabling the integrated SVGA controller will
+cause a 20% performance hit in processing performance, due to limited main
+memory bandwidth.
+
+The TX motherboard under the same test conditions will be slightly
+slower (0.1 - 0.2 MB/s slower).
+
+Burst (instantaneous) transfer rates are supposed to go from 16.6MB/s (PIO
+mode 4) to 16.6MB/s (DMA mode 2) up to 33MB/s (UDMA). In his patch against
+kernel 2.1.55, Kim-Hoe Pang actually checked the UDMA burst transfer rate
+with a logic analiser: 60ns/word, which translates into 33MB/s.
+
+Note that burst transfer rates only affect data transfers to/from the EIDE
+drive cache (476kB for the IBM 6.4GB drive), and IMHO are not particularly
+relevant for most Linux users.
+
+The Linux kernel uses as much RAM as possible to cache hard disk data
+accesses, and so if data is not in the kernel cache there is little chance
+that it will be in the (much smaller) hard disk cache.
+
+2) Processor utilization
+
+Unfortunately, it is very difficult to gather data about processor
+utilization during data transfers, but this is exactly the biggest advantage
+of DMA transfers over PIO transfers. My estimate is that CPU utilization
+during UDMA transfers will be as low as 3-4%, while being somewhere around
+30% for PIO transfers and 6-8% for DMA mode 2.
+
+3) UDMA vs SCSI
+
+The main advantage of DMA mode 2 and UDMA over SCSI is that the controller
+is already on your motherboard, so why not use it?
+
+Mark Lord's triton.c driver has a very small latency and so UDMA drives
+may beat their Ultra-Wide SCSI-2 counterparts in some cases (at equal
+spindle speeds) e.g. lots of small files (loaded news servers) being
+read/written at irregular intervals.
+
+Note however that SCSI drives are available at spindle speeds of 7,200,
+10,000 and even a recently announced 12,030 rpm. IBM is planning some 7,200
+rpm UDMA EIDE drives, but those are not yet available. Seagate has just
+released its EIDE 7,200 rpm drives, but they have special cooling
+requirements just like their SCSI counterparts. Expect this technology to
+become commonplace by the end of 98, though.
+
+The UDMA burst data transfer rates exceed maximum head transfer rates
+(maximum head transfer rates in the industry have reached 160 Mbits/s in
+1998) and so for large files neither Ultra-Wide SCSI-2 nor UDMA will have an
+advantage over the other technology.
+
+It used to be that high-capacity drives were only available with SCSI
+interfaces, but this isn't true anymore. Right now top capacity for an EIDE
+drive is Maxtor's 11.3Gb monster, which is quite affordable in fact. One can
+drive four of these with a standard motherboard: 45Gb for < $2k.
+
+SCSI drives can chain, overlap and re-order commands, EIDE drives cannot.
+However, Linux already has an intelligent "elevator" algorithm for hard disk
+accesses.
+
+At present, EIDE top speed is 33MB/s burst. Ultra-Wide II SCSI is 80MB/s
+burst. The cost of an Ultra-Wide II SCSI controller + 9Gb hard disk is > 4 x
+the cost of an 8GB UDMA drive. IMHO the price/performance ratio of UDMA
+beats SCSI.
+
+A new standard is emerging called ATA-66, which will double the burst
+transfer speed of EIDE drives to 66Mb/s. I don't have any technical info
+about it, unfortunately. The first ATA-66 drives will be shipped by Quantum
+in 1999, but VIA has already announced two ATA-66 capable chipsets (in fact
+based on the same Southbridge chip); as I write this, data sheets are not
+available to the general public. Probably Intel will come out with a chipset
+of its own with ATA-66 capabilities.
+
+4) What is the best UDMA chipset/hard disk?
+
+Intel designed the first DMA mode 2 capable chipset, the FX (Triton I) a few
+years ago. The Linux DMA mode 2 driver was initially written by Mark Lord
+for the original Intel FX chipset and appeared around kernel 1.3.20 if I
+remember well. The later HX and VX chipsets had exactly the same DMA mode 2
+capabilities and the triton.c driver was for a long time Intel-only. Mark
+planned to support the Opti Viper chipset but Opti went out of the
+motherboard chipset business so fast that Mark didn't even have the time to
+get his hands on an Opti motherboard, I guess.
+
+Intel later introduced a UDMA compatible motherboard chipset with its TX
+chipset. Kernel 2.0.31 was the first Linux kernel to support the TX chipset,
+however only DMA mode 2 (16.6MB/s) was supported.
+
+The TX chipset has a proven record of reliability. But DMA mode 2 and UDMA
+transfers on the TX suffer from a flaw common to previous Intel DMA mode 2
+only chipsets: a single data buffer is shared between the two IDE channels.
+This buffer (64 bytes deep) is used to hold data on its way from the PCI bus
+to/from the hard disk's small cache. A hardware arbitration mechanism
+prevents data loss when the OS tries to simultaneously use both IDE
+channels.
+
+VIA chips also have a single FIFO, with the same 64 bytes deep buffer.
+However, VIA chips can have the buffer split 1:1 or 3:1 between both IDE
+channels; an interesting feature, but difficult to use.
+
+How is this FIFO buffer used? Remember that the PCI bus can transfer data at
+a maximum rate of 132MB/s when clocked at 33MHz, 150MB/s when clocked at
+37.5MHz (maximum safe clock speed for PCI is 33MHz, after that well..). So the
+PCI bus mastering IDE controller will be transfering data from main memory
+DRAM to this FIFO buffer in small bursts of < 64 bytes, then from the buffer
+to the IDE disk drive cache (when writing; the other way around for reads).
+
+I recently managed to get hold of the SiS 5598 data sheet and studied the
+IDE controller part of this highly integrated chip, a device identified by
+the number 5513. The 5598 even includes an SVGA controller, which should be
+disabled if one wants to get decent performance from this chipset: it
+severely limits CPU/memory bandwidth. The SiS5597 is the same part with
+a different pinout.
+
+It appears the 5513 has two completely independent IDE channels, each with
+its own 64 bytes deep data buffer. On disk-to-disk or CD-to-disk transfers,
+the 5598 and 5591 chipsets will easily beat the Intel TX and VIA. On
+simultaneous (U)DMA transfers to two disks (for example, when the Linux md
+driver is used to create a RAID-0 array with data striping), the 5513 device
+will be faster than the TX Southbridge device since there will be no
+contention for the data buffer, assuming each drive is connected to a
+different IDE channel. Other PCI bus related features will also improve its
+performance of the SiS devices. So, compared to the Intel TX and various VIA
+chipsets, the 5598 and 5591 win hands down in terms of UDMA implementation.
+
+Unfortunately, it is very difficult to get data sheets for the ALi Aladdin
+IV+ and Aladdin V chipsets. These newer chipsets support up to 1 MB of L2
+SRAM cache, the AGP bus (2X), 100 MHz CPU bus and of course, UDMA data
+transfers. The newest VIA chipset for Socket 7 motherboards beats them all
+in terms of features, as it sports ATA-66 compatibility.
+
+On the UDMA hard drive front, the present performance leaders are the IBM
+Deskstar drives. These drives have relatively large data caches (476kB
+available), a 5,400 rpm rotational speed and < 10ms random access times.
+They run very cool and although they can't be called silent, their noise
+level is acceptable. They are also reliable.
+
+Seagate has just begun shipping 7,200 rpm EIDE drives which will obviously
+benefit from the lower data latency. They are reported as particularly
+silent due to the use of Fluid Dynamic Bearing motors, but running quite
+hot. IMHO if one has to add a fan to cool them, this defeats any advantage
+these drives will have in terms of noise level. Another advantage of this
+technology is the lower vibration levels compared to ball bearings.
+
+IBM has pre-announced very large capacity (14GB), 7,200 rpm EIDE UDMA drives
+a month ago, but those are not shipping yet. They are based on a new head
+technology called Giant Magneto-Resistive Heads, which is supposed to
+increase the data density on the disks by a factor of 4 or more. More details
+when I get my hands on one. IBM licensed Western Digital to use this
+technology.
+
+Quantum has always shipped among the best and fastest EIDE drives, and they
+worked with Intel to create the UDMA standard. They used to have the fastest
+drives for Linux DMA mode 2 transfers (see the comments in
+/Documentation/ide.txt).
+
+Well, I just got an email from Denny de Jonge <de...@luna.nl> that proves
+Quantum drives will keep their reputation:
+
+"Andre,
+
+ After I applied the UDMA-patch for Linux 2.0.33 hdparm showed up with the
+ following benchmarks:
+
+ /dev/hda:
+
+ Timing buffer-cache reads: 64 MB in 1.02 seconds =62.75 MB/sec
+ Timing buffered disk reads: 32 MB in 3.02 seconds =10.60 MB/sec
+
+ Not bad, don't you think ?
+
+ These results have been obtained using the Intel 82371 Chipset and a
+ Quantum Fireball 4.3SE harddisk."
+
+I later asked what kind of processor Denny was using: it's a 266MHz PII.
+
+BTW I have been collecting hard disk/file subsystem benchmarking information
+based on bonnie, a popular benchmark available for Linux. I have come to the
+conclusion that bonnie is not a reliable benchmark when it comes to
+comparing different systems, basically because it depends so much on how
+much RAM one has installed and how much of it is free, as well as system
+load, CPU speed, etc. For this reason I will not quote bonnie results
+anymore. For comparative benchmarking between two hard disk drives on
+exactly the same hardware it may be acceptable, but otherwise it's too
+unreliable as an indicator of performance.
+
+
+Unreliable drive + motherboard + driver combination
+---------------------------------------------------
+
+Quoting Kim-Hoe Pang:
+
+"The UDMA mode of an UDMA drive would NOT be enabled on a non-UDMA capable
+chipset mobo. On power-up or after a hardware reset, the drive is in normal
+PIO/DMA mode. To enable the UDMA mode in the drive, the host, BIOS or OS,
+needs to send a SET FEATURE ("enable UDMA mode subcommand") AT command to
+the drive. A non-UDMA capable mobo will not send this command to the drive.
+
+UDMA mode is dis/enabled via BIOS setup. The patch does not attempt to
+override user's BIOS setting."
+
+There may be some combinations of drives, motherboards (BIOS) and Linux
+driver which may prove unreliable. Remember we are transfering data at
+33MB/s over unshielded ribbon cable in a very noisy (electromagnetically
+speaking) environment.
+
+In the future it would be nice if hard disk manufacturers would publish the
+timings required by their drives, and chipset manufacturers would follow a
+single standard for registers and controller architecture. Right now UDMA is
+extremely timing sensitive.
+
+A few recommendations for troubleshooting:
+
+1) Make sure you have the latest BIOS for your motherboard. Connect to the
+motherboard manufacturer's Web site and download the latest BIOS image file
+and EEPROM flashing utilities. Check your BIOS version, and only flash your
+EEPROM if needed.
+
+2) Keep the IDE cable going from the motherboard to the drive short, and do
+not loop it around another cable. I recommend < 30 cm (12") total cable
+length.
+
+3) If you have just a single UDMA hard disk drive per channel (which I
+recommend), use the connectors at both ends of the cable to connect
+motherboard and drive, do _not_ use the middle connector. If you have a UDMA
+hard disk drive and a CD-ROM drive on the same cable, plug the hard disk
+drive at the end of the cable (use the middle connector for the CD-ROM
+drive). Also the hard disk must be the master EIDE device, the CD-ROM drive
+the slave EIDE device, never the other way around (this is not determined by
+cable position, but by small jumpers on the drive and at the back of the
+CD-ROM). The same rules apply to CD-RW, ZIP and tape EIDE drives.
+
+4) If you have (shudder) Windows 95 installed in your system, and have been
+able to use UDMA, you should be able to use UDMA with Linux.
+
+5) DON'T OVERCLOCK the PCI bus. 33MHz is the maximum supported speed for
+the PCI bus. Some (supposedly compatible) UDMA drives will not even take
+37.5MHz, but should be OK at 33.3MHz.
+
+In any case, NEVER, NEVER set the PCI bus to 41.5MHz.
+
+The RECOMMENDED safe setting is 33MHz.
+
+Adequate testing is needed in each case. The golden rule here, as always:
+backup, backup, backup.
+
+
+Aknowledgments
+--------------
+
+Mark Lord for his excellent, reliable and very readable triton.c driver code
+and all his (E)IDE Linux programming.
+
+Kim-Hoe Pang for the first UDMA patch against kernel 2.1.55.
+
+Christian Brunner for his patch converting triton.c into a generic DMA mode
+2 EIDE driver.
+
+Brion Vibber for his neat Linux UDMA mini-HOWTO, for his help and
+contributions to this package, and for bearing with my various documentation
+changes and suggestions.
+
+Michel Aubry for his complete VIA support and neat diagnostics code, as well
+as the patch to hdparm to support UDMA.
+
+Andre Hedrick for his great code for the various PCI UDMA controller cards.
+
diff -u --recursive --new-file v2.0.36/linux/MAINTAINERS linux/MAINTAINERS
--- v2.0.36/linux/MAINTAINERS Sun Nov 15 21:51:46 1998
+++ linux/MAINTAINERS Sun Jun 13 10:20:59 1999
@@ -123,8 +123,8 @@
X S: Maintained
X
X APM DRIVER
-P: Rik Faith & Stephen Rothwell
-M: fa...@cs.unc.edu, Stephen....@canb.auug.org.au
+P: Stephen Rothwell
+M: Stephen....@canb.auug.org.au
X L: linux-...@vger.rutgers.edu
X S: Maintained
X
@@ -165,11 +165,23 @@
X S: Maintained
X
X CYCLADES ASYNC MUX DRIVER
-P: Marcio Saito
-M: Marcio Saito <mar...@cyclades.com>
+P: Ivan Passos
+M: Ivan Passos <iv...@cyclades.com>
X W: http://www.cyclades.com/
X S: Supported
X
+DC390/AM53C974 SCSI driver
+P: Kurt Garloff
+M: ku...@garloff.de
+W: http://www.garloff.de/kurt/linux/dc390/
+S: Maintained
+
+DAC960 RAID DRIVER
+P: Leonard N. Zubkoff
+M: Leonard N. Zubkoff <l...@dandelion.com>
+L: linux...@vger.rutgers.edu
+S: Maintained
+
X EATA ISA/EISA/PCI SCSI DRIVER
X P: Dario Ballabio
X M: da...@milano.europe.dg.com
@@ -279,9 +291,9 @@
X
X NCP FILESYSTEM:
X P: Volker Lendecke
-M: lend...@namu01.Num.Math.Uni-Goettingen.de
+M: v...@kki.org
X L: lin...@sh.cvut.cz
-S: Maintained
+S: Odd Fixes
X
X NETROM NETWORK LAYER
X P: Jon Naylor
@@ -315,7 +327,7 @@
X
X SMB FILESYSTEM:
X P: Volker Lendecke
-M: lend...@namu01.Num.Math.Uni-Goettingen.de
+M: v...@kki.org
X L: sa...@listproc.anu.edu.au
X S: Odd Fixes
X
diff -u --recursive --new-file v2.0.36/linux/Makefile linux/Makefile
--- v2.0.36/linux/Makefile Sun Nov 15 21:51:46 1998
+++ linux/Makefile Sun Jun 13 10:20:59 1999
@@ -1,8 +1,8 @@
X VERSION = 2
X PATCHLEVEL = 0
-SUBLEVEL = 36
+SUBLEVEL = 37
X
-ARCH = i386
+ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
X
X #
X # For SMP kernels, set this. We don't want to have this in the config file
@@ -359,6 +359,14 @@
X scripts/mkdep `find $(FINDHPATH) -follow -name \*.h ! -name modversions.h -print` > .hdepend
X set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i fastdep; done
X mv .tmpdepend .depend
+
+# Prepare source tree for RCS version control using Emacs VC;
+# make all needed RCS directories and write-lock nearly everything.
+vc:
+ chmod a-w COPYING CREDITS MAINTAINERS Makefile README Rules.make
+ find . -type d ! -name "*RCS" -exec mkdir {}/RCS \;
+ find . -type f \( -name *.[chS] -o -name "*Makefile" -o -name "*README*" -o -name "*Config.in" -o -name "*.txt" \) -exec chmod a-w {} \;
+ find Documentation scripts -type f -exec chmod a-w {} \;
X
X MODVERFILE :=
X
diff -u --recursive --new-file v2.0.36/linux/README linux/README
--- v2.0.36/linux/README Wed Jun 26 01:05:26 1996
+++ linux/README Sun Jun 13 10:20:59 1999
@@ -47,7 +47,12 @@
X gzip -cd linux-2.0.XX.tar.gz | tar xfv -
X
X to get it all put in place. Replace "XX" with the version number of the
- latest kernel.
+ latest kernel. If you use GNU tar,
+
+ cd /usr/src
+ tar -xzvf linux-2.1.XX.tar.gz
+
+ is equivalent.
X
X - You can also upgrade between 2.0.xx releases by patching. Each
X patch that is released for 2.0.xx contains only bugfixes. No
@@ -75,15 +80,6 @@
X can be specified as the first argument. Patches are applied from
X the current directory, but an alternative directory can be specified
X as the second argument.
-
- - make sure your /usr/include/asm, /usr/include/linux, and /usr/include/scsi
- directories are just symlinks to the kernel sources:
-
- cd /usr/include
- rm -rf asm linux scsi
- ln -s /usr/src/linux/include/asm-i386 asm
- ln -s /usr/src/linux/include/linux linux
- ln -s /usr/src/linux/include/scsi scsi
X
X - make sure you have no stale .o files and dependencies lying around:
X
diff -u --recursive --new-file v2.0.36/linux/arch/alpha/Makefile linux/arch/alpha/Makefile
--- v2.0.36/linux/arch/alpha/Makefile Mon Jul 13 13:46:24 1998
+++ linux/arch/alpha/Makefile Sun Jun 13 10:20:59 1999
@@ -27,9 +27,9 @@
X CFLAGS := $(CFLAGS) -mno-fp-regs
X
X # determine if we can use the BWX instructions with GAS
-$(shell rm -f /tmp/GAS_VER)
+dummy:=$(shell rm -f /tmp/GAS_VER)
X #$(shell $(AS) --version >& /tmp/GAS_VER)
-$(shell $(AS) --version > /tmp/GAS_VER 2>&1)
+dummy:=$(shell $(AS) --version > /tmp/GAS_VER 2>&1)
X OLD_GAS := $(shell if cat /tmp/GAS_VER | grep 'version 2.7' > /dev/null; then echo yes; else echo no; fi)
X
X ifneq ($(OLD_GAS),yes)
diff -u --recursive --new-file v2.0.36/linux/arch/alpha/defconfig linux/arch/alpha/defconfig
--- v2.0.36/linux/arch/alpha/defconfig Mon Jul 13 13:46:25 1998
+++ linux/arch/alpha/defconfig Sun Jun 13 10:20:59 1999
@@ -159,7 +159,7 @@
X # CONFIG_LANCE is not set
X # CONFIG_NET_VENDOR_SMC is not set
X # CONFIG_NET_ISA is not set
-CONFIG_NET_EISA=y
+CONFIG_NET_PCI=y
X # CONFIG_APRICOT is not set
X CONFIG_DE4X5=y
X # CONFIG_DEC_ELCP is not set
@@ -220,7 +220,6 @@
X # CONFIG_UMISC is not set
X # CONFIG_QIC02_TAPE is not set
X # CONFIG_FTAPE is not set
-# CONFIG_APM is not set
X # CONFIG_WATCHDOG is not set
X # CONFIG_RTC is not set
X
diff -u --recursive --new-file v2.0.36/linux/arch/i386/boot/setup.S linux/arch/i386/boot/setup.S
--- v2.0.36/linux/arch/i386/boot/setup.S Sun Nov 15 21:51:46 1998
+++ linux/arch/i386/boot/setup.S Sun Jun 13 10:20:59 1999
@@ -18,7 +18,7 @@
X ! March 1993/June 1994 (Christop...@linux.org)
X !
X ! add APM BIOS checking by Stephen Rothwell, May 1994
-! (Stephen....@pd.necisa.oz.au)
+! (Stephen....@canb.auug.org.au)
X !
X ! High load stuff, initrd support and position independency
X ! by Hans Lermen & Werner Almesberger, February 1996
@@ -331,7 +331,7 @@
X
X #ifdef CONFIG_APM
X ! check for APM BIOS
- ! NOTE: DS is pointing to the bootsector
+ ! NOTE: DS is pointing to the boot sector
X !
X mov [64],#0 ! version == 0 means no APM BIOS
X
@@ -481,6 +481,29 @@
X mov al,#0xDF ! A20 on
X out #0x60,al
X call empty_8042
+
+! wait until a20 really *is* enabled; it can take a fair amount of
+! time on certain systems; Toshiba Tecras are known to have this
+! problem. The memory location used here is the int 0x1f vector,
+! which should be safe to use; any *unused* memory location < 0xfff0
+! should work here.
+
+#define TEST_ADDR 0x7c
+
+ push ds
+ xor ax,ax ! segment 0x0000
+ mov ds,ax
+ dec ax ! segment 0xffff (HMA)
+ mov gs,ax
+ mov bx,[TEST_ADDR] ! we want to restore the value later
+a20_wait:
+ inc ax
+ mov [TEST_ADDR],ax
+ seg gs
+ cmp ax,[TEST_ADDR+0x10]
+ je a20_wait ! loop until no longer aliased
+ mov [TEST_ADDR],bx ! restore original value
+ pop ds
X
X ! make sure any possible coprocessor is properly reset..
X
diff -u --recursive --new-file v2.0.36/linux/arch/i386/config.in linux/arch/i386/config.in
--- v2.0.36/linux/arch/i386/config.in Sun Nov 15 21:51:46 1998
+++ linux/arch/i386/config.in Sun Jun 13 10:20:59 1999
@@ -22,6 +22,20 @@
X comment 'General setup'
X
X bool 'Kernel math emulation' CONFIG_MATH_EMULATION
+choice 'Memory configuration' \
+ "Standard CONFIG_MEM_STD \
+ Enterprise CONFIG_MEM_ENT \
+ Custom CONFIG_MEM_SPECIAL" Standard
+
+if [ "$CONFIG_MEM_SPECIAL" = "y" ]; then
+ int ' Max physical memory in MB' CONFIG_MAX_MEMSIZE 1024
+fi
+if [ "$CONFIG_MEM_ENT" = "y" ]; then
+ define_int CONFIG_MAX_MEMSIZE 2048
+fi
+if [ "$CONFIG_MEM_STD" = "y" ]; then
+ define_int CONFIG_MAX_MEMSIZE 1024
+fi
X bool 'Networking support' CONFIG_NET
X bool 'Limit memory to low 16MB' CONFIG_MAX_16M
X bool 'PCI bios support' CONFIG_PCI
@@ -47,6 +61,16 @@
X # Conditionally compile MTRR manipulation support
X if [ "$CONFIG_M686" = "y" -o "$CONFIG_M586" = "y" ]; then
X bool 'Handle buggy SMP BIOSes with bad MTRR setup' CONFIG_MTRR
+fi
+
+bool 'Advanced Power Management BIOS support' CONFIG_APM
+if [ "$CONFIG_APM" = "y" ]; then
+ bool ' Ignore USER SUSPEND' CONFIG_APM_IGNORE_USER_SUSPEND
+ bool ' Enable PM at boot time' CONFIG_APM_DO_ENABLE
+ bool ' Make CPU Idle calls when idle' CONFIG_APM_CPU_IDLE
+ bool ' Enable console blanking using APM' CONFIG_APM_DISPLAY_BLANK
+ bool ' Power off on shutdown' CONFIG_APM_POWER_OFF
+ bool ' Ignore multiple suspend' CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
X fi
X
X endmenu
diff -u --recursive --new-file v2.0.36/linux/arch/i386/defconfig linux/arch/i386/defconfig
--- v2.0.36/linux/arch/i386/defconfig Sun Nov 15 10:49:26 1998
+++ linux/arch/i386/defconfig Sun Jun 13 10:20:59 1999
@@ -55,7 +55,12 @@
X # Additional Block Devices
X #
X # CONFIG_BLK_DEV_LOOP is not set
-# CONFIG_BLK_DEV_MD is not set
+CONFIG_BLK_DEV_MD=y
+CONFIG_AUTODETECT_RAID=y
+CONFIG_MD_LINEAR=y
+CONFIG_MD_STRIPED=y
+CONFIG_MD_MIRRORING=y
+CONFIG_MD_RAID5=y
X # CONFIG_BLK_DEV_RAM is not set
X # CONFIG_BLK_DEV_XD is not set
X # CONFIG_PARIDE is not set
diff -u --recursive --new-file v2.0.36/linux/arch/i386/kernel/Makefile linux/arch/i386/kernel/Makefile
--- v2.0.36/linux/arch/i386/kernel/Makefile Sun Nov 15 21:51:46 1998
+++ linux/arch/i386/kernel/Makefile Sun Jun 13 10:20:59 1999
@@ -23,6 +23,11 @@
X O_TARGET := kernel.o
X O_OBJS := process.o signal.o entry.o traps.o irq.o vm86.o bios32.o \
X ptrace.o ioport.o ldt.o setup.o time.o sys_i386.o ksyms.o
+OX_OBJS :=
+
+ifdef CONFIG_APM
+OX_OBJS += apm.o
+endif
X
X ifdef SMP
X
diff -u --recursive --new-file v2.0.36/linux/arch/i386/kernel/apm.c linux/arch/i386/kernel/apm.c
--- v2.0.36/linux/arch/i386/kernel/apm.c Wed Dec 31 16:00:00 1969
+++ linux/arch/i386/kernel/apm.c Sun Jun 13 10:20:59 1999
@@ -0,0 +1,1269 @@
+/* -*- linux-c -*-
+ * APM BIOS driver for Linux
+ * Copyright 1994-1999 Stephen Rothwell
+ * (Stephen....@canb.auug.org.au)
+ * Development of this driver was funded by NEC Australia P/L
+ * and NEC Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * October 1995, Rik Faith (fa...@cs.unc.edu):
+ * Minor enhancements and updates (to the patch set) for 1.3.x
+ * Documentation
+ * January 1996, Rik Faith (fa...@cs.unc.edu):
+ * Make /proc/apm easy to format (bump driver version)
+ * March 1996, Rik Faith (fa...@cs.unc.edu):
+ * Prohibit APM BIOS calls unless apm_enabled.
+ * (Thanks to Ulrich Windl <Ulrich...@rz.uni-regensburg.de>)
+ * April 1996, Stephen Rothwell (Stephen....@canb.auug.org.au)
+ * Version 1.0 and 1.1
+ * May 1996, Version 1.2
+ *
+ * History:
+ * 0.6b: first version in official kernel, Linux 1.3.46
+ * 0.7: changed /proc/apm format, Linux 1.3.58
+ * 0.8: fixed gcc 2.7.[12] compilation problems, Linux 1.3.59
+ * 0.9: only call bios if bios is present, Linux 1.3.72
+ * 1.0: use fixed device number, consolidate /proc/apm into this file,
+ * Linux 1.3.85
+ * 1.1: support user-space standby and suspend, power off after system
+ * halted, Linux 1.3.98
+ * 1.2: When resetting RTC after resume, take care so that the time
+ * is only incorrect by 30-60mS (vs. 1S previously) (Gabor J. Toth
+ * <jt...@princeton.edu>); improve interaction between
+ * screen-blanking and gpm (Stephen Rothwell); Linux 1.99.4
+ * 1.2a: Fix OOPs on power off with no APM BIOS
+ * Jan Echternach <ech...@informatik.uni-rostock.de>
+ *
+ * Reference:
+ *
+ * Intel Corporation, Microsoft Corporation. Advanced Power Management
+ * (APM) BIOS Interface Specification, Revision 1.1, September 1993.
+ * Intel Order Number 241704-001. Microsoft Part Number 781-110-X01.
+ *
+ * [This document is available free from Intel by calling 800.628.8686 (fax
+ * 916.356.6100) or 800.548.4725; or via anonymous ftp from
+ * ftp://ftp.intel.com/pub/IAL/software_specs/apmv11.doc. It is also
+ * available from Microsoft by calling 206.882.8080.]
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <asm/system.h>
+#include <asm/segment.h>
+
+#include <linux/types.h>
+#include <linux/stddef.h>
+#include <linux/timer.h>
+#include <linux/fcntl.h>
+#include <linux/malloc.h>
+#include <linux/linkage.h>
+#ifdef CONFIG_PROC_FS
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+#endif
+#include <linux/miscdevice.h>
+#include <linux/apm_bios.h>
+
+static struct symbol_table apm_syms = {
+#include <linux/symtab_begin.h>
+ X(apm_register_callback),
+ X(apm_unregister_callback),
+#include <linux/symtab_end.h>
+};
+
+extern unsigned long get_cmos_time(void);
+
+/*
+ * The apm_bios device is one of the misc char devices.
+ * This is its minor number.
+ */
+#define APM_MINOR_DEV 134
+
+/* Configurable options:
+ *
+ * CONFIG_APM_IGNORE_USER_SUSPEND: define to ignore USER SUSPEND requests.
+ * This is necessary on the NEC Versa M series, which generates these when
+ * resuming from SYSTEM SUSPEND. However, enabling this on other laptops
+ * will cause the laptop to generate a CRITICAL SUSPEND when an appropriate
+ * USER SUSPEND is ignored -- this may prevent the APM driver from updating
+ * the system time on a RESUME.
+ *
+ * CONFIG_APM_DO_ENABLE: enable APM features at boot time. From page 36 of
+ * the specification: "When disabled, the APM BIOS does not automatically
+ * power manage devices, enter the Standby State, enter the Suspend State,
+ * or take power saving steps in response to CPU Idle calls." This driver
+ * will make CPU Idle calls when Linux is idle (unless this feature is
+ * turned off -- see below). This should always save battery power, but
+ * more complicated APM features will be dependent on your BIOS
+ * implementation. You may need to turn this option off if your computer
+ * hangs at boot time when using APM support, or if it beeps continuously
+ * instead of suspending. Turn this off if you have a NEC UltraLite Versa
+ * 33/C or a Toshiba T400CDT. This is off by default since most machines
+ * do fine without this feature.
+ *
+ * CONFIG_APM_CPU_IDLE: enable calls to APM CPU Idle/CPU Busy inside the
+ * idle loop. On some machines, this can activate improved power savings,
+ * such as a slowed CPU clock rate, when the machine is idle. These idle
+ * call is made after the idle loop has run for some length of time (e.g.,
+ * 333 mS). On some machines, this will cause a hang at boot time or
+ * whenever the CPU becomes idle.
+ *
+ * CONFIG_APM_DISPLAY_BLANK: enable console blanking using the APM. Some
+ * laptops can use this to turn of the LCD backlight when the VC screen
+ * blanker blanks the screen. Note that this is only used by the VC screen
+ * blanker, and probably won't turn off the backlight when using X11. Some
+ * problems have been reported when using this option with gpm (if you'd
+ * like to debug this, please do so).
+ *
+ * CONFIG_APM_IGNORE_MULTIPLE_SUSPEND: The IBM TP560 bios seems to insist
+ * on returning multiple suspend/standby events whenever one occurs. We
+ * really only need one at a time, so just ignore any beyond the first.
+ * This is probably safe on most laptops.
+ *
+ * If you are debugging the APM support for your laptop, note that code for
+ * all of these options is contained in this file, so you can #define or
+ * #undef these on the next line to avoid recompiling the whole kernel.
+ *
+ */
+
+/* KNOWN PROBLEM MACHINES:
+ *
+ * U: TI 4000M TravelMate: BIOS is *NOT* APM compliant
+ * [Confirmed by TI representative]
+ * U: ACER 486DX4/75: uses dseg 0040, in violation of APM specification
+ * [Confirmed by BIOS disassembly]
+ * P: Toshiba 1950S: battery life information only gets updated after resume
+ *
+ * Legend: U = unusable with APM patches
+ * P = partially usable with APM patches
+ */
+
+/*
+ * Define to have debug messages.
+ */
+#undef APM_DEBUG
+
+/*
+ * Define to always call the APM BIOS busy routine even if the clock was
+ * not slowed by the idle routine.
+ */
+#define ALWAYS_CALL_BUSY
+
+/*
+ * Define to disable interrupts in APM BIOS calls (the CPU Idle BIOS call
+ * should turn interrupts on before it does a 'hlt').
+ */
+#define APM_NOINTS
+
+/*
+ * Define to make the APM BIOS calls zero all data segment registers (do
+ * that if an incorrect BIOS implementation will cause a kernel panic if it
+ * tries to write to arbitrary memory).
+ */
+#define APM_ZERO_SEGS
+
+/*
+ * Define to make all set_limit calls use 64k limits. The APM 1.1 BIOS is
+ * supposed to provide limit information that it recognizes. Many machines
+ * do this correctly, but many others do not restrict themselves to their
+ * claimed limit. When this happens, they will cause a segmentation
+ * violation in the kernel at boot time. Most BIOS's, however, will
+ * respect a 64k limit, so we use that. If you want to be pedantic and
+ * hold your BIOS to its claims, then undefine this.
+ */
+#define APM_RELAX_SEGMENTS
+
+/*
+ * Need to poll the APM BIOS every second
+ */
+#define APM_CHECK_TIMEOUT (HZ)
+
+/*
+ * These are the actual BIOS calls in assembler. Depending on
+ * APM_ZERO_SEGS and APM_NOINTS, we are being really paranoid here! Not
+ * only are interrupts disabled, but all the segment registers (except SS)
+ * are saved and zeroed this means that if the BIOS tries to reference any
+ * data without explicitly loading the segment registers, the kernel will
+ * fault immediately rather than have some unforeseen circumstances for the
+ * rest of the kernel. And it will be very obvious! :-) Doing this
+ * depends on CS referring to the same physical memory as DS so that DS can
+ * be zeroed before the call. Unfortunately, we can't do anything about the


SHAR_EOF
true || echo 'restore of patch-2.0.37 failed'
fi

echo 'End of part 02'
echo 'File patch-2.0.37 is continued in part 03'
echo 03 > _shar_seq_.tmp

Thomas...@ciw.uni-karlsruhe.de

unread,
Jun 16, 1999, 3:00:00 AM6/16/99
to
Archive-name: v2.0/patch-2.0.37/part05

#!/bin/sh
# this is part 05 of a 45 - part archive


# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.0.37 continued
if test ! -r _shar_seq_.tmp; then
echo 'Please unpack part 1 first!'
exit 1
fi
(read Scheck

if test "$Scheck" != 05; then


echo Please unpack part "$Scheck" next!
exit 1
else
exit 0
fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.0.37'
else
echo 'x - continuing with patch-2.0.37'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.0.37' &&

+ DAC960_V3_StatusCommandIdentifierRegOffset = 0x0D,
+ DAC960_V3_StatusRegisterOffset = 0x0E,
+ DAC960_V3_InboundDoorBellRegisterOffset = 0x40,
+ DAC960_V3_OutboundDoorBellRegisterOffset = 0x41,
+ DAC960_V3_InterruptEnableRegisterOffset = 0x43
+}
+DAC960_V3_RegisterOffsets_T;
+
+
+/*
+ Define the structure of the DAC960 V3 Inbound Door Bell Register.
+*/
+
+typedef union DAC960_V3_InboundDoorBellRegister
+{
+ unsigned char All;
+ struct {
+ boolean NewCommand:1; /* Bit 0 */
+ boolean AcknowledgeStatus:1; /* Bit 1 */
+ unsigned char :1; /* Bit 2 */
+ boolean SoftReset:1; /* Bit 3 */
+ unsigned char :4; /* Bits 4-7 */
+ } Write;
+ struct {
+ boolean MailboxFull:1; /* Bit 0 */
+ unsigned char :7; /* Bits 1-7 */
+ } Read;
+}
+DAC960_V3_InboundDoorBellRegister_T;
+
+
+/*
+ Define the structure of the DAC960 V3 Outbound Door Bell Register.
+*/
+
+typedef union DAC960_V3_OutboundDoorBellRegister
+{
+ unsigned char All;
+ struct {
+ boolean AcknowledgeInterrupt:1; /* Bit 0 */
+ unsigned char :7; /* Bits 1-7 */
+ } Write;
+ struct {
+ boolean StatusAvailable:1; /* Bit 0 */
+ unsigned char :7; /* Bits 1-7 */
+ } Read;
+}
+DAC960_V3_OutboundDoorBellRegister_T;
+
+
+/*
+ Define the structure of the DAC960 V3 Interrupt Enable Register.
+*/
+
+typedef union DAC960_V3_InterruptEnableRegister
+{
+ unsigned char All;
+ struct {
+ boolean EnableInterrupts:1; /* Bit 0 */
+ unsigned char :7; /* Bits 1-7 */
+ } Bits;
+}
+DAC960_V3_InterruptEnableRegister_T;
+
+
+/*
+ Define the DAC960 Command Identifier type.
+*/
+
+typedef unsigned char DAC960_CommandIdentifier_T;
+
+
+/*
+ Define the DAC960 Command Opcodes.
+*/
+
+typedef enum
+{
+ /* I/O Commands */
+ DAC960_ReadExtended = 0x33,
+ DAC960_WriteExtended = 0x34,
+ DAC960_ReadAheadExtended = 0x35,
+ DAC960_ReadExtendedWithScatterGather = 0xB3,
+ DAC960_WriteExtendedWithScatterGather = 0xB4,
+ DAC960_Read = 0x36,
+ DAC960_ReadWithOldScatterGather = 0xB6,
+ DAC960_Write = 0x37,
+ DAC960_WriteWithOldScatterGather = 0xB7,
+ DAC960_DCDB = 0x04,
+ DAC960_DCDBWithScatterGather = 0x84,
+ DAC960_Flush = 0x0A,
+ /* Controller Status Related Commands */
+ DAC960_Enquiry = 0x53,
+ DAC960_Enquiry2 = 0x1C,
+ DAC960_GetLogicalDriveElement = 0x55,
+ DAC960_GetLogicalDriveInformation = 0x19,
+ DAC960_IOPortRead = 0x39,
+ DAC960_IOPortWrite = 0x3A,
+ DAC960_GetSDStats = 0x3E,
+ DAC960_GetPDStats = 0x3F,
+ DAC960_PerformEventLogOperation = 0x72,
+ /* Device Related Commands */
+ DAC960_StartDevice = 0x10,
+ DAC960_GetDeviceState = 0x50,
+ DAC960_StopChannel = 0x13,
+ DAC960_StartChannel = 0x12,
+ DAC960_ResetChannel = 0x1A,
+ /* Commands Associated with Data Consistency and Errors */
+ DAC960_Rebuild = 0x09,
+ DAC960_RebuildAsync = 0x16,
+ DAC960_CheckConsistency = 0x0F,
+ DAC960_CheckConsistencyAsync = 0x1E,
+ DAC960_RebuildStat = 0x0C,
+ DAC960_GetRebuildProgress = 0x27,
+ DAC960_RebuildControl = 0x1F,
+ DAC960_ReadBadBlockTable = 0x0B,
+ DAC960_ReadBadDataTable = 0x25,
+ DAC960_ClearBadDataTable = 0x26,
+ DAC960_GetErrorTable = 0x17,
+ DAC960_AddCapacityAsync = 0x2A,
+ /* Configuration Related Commands */
+ DAC960_ReadConfig2 = 0x3D,
+ DAC960_WriteConfig2 = 0x3C,
+ DAC960_ReadConfigurationOnDisk = 0x4A,
+ DAC960_WriteConfigurationOnDisk = 0x4B,
+ DAC960_ReadConfiguration = 0x4E,
+ DAC960_ReadBackupConfiguration = 0x4D,
+ DAC960_WriteConfiguration = 0x4F,
+ DAC960_AddConfiguration = 0x4C,
+ DAC960_ReadConfigurationLabel = 0x48,
+ DAC960_WriteConfigurationLabel = 0x49,
+ /* Firmware Upgrade Related Commands */
+ DAC960_LoadImage = 0x20,
+ DAC960_StoreImage = 0x21,
+ DAC960_ProgramImage = 0x22,
+ /* Diagnostic Commands */
+ DAC960_SetDiagnosticMode = 0x31,
+ DAC960_RunDiagnostic = 0x32,
+ /* Subsystem Service Commands */
+ DAC960_GetSubsystemData = 0x70,
+ DAC960_SetSubsystemParameters = 0x71
+}
+__attribute__ ((packed))
+DAC960_CommandOpcode_T;
+
+
+/*
+ Define the DAC960 Command Status Codes.
+*/
+
+#define DAC960_NormalCompletion 0x0000 /* Common */
+#define DAC960_CheckConditionReceived 0x0002 /* Common */
+#define DAC960_NoDeviceAtAddress 0x0102 /* Common */
+#define DAC960_InvalidDeviceAddress 0x0105 /* Common */
+#define DAC960_InvalidParameter 0x0105 /* Common */
+#define DAC960_IrrecoverableDataError 0x0001 /* I/O */
+#define DAC960_LogicalDriveNonexistentOrOffline 0x0002 /* I/O */
+#define DAC960_AccessBeyondEndOfLogicalDrive 0x0105 /* I/O */
+#define DAC960_BadDataEncountered 0x010C /* I/O */
+#define DAC960_DeviceBusy 0x0008 /* DCDB */
+#define DAC960_DeviceNonresponsive 0x000E /* DCDB */
+#define DAC960_CommandTerminatedAbnormally 0x000F /* DCDB */
+#define DAC960_UnableToStartDevice 0x0002 /* Device */
+#define DAC960_InvalidChannelOrTarget 0x0105 /* Device */
+#define DAC960_ChannelBusy 0x0106 /* Device */
+#define DAC960_ChannelNotStopped 0x0002 /* Device */
+#define DAC960_AttemptToRebuildOnlineDrive 0x0002 /* Consistency */
+#define DAC960_RebuildBadBlocksEncountered 0x0003 /* Consistency */
+#define DAC960_NewDiskFailedDuringRebuild 0x0004 /* Consistency */
+#define DAC960_RebuildOrCheckAlreadyInProgress 0x0106 /* Consistency */
+#define DAC960_DependentDiskIsDead 0x0002 /* Consistency */
+#define DAC960_InconsistentBlocksFound 0x0003 /* Consistency */
+#define DAC960_InvalidOrNonredundantLogicalDrive 0x0105 /* Consistency */
+#define DAC960_NoRebuildOrCheckInProgress 0x0105 /* Consistency */
+#define DAC960_RebuildInProgress_DataValid 0x0000 /* Consistency */
+#define DAC960_RebuildFailed_LogicalDriveFailure 0x0002 /* Consistency */
+#define DAC960_RebuildFailed_BadBlocksOnOther 0x0003 /* Consistency */
+#define DAC960_RebuildFailed_NewDriveFailed 0x0004 /* Consistency */
+#define DAC960_RebuildSuccessful 0x0100 /* Consistency */
+#define DAC960_AddCapacityInProgress 0x0004 /* Consistency */
+#define DAC960_AddCapacityFailedOrSuspended 0x00F4 /* Consistency */
+#define DAC960_Config2ChecksumError 0x0002 /* Configuration */
+#define DAC960_ConfigurationSuspended 0x0106 /* Configuration */
+#define DAC960_FailedToConfigureNVRAM 0x0105 /* Configuration */
+#define DAC960_ConfigurationNotSavedStateChange 0x0106 /* Configuration */
+#define DAC960_SubsystemNotInstalled 0x0001 /* Subsystem */
+#define DAC960_SubsystemFailed 0x0002 /* Subsystem */
+#define DAC960_SubsystemBusy 0x0106 /* Subsystem */
+
+typedef unsigned short DAC960_CommandStatus_T;
+
+
+/*
+ Define the Enquiry reply structure.
+*/
+
+typedef struct DAC960_Enquiry
+{
+ unsigned char NumberOfLogicalDrives; /* Byte 0 */
+ unsigned int :24; /* Bytes 1-3 */
+ unsigned int LogicalDriveSizes[32]; /* Bytes 4-131 */
+ unsigned short FlashAge; /* Bytes 132-133 */
+ struct {
+ boolean DeferredWriteError:1; /* Byte 134 Bit 0 */
+ boolean BatteryLow:1; /* Byte 134 Bit 1 */
+ unsigned char :6; /* Byte 134 Bits 2-7 */
+ } StatusFlags;
+ unsigned char :8; /* Byte 135 */
+ unsigned char MinorFirmwareVersion; /* Byte 136 */
+ unsigned char MajorFirmwareVersion; /* Byte 137 */
+ enum {
+ DAC960_NoStandbyRebuildOrCheckInProgress = 0x00,
+ DAC960_StandbyRebuildInProgress = 0x01,
+ DAC960_BackgroundRebuildInProgress = 0x02,
+ DAC960_BackgroundCheckInProgress = 0x03,
+ DAC960_StandbyRebuildCOmpletedWithError = 0xFF,
+ DAC960_BackgroundRebuildOrCheckFailed_DriveFailed = 0xF0,
+ DAC960_BackgroundRebuildOrCheckFailed_LogicalDriveFailed = 0xF1,
+ DAC960_BackgroundRebuildOrCheckFailed_OtherCauses = 0xF2,
+ DAC960_BackgroundRebuildOrCheckSuccessfullyTerminated = 0xF3
+ } __attribute__ ((packed)) RebuildFlag; /* Byte 138 */
+ unsigned char MaxCommands; /* Byte 139 */
+ unsigned char OfflineLogicalDriveCount; /* Byte 140 */
+ unsigned char :8; /* Byte 141 */
+ unsigned short EventLogSequenceNumber; /* Bytes 142-143 */
+ unsigned char CriticalLogicalDriveCount; /* Byte 144 */
+ unsigned int :24; /* Bytes 145-147 */
+ unsigned char DeadDriveCount; /* Byte 148 */
+ unsigned char :8; /* Byte 149 */
+ unsigned char RebuildCount; /* Byte 150 */
+ struct {
+ unsigned char :3; /* Byte 151 Bits 0-2 */
+ boolean BatteryBackupUnitPresent:1; /* Byte 151 Bit 3 */
+ unsigned char :3; /* Byte 151 Bits 4-6 */
+ unsigned char :1; /* Byte 151 Bit 7 */
+ } MiscFlags;
+ struct {
+ unsigned char TargetID;
+ unsigned char Channel;
+ } DeadDrives[21]; /* Bytes 152-194 */
+ unsigned char Reserved[62]; /* Bytes 195-255 */
+}
+__attribute__ ((packed))
+DAC960_Enquiry_T;
+
+
+/*
+ Define the Enquiry2 reply structure.
+*/
+
+typedef struct DAC960_Enquiry2
+{
+ struct {
+ enum {
+ DAC960_P_PD_PU = 0x01,
+ DAC960_PL = 0x02,
+ DAC960_PG = 0x10,
+ DAC960_PJ = 0x11,
+ DAC960_PTL_0 = 0x14,
+ DAC960_PTL_1 = 0x16
+ } __attribute__ ((packed)) SubModel; /* Byte 0 */
+ unsigned char ActualChannels; /* Byte 1 */
+ enum {
+ DAC960_FiveChannelBoard = 0x01,
+ DAC960_ThreeChannelBoard = 0x02,
+ DAC960_TwoChannelBoard = 0x03,
+ DAC960_ThreeChannelASIC_DAC = 0x04
+ } __attribute__ ((packed)) Model; /* Byte 2 */
+ enum {
+ DAC960_EISA_Controller = 0x01,
+ DAC960_MicroChannel_Controller = 0x02,
+ DAC960_PCI_Controller = 0x03,
+ DAC960_SCSItoSCSI_Controller = 0x08
+ } __attribute__ ((packed)) ProductFamily; /* Byte 3 */
+ } HardwareID; /* Bytes 0-3 */
+ /* MajorVersion.MinorVersion-FirmwareType-TurnID */
+ struct {
+ unsigned char MajorVersion; /* Byte 4 */
+ unsigned char MinorVersion; /* Byte 5 */
+ unsigned char TurnID; /* Byte 6 */
+ char FirmwareType; /* Byte 7 */
+ } FirmwareID; /* Bytes 4-7 */
+ unsigned char :8; /* Byte 8 */
+ unsigned int :24; /* Bytes 9-11 */
+ unsigned char ConfiguredChannels; /* Byte 12 */
+ unsigned char ActualChannels; /* Byte 13 */
+ unsigned char MaxTargets; /* Byte 14 */
+ unsigned char MaxTags; /* Byte 15 */
+ unsigned char MaxLogicalDrives; /* Byte 16 */
+ unsigned char MaxArms; /* Byte 17 */
+ unsigned char MaxSpans; /* Byte 18 */
+ unsigned char :8; /* Byte 19 */
+ unsigned int :32; /* Bytes 20-23 */
+ unsigned int MemorySize; /* Bytes 24-27 */
+ unsigned int CacheSize; /* Bytes 28-31 */
+ unsigned int FlashMemorySize; /* Bytes 32-35 */
+ unsigned int NonVolatileMemorySize; /* Bytes 36-39 */
+ struct {
+ enum {
+ DAC960_DRAM = 0x00,
+ DAC960_EDO = 0x01
+ } __attribute__ ((packed)) RamType:3; /* Byte 40 Bits 0-2 */
+ enum {
+ DAC960_None = 0x00,
+ DAC960_Parity = 0x01,
+ DAC960_ECC = 0x02
+ } __attribute__ ((packed)) ErrorCorrection:3; /* Byte 40 Bits 3-5 */
+ boolean FastPageMode:1; /* Byte 40 Bit 6 */
+ boolean LowPowerMemory:1; /* Byte 40 Bit 7 */
+ unsigned char :8; /* Bytes 41 */
+ } MemoryType;
+ unsigned short ClockSpeed; /* Bytes 42-43 */
+ unsigned short MemorySpeed; /* Bytes 44-45 */
+ unsigned short HardwareSpeed; /* Bytes 46-47 */
+ unsigned int :32; /* Bytes 48-51 */
+ unsigned int :32; /* Bytes 52-55 */
+ unsigned char :8; /* Byte 56 */
+ unsigned char :8; /* Byte 57 */
+ unsigned short :16; /* Bytes 58-59 */
+ unsigned short MaxCommands; /* Bytes 60-61 */
+ unsigned short MaxScatterGatherEntries; /* Bytes 62-63 */
+ unsigned short MaxDriveCommands; /* Bytes 64-65 */
+ unsigned short MaxIODescriptors; /* Bytes 66-67 */
+ unsigned short MaxCombinedSectors; /* Bytes 68-69 */
+ unsigned char Latency; /* Byte 70 */
+ unsigned char :8; /* Byte 71 */
+ unsigned char SCSITimeout; /* Byte 72 */
+ unsigned char :8; /* Byte 73 */
+ unsigned short MinFreeLines; /* Bytes 74-75 */
+ unsigned int :32; /* Bytes 76-79 */
+ unsigned int :32; /* Bytes 80-83 */
+ unsigned char RebuildRateConstant; /* Byte 84 */
+ unsigned char :8; /* Byte 85 */
+ unsigned char :8; /* Byte 86 */
+ unsigned char :8; /* Byte 87 */
+ unsigned int :32; /* Bytes 88-91 */
+ unsigned int :32; /* Bytes 92-95 */
+ unsigned short PhysicalDriveBlockSize; /* Bytes 96-97 */
+ unsigned short LogicalDriveBlockSize; /* Bytes 98-99 */
+ unsigned short MaxBlocksPerCommand; /* Bytes 100-101 */
+ unsigned short BlockFactor; /* Bytes 102-103 */
+ unsigned short CacheLineSize; /* Bytes 104-105 */
+ struct {
+ enum {
+ DAC960_Narrow_8bit = 0x00,
+ DAC960_Wide_16bit = 0x01,
+ DAC960_Wide_32bit = 0x02
+ } __attribute__ ((packed)) BusWidth:2; /* Byte 106 Bits 0-1 */
+ enum {
+ DAC960_Fast = 0x00,
+ DAC960_Ultra = 0x01,
+ } __attribute__ ((packed)) BusSpeed:2; /* Byte 106 Bits 2-3 */
+ boolean Differential:1; /* Byte 106 Bit 4 */
+ unsigned char :3; /* Byte 106 Bits 5-7 */
+ } SCSICapability;
+ unsigned char :8; /* Byte 107 */
+ unsigned int :32; /* Bytes 108-111 */
+ unsigned short FirmwareBuildNumber; /* Bytes 112-113 */
+ enum {
+ DAC960_AEMI = 0x01,
+ DAC960_OEM1 = 0x02,
+ DAC960_OEM2 = 0x04,
+ DAC960_OEM3 = 0x08,
+ DAC960_Conner = 0x10,
+ DAC960_SAFTE = 0x20
+ } __attribute__ ((packed)) FaultManagementType; /* Byte 114 */
+ unsigned char :8; /* Byte 115 */
+ struct {
+ boolean Clustering:1; /* Byte 116 Bit 0 */
+ boolean MylexOnlineRAIDExpansion:1; /* Byte 116 Bit 1 */
+ unsigned int :30; /* Bytes 116-119 */
+ } FirmwareFeatures;
+ unsigned int :32; /* Bytes 120-123 */
+ unsigned int :32; /* Bytes 124-127 */
+}
+DAC960_Enquiry2_T;
+
+
+/*
+ Define the Get Logical Drive Information reply structure.
+*/
+
+typedef struct DAC960_LogicalDriveInformation
+{
+ unsigned int LogicalDriveSize; /* Bytes 0-3 */
+ enum {
+ DAC960_LogicalDrive_Online = 0x03,
+ DAC960_LogicalDrive_Critical = 0x04,
+ DAC960_LogicalDrive_Offline = 0xFF
+ } __attribute__ ((packed)) LogicalDriveState; /* Byte 4 */
+ unsigned char RAIDLevel:7; /* Byte 5 Bits 0-6 */
+ boolean WriteBack:1; /* Byte 5 Bit 7 */
+ unsigned int :16; /* Bytes 6-7 */
+}
+DAC960_LogicalDriveInformation_T;
+
+
+/*
+ Define the Perform Event Log Operation Types.
+*/
+
+typedef enum
+{
+ DAC960_GetEventLogEntry = 0x00
+}
+__attribute__ ((packed))
+DAC960_PerformEventLogOpType_T;
+
+
+/*
+ Define the Get Event Log Entry reply structure.
+*/
+
+typedef struct DAC960_EventLogEntry
+{
+ unsigned char MessageType; /* Byte 0 */
+ unsigned char MessageLength; /* Byte 1 */
+ unsigned char TargetID:5; /* Byte 2 Bits 0-4 */
+ unsigned char Channel:3; /* Byte 2 Bits 5-7 */
+ unsigned char LogicalUnit:6; /* Byte 3 Bits 0-5 */
+ unsigned char :2; /* Byte 3 Bits 6-7 */
+ unsigned short SequenceNumber; /* Bytes 4-5 */
+ unsigned char ErrorCode:7; /* Byte 6 Bits 0-6 */
+ boolean Valid:1; /* Byte 6 Bit 7 */
+ unsigned char SegmentNumber; /* Byte 7 */
+ unsigned char SenseKey:4; /* Byte 8 Bits 0-3 */
+ unsigned char :1; /* Byte 8 Bit 4 */
+ boolean ILI:1; /* Byte 8 Bit 5 */
+ boolean EOM:1; /* Byte 8 Bit 6 */
+ boolean Filemark:1; /* Byte 8 Bit 7 */
+ unsigned char Information[4]; /* Bytes 9-12 */
+ unsigned char AdditionalSenseLength; /* Byte 13 */
+ unsigned char CommandSpecificInformation[4]; /* Bytes 14-17 */
+ unsigned char AdditionalSenseCode; /* Byte 18 */
+ unsigned char AdditionalSenseCodeQualifier; /* Byte 19 */
+ unsigned char Dummy[12]; /* Bytes 20-31 */
+}
+DAC960_EventLogEntry_T;
+
+#define DAC960_EventMessagesCount 13
+
+static char
+ *DAC960_EventMessages[DAC960_EventMessagesCount] =
+ { "killed because write recovery failed",
+ "killed because of SCSI bus reset failure",
+ "killed because of double check condition",
+ "killed because it was removed",
+ "killed because of gross error on SCSI chip",
+ "killed because of bad tag returned from drive",
+ "killed because of timeout on SCSI command",
+ "killed because of reset SCSI command issued from system",
+ "killed because busy or parity error count exceeded limit",
+ "killed because of 'kill drive' command from system",
+ "killed because of selection timeout",
+ "killed due to SCSI phase sequence error",
+ "killed due to unknown status" };
+
+
+/*
+ Define the Get Device State reply structure.
+*/
+
+typedef struct DAC960_DeviceState
+{
+ boolean Present:1; /* Byte 0 Bit 0 */
+ unsigned char :7; /* Byte 0 Bits 1-7 */
+ enum {
+ DAC960_OtherType = 0x00,
+ DAC960_DiskType = 0x01,
+ DAC960_SequentialType = 0x02,
+ DAC960_CDROM_or_WORM_Type = 0x03
+ } __attribute__ ((packed)) DeviceType:2; /* Byte 1 Bits 0-1 */
+ boolean :1; /* Byte 1 Bit 2 */
+ boolean Fast20:1; /* Byte 1 Bit 3 */
+ boolean Sync:1; /* Byte 1 Bit 4 */
+ boolean Fast:1; /* Byte 1 Bit 5 */
+ boolean Wide:1; /* Byte 1 Bit 6 */
+ boolean TaggedQueuingSupported:1; /* Byte 1 Bit 7 */
+ enum {
+ DAC960_Device_Dead = 0x00,
+ DAC960_Device_WriteOnly = 0x02,
+ DAC960_Device_Online = 0x03,
+ DAC960_Device_Standby = 0x10
+ } __attribute__ ((packed)) DeviceState; /* Byte 2 */
+ unsigned char :8; /* Byte 3 */
+ unsigned char SynchronousMultiplier; /* Byte 4 */
+ unsigned char SynchronousOffset:5; /* Byte 5 Bits 0-4 */
+ unsigned char :3; /* Byte 5 Bits 5-7 */
+ unsigned long DiskSize __attribute__ ((packed)); /* Bytes 6-9 */
+}
+DAC960_DeviceState_T;
+
+
+/*
+ Define the Get Rebuild Progress reply structure.
+*/
+
+typedef struct DAC960_RebuildProgress
+{
+ unsigned int LogicalDriveNumber; /* Bytes 0-3 */
+ unsigned int LogicalDriveSize; /* Bytes 4-7 */
+ unsigned int RemainingBlocks; /* Bytes 8-11 */
+}
+DAC960_RebuildProgress_T;
+
+
+/*
+ Define the Config2 reply structure.
+*/
+
+typedef struct DAC960_Config2
+{
+ unsigned char :1; /* Byte 0 Bit 0 */
+ boolean ActiveNegationEnabled:1; /* Byte 0 Bit 1 */
+ unsigned char :5; /* Byte 0 Bits 2-6 */
+ boolean NoRescanIfResetReceivedDuringScan:1; /* Byte 0 Bit 7 */
+ boolean StorageWorksSupportEnabled:1; /* Byte 1 Bit 0 */
+ boolean HewlettPackardSupportEnabled:1; /* Byte 1 Bit 1 */
+ boolean NoDisconnectOnFirstCommand:1; /* Byte 1 Bit 2 */
+ unsigned char :2; /* Byte 1 Bits 3-4 */
+ boolean AEMI_ARM:1; /* Byte 1 Bit 5 */
+ boolean AEMI_OFM:1; /* Byte 1 Bit 6 */
+ unsigned char :1; /* Byte 1 Bit 7 */
+ enum {
+ DAC960_OEMID_Mylex = 0x00,
+ DAC960_OEMID_IBM = 0x08,
+ DAC960_OEMID_HP = 0x0A,
+ DAC960_OEMID_DEC = 0x0C,
+ DAC960_OEMID_Siemens = 0x10,
+ DAC960_OEMID_Intel = 0x12
+ } __attribute__ ((packed)) OEMID; /* Byte 2 */
+ unsigned char OEMModelNumber; /* Byte 3 */
+ unsigned char PhysicalSector; /* Byte 4 */
+ unsigned char LogicalSector; /* Byte 5 */
+ unsigned char BlockFactor; /* Byte 6 */
+ boolean ReadAheadEnabled:1; /* Byte 7 Bit 0 */
+ boolean LowBIOSDelay:1; /* Byte 7 Bit 1 */
+ unsigned char :2; /* Byte 7 Bits 2-3 */
+ boolean ReassignRestrictedToOneSector:1; /* Byte 7 Bit 4 */
+ unsigned char :1; /* Byte 7 Bit 5 */
+ boolean ForceUnitAccessDuringWriteRecovery:1; /* Byte 7 Bit 6 */
+ boolean EnableLeftSymmetricRAID5Algorithm:1; /* Byte 7 Bit 7 */
+ unsigned char DefaultRebuildRate; /* Byte 8 */
+ unsigned char :8; /* Byte 9 */
+ unsigned char BlocksPerCacheLine; /* Byte 10 */
+ unsigned char BlocksPerStripe; /* Byte 11 */
+ struct {
+ enum {
+ DAC960_Async = 0x00,
+ DAC960_Sync_8MHz = 0x01,
+ DAC960_Sync_5MHz = 0x02,
+ DAC960_Sync_10or20MHz = 0x03 /* Bits 0-1 */
+ } __attribute__ ((packed)) Speed:2;
+ boolean Force8Bit:1; /* Bit 2 */
+ boolean DisableFast20:1; /* Bit 3 */
+ unsigned char :3; /* Bits 4-6 */
+ boolean EnableTaggedQueuing:1; /* Bit 7 */
+ } __attribute__ ((packed)) ChannelParameters[6]; /* Bytes 12-17 */
+ unsigned char SCSIInitiatorID; /* Byte 18 */
+ unsigned char :8; /* Byte 19 */
+ enum {
+ DAC960_StartupMode_ControllerSpinUp = 0x00,
+ DAC960_StartupMode_PowerOnSpinUp = 0x01
+ } __attribute__ ((packed)) StartupMode; /* Byte 20 */
+ unsigned char SimultaneousDeviceSpinUpCount; /* Byte 21 */
+ unsigned char SecondsDelayBetweenSpinUps; /* Byte 22 */
+ unsigned char Reserved1[29]; /* Bytes 23-51 */
+ boolean BIOSDisabled:1; /* Byte 52 Bit 0 */
+ boolean CDROMBootEnabled:1; /* Byte 52 Bit 1 */
+ unsigned char :3; /* Byte 52 Bits 2-4 */
+ enum {
+ DAC960_Geometry_128_32 = 0x00,
+ DAC960_Geometry_255_63 = 0x01,
+ DAC960_Geometry_Reserved1 = 0x02,
+ DAC960_Geometry_Reserved2 = 0x03
+ } __attribute__ ((packed)) DriveGeometry:2; /* Byte 52 Bits 5-6 */
+ unsigned char :1; /* Byte 52 Bit 7 */
+ unsigned char Reserved2[9]; /* Bytes 53-61 */
+ unsigned short Checksum; /* Bytes 62-63 */
+}
+DAC960_Config2_T;
+
+
+/*
+ Define the Scatter/Gather List Type 1 32 Bit Address 32 Bit Byte Count
+ structure.
+*/
+
+typedef struct DAC960_ScatterGatherSegment
+{
+ DAC960_BusAddress_T SegmentDataPointer; /* Bytes 0-3 */
+ DAC960_ByteCount_T SegmentByteCount; /* Bytes 4-7 */
+}
+DAC960_ScatterGatherSegment_T;
+
+
+/*
+ Define the 13 Byte DAC960 Command Mailbox structure. Bytes 13-15 are
+ not used. The Command Mailbox structure is padded to 16 bytes for
+ efficient access.
+*/
+
+typedef union DAC960_CommandMailbox
+{
+ unsigned int Words[4]; /* Words 0-3 */
+ unsigned char Bytes[16]; /* Bytes 0-15 */
+ struct {
+ DAC960_CommandOpcode_T CommandOpcode; /* Byte 0 */
+ DAC960_CommandIdentifier_T CommandIdentifier; /* Byte 1 */
+ unsigned char Dummy[14]; /* Bytes 2-15 */
+ } __attribute__ ((packed)) Common;
+ struct {
+ DAC960_CommandOpcode_T CommandOpcode; /* Byte 0 */
+ DAC960_CommandIdentifier_T CommandIdentifier; /* Byte 1 */
+ unsigned char Dummy1[6]; /* Bytes 2-7 */
+ DAC960_BusAddress_T BusAddress; /* Bytes 8-11 */
+ unsigned char Dummy2[4]; /* Bytes 12-15 */
+ } __attribute__ ((packed)) Type3;
+ struct {
+ DAC960_CommandOpcode_T CommandOpcode; /* Byte 0 */
+ DAC960_CommandIdentifier_T CommandIdentifier; /* Byte 1 */
+ unsigned char Channel; /* Byte 2 */
+ unsigned char TargetID; /* Byte 3 */
+ unsigned char Dummy1[4]; /* Bytes 4-7 */
+ DAC960_BusAddress_T BusAddress; /* Bytes 8-11 */
+ unsigned char Dummy2[4]; /* Bytes 12-15 */
+ } __attribute__ ((packed)) Type3D;
+ struct {
+ DAC960_CommandOpcode_T CommandOpcode; /* Byte 0 */
+ DAC960_CommandIdentifier_T CommandIdentifier; /* Byte 1 */
+ DAC960_PerformEventLogOpType_T OperationType; /* Byte 2 */
+ unsigned char OperationQualifier; /* Byte 3 */
+ unsigned short SequenceNumber; /* Bytes 4-5 */
+ unsigned char Dummy1[2]; /* Bytes 6-7 */
+ DAC960_BusAddress_T BusAddress; /* Bytes 8-11 */
+ unsigned char Dummy2[4]; /* Bytes 12-15 */
+ } __attribute__ ((packed)) Type3E;
+ struct {
+ DAC960_CommandOpcode_T CommandOpcode; /* Byte 0 */
+ DAC960_CommandIdentifier_T CommandIdentifier; /* Byte 1 */
+ struct {
+ unsigned short TransferLength:11; /* Bytes 2-3 */
+ unsigned char LogicalDriveNumber:5; /* Byte 3 Bits 3-7 */
+ } __attribute__ ((packed)) LD;
+ unsigned int LogicalBlockAddress; /* Bytes 4-7 */
+ DAC960_BusAddress_T BusAddress; /* Bytes 8-11 */
+ unsigned char ScatterGatherCount:6; /* Byte 12 Bits 0-5 */
+ enum {
+ DAC960_ScatterGather_32BitAddress_32BitByteCount = 0x0,
+ DAC960_ScatterGather_32BitAddress_16BitByteCount = 0x1,
+ DAC960_ScatterGather_32BitByteCount_32BitAddress = 0x2,
+ DAC960_ScatterGather_16BitByteCount_32BitAddress = 0x3
+ } __attribute__ ((packed)) ScatterGatherType:2; /* Byte 12 Bits 6-7 */
+ unsigned char Dummy[3]; /* Bytes 13-15 */
+ } __attribute__ ((packed)) Type5;
+ struct {
+ DAC960_CommandOpcode_T CommandOpcode; /* Byte 0 */
+ DAC960_CommandIdentifier_T CommandIdentifier; /* Byte 1 */
+ unsigned char CommandOpcode2; /* Byte 2 */
+ unsigned char :8; /* Byte 3 */
+ DAC960_BusAddress_T CommandMailboxesBusAddress; /* Bytes 4-7 */
+ DAC960_BusAddress_T StatusMailboxesBusAddress; /* Bytes 8-11 */
+ unsigned char Dummy[4]; /* Bytes 12-15 */
+ } __attribute__ ((packed)) TypeX;
+}
+DAC960_CommandMailbox_T;
+
+
+/*
+ Define the DAC960 V4 Controller Command Mailbox structure.
+*/
+
+typedef DAC960_CommandMailbox_T DAC960_V4_CommandMailbox_T;
+
+
+/*
+ Define the DAC960 V4 Controller Status Mailbox structure.
+*/
+
+typedef union DAC960_V4_StatusMailbox
+{
+ unsigned int Word; /* Bytes 0-3 */
+ struct {
+ DAC960_CommandIdentifier_T CommandIdentifier; /* Byte 0 */
+ unsigned char :7; /* Byte 1 Bits 0-6 */
+ boolean Valid:1; /* Byte 1 Bit 7 */
+ DAC960_CommandStatus_T CommandStatus; /* Bytes 2-3 */
+ } Fields;
+}
+DAC960_V4_StatusMailbox_T;
+
+
+/*
+ Define the DAC960 Driver Command Types.
+*/
+
+typedef enum
+{
+ DAC960_ReadCommand = 1,
+ DAC960_WriteCommand = 2,
+ DAC960_ReadRetryCommand = 3,
+ DAC960_WriteRetryCommand = 4,
+ DAC960_MonitoringCommand = 5,
+ DAC960_ImmediateCommand = 6
+}
+DAC960_CommandType_T;
+
+
+/*
+ Define the DAC960 Driver Command structure.
+*/
+
+typedef struct DAC960_Command
+{
+ DAC960_CommandType_T CommandType;
+ DAC960_CommandMailbox_T CommandMailbox;
+ DAC960_CommandStatus_T CommandStatus;
+ struct DAC960_Controller *Controller;
+ struct DAC960_Command *Next;
+ Semaphore_T *Semaphore;
+ unsigned int LogicalDriveNumber;
+ unsigned int BlockNumber;
+ unsigned int BlockCount;
+ unsigned int SegmentCount;
+ BufferHeader_T *BufferHeader;
+ DAC960_ScatterGatherSegment_T
+ ScatterGatherList[DAC960_MaxScatterGatherSegments];
+}
+DAC960_Command_T;
+
+
+/*
+ Define the DAC960 Driver Controller structure.
+*/
+
+typedef struct DAC960_Controller
+{
+ void *BaseAddress;
+ void *MemoryMappedAddress;
+ DAC960_ControllerType_T ControllerType;
+ DAC960_IO_Address_T IO_Address;
+ DAC960_PCI_Address_T PCI_Address;
+ unsigned char ControllerNumber;
+ unsigned char ModelName[12];
+ unsigned char FullModelName[18];
+ unsigned char FirmwareVersion[14];
+ unsigned char Bus;
+ unsigned char Device;
+ unsigned char Function;
+ unsigned char IRQ_Channel;
+ unsigned char Channels;
+ unsigned char MemorySize;
+ unsigned char LogicalDriveCount;
+ unsigned char GeometryTranslationHeads;
+ unsigned char GeometryTranslationSectors;
+ unsigned short ControllerQueueDepth;
+ unsigned short DriverQueueDepth;
+ unsigned short MaxBlocksPerCommand;
+ unsigned short MaxScatterGatherSegments;
+ unsigned short StripeSize;
+ unsigned short SegmentSize;
+ unsigned short NewEventLogSequenceNumber;
+ unsigned short OldEventLogSequenceNumber;
+ unsigned short MessageBufferLength;
+ unsigned int ControllerUsageCount;
+ unsigned int EnquiryIndex;
+ unsigned int LogicalDriveInformationIndex;
+ unsigned int DeviceStateIndex;
+ unsigned int DeviceStateChannel;
+ unsigned int DeviceStateTargetID;
+ unsigned long SecondaryMonitoringTime;
+ unsigned long RebuildLastReportTime;
+ boolean SAFTE_FaultManagementEnabled;
+ boolean MonitoringCommandDeferred;
+ boolean NeedLogicalDriveInformation;
+ boolean NeedDeviceStateInformation;
+ boolean NeedRebuildProgress;
+ GenericDiskInfo_T GenericDiskInfo;
+ Timer_T MonitoringTimer;
+ DAC960_Command_T *FreeCommands;
+ DAC960_V4_CommandMailbox_T *FirstCommandMailbox;
+ DAC960_V4_CommandMailbox_T *LastCommandMailbox;
+ DAC960_V4_CommandMailbox_T *NextCommandMailbox;
+ DAC960_V4_CommandMailbox_T *PreviousCommandMailbox;
+ DAC960_V4_StatusMailbox_T *FirstStatusMailbox;
+ DAC960_V4_StatusMailbox_T *LastStatusMailbox;
+ DAC960_V4_StatusMailbox_T *NextStatusMailbox;
+ DAC960_Enquiry_T Enquiry[2];
+ DAC960_LogicalDriveInformation_T
+ LogicalDriveInformation[2][DAC960_MaxLogicalDrives];
+ DAC960_DeviceState_T DeviceState[2][DAC960_MaxChannels][DAC960_MaxTargets];
+ DAC960_EventLogEntry_T EventLogEntry;
+ DAC960_RebuildProgress_T RebuildProgress;
+ DAC960_Command_T Commands[DAC960_MaxDriverQueueDepth];
+ DiskPartition_T DiskPartitions[DAC960_MinorCount];
+ int LogicalDriveUsageCount[DAC960_MaxLogicalDrives];
+ int PartitionSizes[DAC960_MinorCount];
+ int BlockSizes[DAC960_MinorCount];
+ int MaxSectorsPerRequest[DAC960_MinorCount];
+ int MaxSegmentsPerRequest[DAC960_MinorCount];
+ char MessageBuffer[DAC960_MessageBufferSize];
+}
+DAC960_Controller_T;
+
+
+/*
+ DAC960_AcquireControllerLock acquires exclusive access to Controller.
+*/
+
+static inline
+void DAC960_AcquireControllerLock(DAC960_Controller_T *Controller,
+ ProcessorFlags_T *ProcessorFlags)
+{
+ save_flags(*ProcessorFlags);
+ cli();
+}
+
+
+/*
+ DAC960_ReleaseControllerLock releases exclusive access to Controller.
+*/
+
+static inline
+void DAC960_ReleaseControllerLock(DAC960_Controller_T *Controller,
+ ProcessorFlags_T *ProcessorFlags)
+{
+ restore_flags(*ProcessorFlags);
+}
+
+
+/*
+ DAC960_AcquireControllerLockRF acquires exclusive access to Controller,
+ but is only called from the request function when interrupts are disabled.
+*/
+
+static inline
+void DAC960_AcquireControllerLockRF(DAC960_Controller_T *Controller,
+ ProcessorFlags_T *ProcessorFlags)
+{
+}
+
+
+/*
+ DAC960_ReleaseControllerLockRF releases exclusive access to Controller,
+ but is only called from the request function when interrupts are disabled.
+*/
+
+static inline
+void DAC960_ReleaseControllerLockRF(DAC960_Controller_T *Controller,
+ ProcessorFlags_T *ProcessorFlags)
+{
+}
+
+
+/*
+ DAC960_AcquireControllerLockIH acquires exclusive access to Controller,
+ but is only called from the interrupt handler when interrupts are disabled.
+*/
+
+static inline
+void DAC960_AcquireControllerLockIH(DAC960_Controller_T *Controller,
+ ProcessorFlags_T *ProcessorFlags)
+{
+}
+
+
+/*
+ DAC960_ReleaseControllerLockIH releases exclusive access to Controller,
+ but is only called from the interrupt handler when interrupts are disabled.
+*/
+
+static inline
+void DAC960_ReleaseControllerLockIH(DAC960_Controller_T *Controller,
+ ProcessorFlags_T *ProcessorFlags)
+{
+}
+
+
+/*
+ Define inline functions to provide an abstraction for reading and writing the
+ DAC960 V4 Controller Interface Registers.
+*/
+
+static inline
+void DAC960_V4_NewCommand(void *ControllerBaseAddress)
+{
+ DAC960_V4_InboundDoorBellRegister_T InboundDoorBellRegister;
+ InboundDoorBellRegister.All = 0;
+ InboundDoorBellRegister.Write.NewCommand = true;
+ writel(InboundDoorBellRegister.All,
+ ControllerBaseAddress + DAC960_V4_InboundDoorBellRegisterOffset);
+}
+
+static inline
+void DAC960_V4_AcknowledgeStatus(void *ControllerBaseAddress)
+{
+ DAC960_V4_InboundDoorBellRegister_T InboundDoorBellRegister;
+ InboundDoorBellRegister.All = 0;
+ InboundDoorBellRegister.Write.AcknowledgeStatus = true;
+ writel(InboundDoorBellRegister.All,
+ ControllerBaseAddress + DAC960_V4_InboundDoorBellRegisterOffset);
+}
+
+static inline
+void DAC960_V4_SoftReset(void *ControllerBaseAddress)
+{
+ DAC960_V4_InboundDoorBellRegister_T InboundDoorBellRegister;
+ InboundDoorBellRegister.All = 0;
+ InboundDoorBellRegister.Write.SoftReset = true;
+ writel(InboundDoorBellRegister.All,
+ ControllerBaseAddress + DAC960_V4_InboundDoorBellRegisterOffset);
+}
+
+static inline
+boolean DAC960_V4_MailboxFullP(void *ControllerBaseAddress)
+{
+ DAC960_V4_InboundDoorBellRegister_T InboundDoorBellRegister;
+ InboundDoorBellRegister.All =
+ readl(ControllerBaseAddress + DAC960_V4_InboundDoorBellRegisterOffset);
+ return InboundDoorBellRegister.Read.MailboxFull;
+}
+
+static inline
+void DAC960_V4_AcknowledgeInterrupt(void *ControllerBaseAddress)
+{
+ DAC960_V4_OutboundDoorBellRegister_T OutboundDoorBellRegister;
+ OutboundDoorBellRegister.All = 0;
+ OutboundDoorBellRegister.Write.AcknowledgeInterrupt = true;
+ writel(OutboundDoorBellRegister.All,
+ ControllerBaseAddress + DAC960_V4_OutboundDoorBellRegisterOffset);
+}
+
+static inline
+boolean DAC960_V4_StatusAvailableP(void *ControllerBaseAddress)
+{
+ DAC960_V4_OutboundDoorBellRegister_T OutboundDoorBellRegister;
+ OutboundDoorBellRegister.All =
+ readl(ControllerBaseAddress + DAC960_V4_OutboundDoorBellRegisterOffset);
+ return OutboundDoorBellRegister.Read.StatusAvailable;
+}
+
+static inline
+void DAC960_V4_EnableInterrupts(void *ControllerBaseAddress)
+{
+ DAC960_V4_InterruptMaskRegister_T InterruptMaskRegister;
+ InterruptMaskRegister.All = 0;
+ InterruptMaskRegister.Bits.MessageUnitInterruptMask1 = 0x3;
+ InterruptMaskRegister.Bits.DisableInterrupts = false;
+ InterruptMaskRegister.Bits.MessageUnitInterruptMask2 = 0x1F;
+ writel(InterruptMaskRegister.All,
+ ControllerBaseAddress + DAC960_V4_InterruptMaskRegisterOffset);
+}
+
+static inline
+void DAC960_V4_DisableInterrupts(void *ControllerBaseAddress)
+{
+ DAC960_V4_InterruptMaskRegister_T InterruptMaskRegister;
+ InterruptMaskRegister.All = 0;
+ InterruptMaskRegister.Bits.MessageUnitInterruptMask1 = 0x3;
+ InterruptMaskRegister.Bits.DisableInterrupts = true;
+ InterruptMaskRegister.Bits.MessageUnitInterruptMask2 = 0x1F;
+ writel(InterruptMaskRegister.All,
+ ControllerBaseAddress + DAC960_V4_InterruptMaskRegisterOffset);
+}
+
+static inline
+boolean DAC960_V4_InterruptsEnabledP(void *ControllerBaseAddress)
+{
+ DAC960_V4_InterruptMaskRegister_T InterruptMaskRegister;
+ InterruptMaskRegister.All =
+ readl(ControllerBaseAddress + DAC960_V4_InterruptMaskRegisterOffset);
+ return !InterruptMaskRegister.Bits.DisableInterrupts;
+}
+
+static inline
+void DAC960_V4_WriteCommandMailbox(DAC960_CommandMailbox_T *NextCommandMailbox,
+ DAC960_CommandMailbox_T *CommandMailbox)
+{
+ NextCommandMailbox->Words[1] = CommandMailbox->Words[1];
+ NextCommandMailbox->Words[2] = CommandMailbox->Words[2];
+ NextCommandMailbox->Words[3] = CommandMailbox->Words[3];
+ NextCommandMailbox->Words[0] = CommandMailbox->Words[0];
+}
+
+static inline
+void DAC960_V4_WriteLegacyCommand(void *ControllerBaseAddress,
+ DAC960_CommandMailbox_T *CommandMailbox)
+{
+ writel(CommandMailbox->Words[0],
+ ControllerBaseAddress + DAC960_V4_CommandOpcodeRegisterOffset);
+ writel(CommandMailbox->Words[1],
+ ControllerBaseAddress + DAC960_V4_MailboxRegister4Offset);
+ writel(CommandMailbox->Words[2],
+ ControllerBaseAddress + DAC960_V4_MailboxRegister8Offset);
+ writeb(CommandMailbox->Bytes[12],
+ ControllerBaseAddress + DAC960_V4_MailboxRegister12Offset);
+}
+
+static inline DAC960_CommandIdentifier_T
+DAC960_V4_ReadStatusCommandIdentifier(void *ControllerBaseAddress)
+{
+ return readb(ControllerBaseAddress
+ + DAC960_V4_StatusCommandIdentifierRegOffset);
+}
+
+static inline DAC960_CommandStatus_T
+DAC960_V4_ReadStatusRegister(void *ControllerBaseAddress)
+{
+ return readw(ControllerBaseAddress + DAC960_V4_StatusRegisterOffset);
+}
+
+
+/*
+ Define inline functions to provide an abstraction for reading and writing the
+ DAC960 V3 Controller Interface Registers.
+*/
+
+static inline
+void DAC960_V3_NewCommand(void *ControllerBaseAddress)
+{
+ DAC960_V3_InboundDoorBellRegister_T InboundDoorBellRegister;
+ InboundDoorBellRegister.All = 0;
+ InboundDoorBellRegister.Write.NewCommand = true;
+ writeb(InboundDoorBellRegister.All,
+ ControllerBaseAddress + DAC960_V3_InboundDoorBellRegisterOffset);
+}
+
+static inline
+void DAC960_V3_AcknowledgeStatus(void *ControllerBaseAddress)
+{
+ DAC960_V3_InboundDoorBellRegister_T InboundDoorBellRegister;
+ InboundDoorBellRegister.All = 0;
+ InboundDoorBellRegister.Write.AcknowledgeStatus = true;
+ writeb(InboundDoorBellRegister.All,
+ ControllerBaseAddress + DAC960_V3_InboundDoorBellRegisterOffset);
+}
+
+static inline
+void DAC960_V3_SoftReset(void *ControllerBaseAddress)
+{
+ DAC960_V3_InboundDoorBellRegister_T InboundDoorBellRegister;
+ InboundDoorBellRegister.All = 0;
+ InboundDoorBellRegister.Write.SoftReset = true;
+ writeb(InboundDoorBellRegister.All,
+ ControllerBaseAddress + DAC960_V3_InboundDoorBellRegisterOffset);
+}
+
+static inline
+boolean DAC960_V3_MailboxFullP(void *ControllerBaseAddress)
+{
+ DAC960_V3_InboundDoorBellRegister_T InboundDoorBellRegister;
+ InboundDoorBellRegister.All =
+ readb(ControllerBaseAddress + DAC960_V3_InboundDoorBellRegisterOffset);
+ return InboundDoorBellRegister.Read.MailboxFull;
+}
+
+static inline
+void DAC960_V3_AcknowledgeInterrupt(void *ControllerBaseAddress)
+{
+ DAC960_V3_OutboundDoorBellRegister_T OutboundDoorBellRegister;
+ OutboundDoorBellRegister.All = 0;
+ OutboundDoorBellRegister.Write.AcknowledgeInterrupt = true;
+ writeb(OutboundDoorBellRegister.All,
+ ControllerBaseAddress + DAC960_V3_OutboundDoorBellRegisterOffset);
+}
+
+static inline
+boolean DAC960_V3_StatusAvailableP(void *ControllerBaseAddress)
+{
+ DAC960_V3_OutboundDoorBellRegister_T OutboundDoorBellRegister;
+ OutboundDoorBellRegister.All =
+ readb(ControllerBaseAddress + DAC960_V3_OutboundDoorBellRegisterOffset);
+ return OutboundDoorBellRegister.Read.StatusAvailable;
+}
+
+static inline
+void DAC960_V3_EnableInterrupts(void *ControllerBaseAddress)
+{
+ DAC960_V3_InterruptEnableRegister_T InterruptEnableRegister;
+ InterruptEnableRegister.All = 0;
+ InterruptEnableRegister.Bits.EnableInterrupts = true;
+ writeb(InterruptEnableRegister.All,
+ ControllerBaseAddress + DAC960_V3_InterruptEnableRegisterOffset);
+}
+
+static inline
+void DAC960_V3_DisableInterrupts(void *ControllerBaseAddress)
+{
+ DAC960_V3_InterruptEnableRegister_T InterruptEnableRegister;
+ InterruptEnableRegister.All = 0;
+ InterruptEnableRegister.Bits.EnableInterrupts = false;
+ writeb(InterruptEnableRegister.All,
+ ControllerBaseAddress + DAC960_V3_InterruptEnableRegisterOffset);
+}
+
+static inline
+boolean DAC960_V3_InterruptsEnabledP(void *ControllerBaseAddress)
+{
+ DAC960_V3_InterruptEnableRegister_T InterruptEnableRegister;
+ InterruptEnableRegister.All =
+ readb(ControllerBaseAddress + DAC960_V3_InterruptEnableRegisterOffset);
+ return InterruptEnableRegister.Bits.EnableInterrupts;
+}
+
+static inline
+void DAC960_V3_WriteCommandMailbox(void *ControllerBaseAddress,
+ DAC960_CommandMailbox_T *CommandMailbox)
+{
+ writel(CommandMailbox->Words[0],
+ ControllerBaseAddress + DAC960_V3_CommandOpcodeRegisterOffset);
+ writel(CommandMailbox->Words[1],
+ ControllerBaseAddress + DAC960_V3_MailboxRegister4Offset);
+ writel(CommandMailbox->Words[2],
+ ControllerBaseAddress + DAC960_V3_MailboxRegister8Offset);
+ writeb(CommandMailbox->Bytes[12],
+ ControllerBaseAddress + DAC960_V3_MailboxRegister12Offset);
+}
+
+static inline DAC960_CommandIdentifier_T
+DAC960_V3_ReadStatusCommandIdentifier(void *ControllerBaseAddress)
+{
+ return readb(ControllerBaseAddress
+ + DAC960_V3_StatusCommandIdentifierRegOffset);
+}
+
+static inline DAC960_CommandStatus_T
+DAC960_V3_ReadStatusRegister(void *ControllerBaseAddress)
+{
+ return readw(ControllerBaseAddress + DAC960_V3_StatusRegisterOffset);
+}
+
+
+/*
+ Virtual_to_Bus and Bus_to_Virtual map between Kernel Virtual Addresses
+ and PCI Bus Addresses.
+*/
+
+static inline DAC960_BusAddress_T Virtual_to_Bus(void *VirtualAddress)
+{
+ return (DAC960_BusAddress_T) virt_to_bus(VirtualAddress);
+}
+
+static inline void *Bus_to_Virtual(DAC960_BusAddress_T BusAddress)
+{
+ return (void *) bus_to_virt(BusAddress);
+}
+
+
+/*
+ Define compatibility macros between Linux 2.0 and Linux 2.1.
+*/
+
+#if LINUX_VERSION_CODE < 0x20100
+
+#define MODULE_PARM(Variable, Type)
+#define ioremap_nocache(Offset, Size) vremap(Offset, Size)
+#define iounmap(Address) vfree(Address)
+
+#endif
+
+
+/*
+ Define prototypes for the forward referenced DAC960 Driver Internal Functions.
+*/
+
+static void DAC960_RequestFunction0(void);
+static void DAC960_RequestFunction1(void);
+static void DAC960_RequestFunction2(void);
+static void DAC960_RequestFunction3(void);
+static void DAC960_RequestFunction4(void);
+static void DAC960_RequestFunction5(void);
+static void DAC960_RequestFunction6(void);
+static void DAC960_RequestFunction7(void);
+static void DAC960_InterruptHandler(int, void *, Registers_T *);
+static void DAC960_QueueMonitoringCommand(DAC960_Command_T *);
+static void DAC960_MonitoringTimerFunction(unsigned long);
+static int DAC960_Open(Inode_T *, File_T *);
+static void DAC960_Release(Inode_T *, File_T *);
+static int DAC960_Ioctl(Inode_T *, File_T *, unsigned int, unsigned long);
+static void DAC960_InitializeGenericDiskInfo(GenericDiskInfo_T *);
+static void DAC960_Message(DAC960_MessageLevel_T, char *,
+ DAC960_Controller_T *, ...);
+
+
+#endif /* DAC960_DriverVersion */
diff -u --recursive --new-file v2.0.36/linux/drivers/block/Makefile linux/drivers/block/Makefile
--- v2.0.36/linux/drivers/block/Makefile Sun Nov 15 10:49:30 1998
+++ linux/drivers/block/Makefile Sun Jun 13 10:21:00 1999
@@ -118,6 +118,10 @@
X endif
X endif
X
+ifeq ($(CONFIG_BLK_DEV_DAC960),y)
+L_OBJS += DAC960.o
+endif
+
X ifeq ($(CONFIG_BLK_DEV_MD),y)
X LX_OBJS += md.o
X
@@ -152,7 +156,15 @@
X M_OBJS += raid5.o
X endif
X endif
+endif
X
+ifeq ($(CONFIG_BLK_CPQ_DA),y)
+L_OBJS += cpqarray.o proc_array.o
+else
+ ifeq ($(CONFIG_BLK_CPQ_DA),m)
+ M_OBJS += cpqarray.o
+ endif
X endif
+
X
X include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.0.36/linux/drivers/block/README.smart2 linux/drivers/block/README.smart2
--- v2.0.36/linux/drivers/block/README.smart2 Wed Dec 31 16:00:00 1969
+++ linux/drivers/block/README.smart2 Sun Jun 13 10:21:00 1999
@@ -0,0 +1,85 @@
+This driver is for Compaq's SMART2 Intellegent Disk Array Controllers.
+
+WARNING:
+--------
+
+This code is distributed without warranty. Use at your own risk.
+
+Installing:
+-----------
+
+You need to build a new kernel to use this device, even if you want to
+use a loadable module. This driver requires Leonard N. Zubkoff's excellent
+patches to ll_rw_blk.c (to controll the number of scatter/gather elements
+sent to lower disk drivers). Visit http://www.dandelion.com/Linux/DAC960.html
+to get his patches.
+
+Apply the patch to a 2.0.36 kernel after applying Leonard's patch:
+
+# cd linux
+# patch -p1 <DAC960.patch
+# patch -p1 <smart2.patch
+
+Then build a new kernel and turn on Compaq SMART2 Disk Array support.
+Create device nodes for the diskarray device:
+
+# mkdev.ida [ctlrs]
+
+Where ctlrs is the number of controllers you have (defaults to 1 if not
+specified).
+
+EISA Controllers:
+-----------------
+
+If you want to use an EISA controller you'll have to turn on EISA support
+and supply some insmod/lilo paramaters. If the driver is compiled into the
+kernel, must give it port/irq data at boot time. For example, if you had
+two SMART-2/E controllers, in EISA slots 1 and 2, on irqs 15 and 5 respectively
+you'd give it a boot argument like this:
+
+ smart2=0x1000,0xf,0x2000,0x5
+
+If you were loading the driver as a module, you'd give load it like this:
+
+ insmod cpqarray.o eisa=0x1000,0xf,0x2000,0x5
+
+You can use EISA and PCI adapters at the same time.
+
+Booting:
+--------
+
+You'll need to use a modified lilo if you want to boot from a disk array.
+Its simply a version of lilo with some code added to tell it how to
+understand Compaq diskarray devices.
+
+Device Naming:
+--------------
+
+You need some entries in /dev for the ida device. The mkdev.ida script
+can make device nodes for you automatically. Currently the device setup
+is as follows:
+
+Major numbers:
+ 72 ida0
+ 73 ida1
+ 74 ida2
+ etc...
+
+Minor numbers:
+ b7 b6 b5 b4 b3 b2 b1 b0
+ |----+----| |----+----|
+ | |
+ | +-------- Partition ID (0=wholedev, 1-15 partition)
+ |
+ +-------------------- Logical Volume number
+
+The suggested device naming scheme is:
+/dev/ida/c0d0 Controller 0, disk 0, whole device
+/dev/ida/c0d0p1 Controller 0, disk 0, partition 1
+/dev/ida/c0d0p2 Controller 0, disk 0, partition 2
+/dev/ida/c0d0p3 Controller 0, disk 0, partition 3
+
+/dev/ida/c1d1 Controller 1, disk 1, whole device
+/dev/ida/c1d1p1 Controller 1, disk 1, partition 1
+/dev/ida/c1d1p2 Controller 1, disk 1, partition 2
+/dev/ida/c1d1p3 Controller 1, disk 1, partition 3
diff -u --recursive --new-file v2.0.36/linux/drivers/block/TODO.smart2 linux/drivers/block/TODO.smart2
--- v2.0.36/linux/drivers/block/TODO.smart2 Wed Dec 31 16:00:00 1969
+++ linux/drivers/block/TODO.smart2 Sun Jun 13 10:21:00 1999
@@ -0,0 +1,20 @@
+Passthrough ioctl (needs testing)
+
+Missing #defines for error codes and bit definitions in arraycmd.h
+Missing structures for health and wellness stuff in arraycmd.h
+
+Online Array config utility for userspace.
+
+Array health monitor for userspace. Perhaps add functionality to use
+the Event Notifier to send health events to a userspace daemon.
+
+Portability: This driver probably doesn't work on Compaq's Alpha hardware.
+
+Performance, Performance, Performance: There just have to be some bottlenecks
+in this driver. I'd like to get some more profiling numbers on things, like
+how often we totally fill the controller's queue, how much stuff sits out on
+the completetion queue and timings on some critical sections of code (the
+intr. handler, the request function, cmd_alloc, etc). The end result being
+that I'm absolutely positive that when the kernel has IO for me, I am not
+letting the controller idle at all.
+
diff -u --recursive --new-file v2.0.36/linux/drivers/block/cpqarray.c linux/drivers/block/cpqarray.c
--- v2.0.36/linux/drivers/block/cpqarray.c Wed Dec 31 16:00:00 1969
+++ linux/drivers/block/cpqarray.c Sun Jun 13 10:21:00 1999
@@ -0,0 +1,1662 @@
+/*
+ * Disk Array driver for Compaq SMART2 Controllers
+ * Copyright 1998 Compaq Computer Corporation


+ *
+ * This program is free software; you can redistribute it and/or modify

+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.


+ *
+ * This program is distributed in the hope that it will be useful,

+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Questions/Comments/Bugfixes to arr...@compaq.com
+ *
+ * If you want to make changes, improve or add functionality to this
+ * driver, you'll probably need the Compaq Array Controller Interface
+ * Specificiation (Document number ECG086/1198)
+ */
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/bios32.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <linux/delay.h>
+#include <linux/major.h>
+#include <linux/fs.h>
+#include <linux/timer.h>
+#include <linux/proc_fs.h>
+#include <linux/hdreg.h>
+#include <asm/io.h>
+#include <asm/bitops.h>
+
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#else
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
+#endif
+
+#define DRIVER_NAME "Compaq SMART2 Driver (v 1.0)"
+
+#define MAJOR_NR COMPAQ_SMART2_MAJOR
+#include <linux/blk.h>
+#include <linux/blkdev.h>
+#include <linux/genhd.h>
+
+#include "cpqarray.h"
+#include "ida_cmd.h"
+#include "ida_ioctl.h"
+
+#define READ_AHEAD 128
+#define NR_CMDS 128 /* This can probably go as high as ~400 */
+
+#define MAX_CTLR 8
+#define CTLR_SHIFT 8
+
+static int nr_ctlr = 0;
+static ctlr_info_t *hba[MAX_CTLR] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+
+#ifdef CONFIG_BLK_CPQ_DA_EISA
+#ifndef MODULE
+static
+#endif
+int eisa[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+#endif
+
+static char *product_names[] = {
+ "Unknown",
+ "SMART-2/E",
+ "SMART-2/P", /* or SMART-2DH */
+ "SMART-2SL",
+ "SMART-3200",
+ "SMART-3100ES",
+ "SMART-221",
+};
+
+static struct hd_struct * ida;
+static int * ida_sizes;
+static int * ida_blocksizes;
+static int * ida_hardsizes;
+static int * ida_maxsectors;
+static int * ida_maxsegments;
+static struct gendisk ida_gendisk[MAX_CTLR];
+
+
+/* Debug... */
+#define DBG(s) s
+/* Debug (general info)... */
+#define DBGINFO(s)
+/* Debug Paranoid... */
+#define DBGP(s) s
+/* Debug Extra Paranoid... */
+#define DBGPX(s)
+
+void cpqarray_init(void);
+#ifdef CONFIG_BLK_CPQ_DA_PCI
+static int cpqarray_pci_detect(void);
+static void cpqarray_pci_init(ctlr_info_t *c, unchar bus, unchar device_fn);
+static ulong remap_pci_mem(ulong base, ulong size);
+#endif
+#ifdef CONFIG_BLK_CPQ_DA_EISA
+static int cpqarray_eisa_detect(void);
+#endif
+static void flushcomplete(int ctlr);
+static int pollcomplete(int ctlr);
+static void getgeometry(int ctlr);
+
+static cmdlist_t * cmd_alloc(ctlr_info_t *h);
+static void cmd_free(ctlr_info_t *h, cmdlist_t *c);
+
+static int sendcmd(
+ __u8 cmd,
+ int ctlr,
+ void *buff,
+ size_t size,
+ unsigned int blk,
+ unsigned int blkcnt,
+ unsigned int log_unit );
+
+static int ida_open(struct inode *inode, struct file *filep);
+static void ida_release(struct inode *inode, struct file *filep);
+static int ida_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, unsigned long arg);
+static int ida_ctlr_ioctl(int ctlr, int dsk, ida_ioctl_t *io);
+
+static void do_ida_request(int i);
+/*
+ * This is a hack. This driver eats a major number for each controller, and
+ * sets blkdev[xxx].request_fn to each one of these so the real request
+ * function knows what controller its working with.
+ */
+#define DO_IDA_REQUEST(x) { \
+ int flags; save_flags(flags); cli(); \
+ do_ida_request(x); restore_flags(flags); }
+
+static void do_ida_request0(void) DO_IDA_REQUEST(0);
+static void do_ida_request1(void) DO_IDA_REQUEST(1);
+static void do_ida_request2(void) DO_IDA_REQUEST(2);
+static void do_ida_request3(void) DO_IDA_REQUEST(3);
+static void do_ida_request4(void) DO_IDA_REQUEST(4);
+static void do_ida_request5(void) DO_IDA_REQUEST(5);
+static void do_ida_request6(void) DO_IDA_REQUEST(6);
+static void do_ida_request7(void) DO_IDA_REQUEST(7);
+
+static void start_io(ctlr_info_t *h);
+
+static inline cmdlist_t *removeQ(cmdlist_t **Qptr, cmdlist_t *c);
+static inline void addQ(cmdlist_t **Qptr, cmdlist_t *c);
+static inline void complete_buffers(struct buffer_head *bh, int ok);
+static inline void complete_command(cmdlist_t *cmd, int timeout);
+
+static void do_ida_intr(int irq, void *dev_id, struct pt_regs * regs);
+static void ida_timer(unsigned long tdata);
+static int frevalidate_logvol(kdev_t dev);
+static int revalidate_logvol(kdev_t dev, int maxusage);
+static int revalidate_allvol(kdev_t dev);
+
+static void ida_procinit(int i);
+static int ida_proc_get_info(char *buffer, char **start, off_t offset, int length, int dp);
+
+/*
+ * These macros control what happens when the driver tries to write to or
+ * read from a card. If the driver is configured for EISA only or PCI only,
+ * the macros expand to inl/outl or readl/writel. If the drive is configured
+ * for both EISA and PCI, the macro expands to a conditional which uses
+ * memory mapped IO if the card has it (PCI) or io ports if it doesn't (EISA).
+ */
+#ifdef CONFIG_BLK_CPQ_DA_PCI
+# ifdef CONFIG_BLK_CPQ_DA_EISA
+# define smart2_read(h, offset) ( ((h)->vaddr) ? readl((h)->vaddr+(offset)) : inl((h)->ioaddr+(offset)) )
+# define smart2_write(p, h, offset) ( ((h)->vaddr) ? writel((p), (h)->vaddr+(offset)) : outl((p), (h)->ioaddr+(offset)) )
+# else
+# define smart2_read(h, offset) readl((h)->vaddr+(offset))
+# define smart2_write(p, h, offset) writel((p), (h)->vaddr+(offset))
+# endif
+#else
+# ifdef CONFIG_BLK_CPQ_DA_EISA
+# define smart2_read(h, offset) inl((h)->vaddr+(offset))
+# define smart2_write(p, h, offset) outl((p), (h)->vaddr+(offset))
+# else
+# error "You must enable either SMART2 PCI support or SMART2 EISA support or both!"
+# endif
+#endif
+
+void ida_geninit(struct gendisk *g)
+{
+ int ctlr = g-ida_gendisk;
+ int i,j;
+ drv_info_t *drv;
+
+ for(i=0; i<NWD; i++) {
+ drv = &hba[ctlr]->drv[i];
+ if (!drv->nr_blks)
+ continue;
+ ida[(ctlr<<CTLR_SHIFT) + (i<<NWD_SHIFT)].nr_sects =
+ ida_sizes[(ctlr<<CTLR_SHIFT) + (i<<NWD_SHIFT)] =
+ drv->nr_blks;
+
+ for(j=0; j<16; j++) {
+ ida_blocksizes[(ctlr<<CTLR_SHIFT) + (i<<NWD_SHIFT)+j] =
+ 1024;
+ ida_hardsizes[(ctlr<<CTLR_SHIFT) + (i<<NWD_SHIFT)+j] =
+ drv->blk_size;
+ }
+ ida_gendisk[ctlr].nr_real++;
+ }
+
+}
+
+struct file_operations ida_fops = {
+ NULL, /* lseek - default */
+ block_read, /* read - general block-dev read */
+ block_write, /* write - general block-dev write */
+ NULL, /* readdir - bad */
+ NULL, /* select */
+ ida_ioctl, /* ioctl */
+ NULL, /* mmap */
+ ida_open, /* open code */
+ ida_release, /* release */
+ block_fsync, /* fsync */
+ NULL, /* fasync */
+ NULL, /* Disk change */
+ frevalidate_logvol, /* revalidate */
+};
+
+
+/*
+ * Get us a file in /proc that says something about each controller. Right
+ * now, we add entries to /proc, but in the future we should probably get
+ * our own subdir in /proc (/proc/array/ida) and put our stuff in there.
+ */
+extern struct inode_operations proc_diskarray_inode_operations;
+struct proc_dir_entry *proc_array = NULL;
+static void ida_procinit(int i)
+{
+ struct proc_dir_entry *pd;
+
+ if (proc_array == NULL) {
+ proc_array = kmalloc(sizeof(struct proc_dir_entry), GFP_KERNEL);
+ if (!proc_array) return;
+ memset(proc_array, 0, sizeof(struct proc_dir_entry));
+ proc_array->namelen = 5;
+ proc_array->name = "array";
+ proc_array->mode = S_IFDIR | S_IRUGO | S_IXUGO;
+ proc_array->nlink = 2;
+ proc_array->uid = 0;
+ proc_array->gid = 0;
+ proc_array->size = 0;
+ proc_array->ops = &proc_dir_inode_operations;
+ proc_register_dynamic(&proc_root, proc_array);
+ }
+
+ pd = kmalloc(sizeof(struct proc_dir_entry), GFP_KERNEL);
+ if (!pd) return;
+ memset(pd, 0, sizeof(struct proc_dir_entry));
+ pd->namelen = 4;
+ pd->name = hba[i]->devname;
+ pd->mode = S_IFREG | S_IRUGO;
+ pd->nlink = 1;
+ pd->uid = 0;
+ pd->gid = 0;
+ pd->size = 0;
+ pd->ops = &proc_diskarray_inode_operations;
+ pd->get_info = ida_proc_get_info;
+
+ hba[i]->proc = (int)pd;
+ proc_register_dynamic(proc_array, pd);
+}
+
+/*
+ * Report information about this controller.
+ */
+static int ida_proc_get_info(char *buffer, char **start, off_t offset, int length, int pd)
+{
+ off_t pos = 0;
+ off_t len = 0;
+ int size, i, ctlr;
+ ctlr_info_t *h;
+ drv_info_t *drv;
+#ifdef CPQ_PROC_PRINT_QUEUES
+ cmdlist_t *c;
+#endif
+
+ for(ctlr=0; ctlr<nr_ctlr; ctlr++)
+ if (hba[ctlr] && hba[ctlr]->proc == pd) break;
+
+
+ if ((h = hba[ctlr]) == NULL)
+ return 0;
+
+ size = sprintf(buffer, "%s: Compaq %s Disk Array Controller\n"
+ " Board ID: %08lx\n"
+ " Firmware Revision: %c%c%c%c\n"
+ " Controller Sig: %08lx\n"
+ " Memory Address: %08lx\n"
+ " I/O Port: %04x\n"
+ " IRQ: %x\n"
+ " Logical drives: %d\n"
+ " Physical drives: %d\n\n"
+ " Current Q depth: %d\n"
+ " Max Q depth since init: %d\n\n",
+ h->devname,
+ product_names[h->product],
+ (unsigned long)h->board_id,
+ h->firm_rev[0], h->firm_rev[1], h->firm_rev[2], h->firm_rev[3],
+ (unsigned long)h->ctlr_sig, (unsigned long)h->vaddr,
+ (unsigned int) h->ioaddr, (unsigned int)h->intr,
+ h->log_drives, h->phys_drives,
+ h->Qdepth, h->maxQsinceinit);
+
+ pos += size; len += size;
+
+ size = sprintf(buffer+len, "Logical Drive Info:\n");
+ pos += size; len += size;
+
+ for(i=0; i<h->log_drives; i++) {
+ drv = &h->drv[i];
+ size = sprintf(buffer+len, "ida/c%dd%d: blksz=%d nr_blks=%d\n",
+ ctlr, i, drv->blk_size, drv->nr_blks);
+ pos += size; len += size;
+ }
+
+#ifdef CPQ_PROC_PRINT_QUEUES
+ size = sprintf(buffer+len, "\nCurrent Queues:\n");
+ pos += size; len += size;
+
+ c = h->reqQ;
+ size = sprintf(buffer+len, "reqQ = %p", c); pos += size; len += size;
+ if (c) c=c->next;
+ while(c && c != h->reqQ) {
+ size = sprintf(buffer+len, "->%p", c);
+ pos += size; len += size;
+ c=c->next;
+ }
+
+ c = h->cmpQ;
+ size = sprintf(buffer+len, "\ncmpQ = %p", c); pos += size; len += size;
+ if (c) c=c->next;
+ while(c && c != h->cmpQ) {
+ size = sprintf(buffer+len, "->%p", c);
+ pos += size; len += size;
+ c=c->next;
+ }
+
+ size = sprintf(buffer+len, "\n"); pos += size; len += size;
+#endif
+ size = sprintf(buffer+len,"nr_allocs = %d\nnr_frees = %d\n",
+ h->nr_allocs, h->nr_frees);
+ pos += size; len += size;
+
+ *start = buffer+offset;
+ len -= offset;
+ if (len>length)
+ len = length;
+ return len;
+}
+
+#ifdef MODULE
+/* This is a hack... */
+#include "proc_array.c"
+int init_module(void)
+{
+ int i, j;
+ cpqarray_init();
+ if (nr_ctlr == 0)
+ return -EIO;
+
+ for(i=0; i<nr_ctlr; i++) {
+ ida_geninit(&ida_gendisk[i]);
+ for(j=0; j<NWD; j++)
+ if (ida_sizes[(i<<CTLR_SHIFT) + (j<<NWD_SHIFT)])
+ resetup_one_dev(&ida_gendisk[i], j);
+ }
+ return 0;
+}
+void cleanup_module(void)
+{
+ int i;
+ struct gendisk *g;
+
+ for(i=0; i<nr_ctlr; i++) {
+ smart2_write(0, hba[i], INTR_MASK);
+ free_irq(hba[i]->intr, hba[i]);
+ vfree((void*)hba[i]->vaddr);
+ unregister_blkdev(MAJOR_NR+i, hba[i]->devname);
+ del_timer(&hba[i]->timer);


SHAR_EOF
true || echo 'restore of patch-2.0.37 failed'
fi

echo 'End of part 05'
echo 'File patch-2.0.37 is continued in part 06'
echo 06 > _shar_seq_.tmp
exit 0

Thomas...@ciw.uni-karlsruhe.de

unread,
Jun 16, 1999, 3:00:00 AM6/16/99
to
Archive-name: v2.0/patch-2.0.37/part07

#!/bin/sh
# this is part 07 of a 45 - part archive


# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.0.37 continued
if test ! -r _shar_seq_.tmp; then
echo 'Please unpack part 1 first!'
exit 1
fi
(read Scheck

if test "$Scheck" != 07; then


echo Please unpack part "$Scheck" next!
exit 1
else
exit 0
fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.0.37'
else
echo 'x - continuing with patch-2.0.37'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.0.37' &&
+

+#define IDA_READ 0x20
+#define IDA_WRITE 0x30
+#define IDA_WRITE_MEDIA 0x31
+#define RESET_TO_DIAG 0x40
+#define DIAG_PASS_THRU 0x41
+
+#define SENSE_CONFIG 0x50
+#define SET_CONFIG 0x51
+typedef struct {
+ __u32 cfg_sig;
+ __u16 compat_port;
+ __u8 data_dist_mode;
+ __u8 surf_an_ctrl;
+ __u16 ctlr_phys_drv;
+ __u16 log_unit_phys_drv;
+ __u16 fault_tol_mode;
+ __u8 phys_drv_param[16];
+ drv_param_t drv;
+ __u32 drv_asgn_map;
+ __u16 dist_factor;
+ __u32 spare_asgn_map;
+ __u8 reserved[6];
+ __u16 os;
+ __u8 ctlr_order;
+ __u8 extra_info;
+ __u32 data_offs;
+ __u8 parity_backedout_write_drvs;
+ __u8 parity_dist_mode;
+ __u8 parity_shift_fact;
+ __u8 bios_disable_flag;
+ __u32 blks_on_vol;
+ __u32 blks_per_drv;
+ __u8 scratch[16];
+ __u16 big_drv_map[8];
+ __u16 big_spare_map[8];
+ __u8 ss_source_vol;
+ __u8 mix_drv_cap_range;
+ struct {
+ __u16 big_drv_map[8];
+ __u32 blks_per_drv;
+ __u16 fault_tol_mode;
+ __u16 dist_factor;
+ } MDC_range[4];
+ __u8 reserved1[248];
+} config_t;
+
+#define BYPASS_VOL_STATE 0x52
+#define SS_CREATE_VOL 0x53
+#define CHANGE_CONFIG 0x54
+#define SENSE_ORIG_CONF 0x55
+#define REORDER_LOG_DRV 0x56
+typedef struct {
+ __u8 old_units[32];
+} reorder_log_drv_t;
+
+#define LABEL_LOG_DRV 0x57
+typedef struct {
+ __u8 log_drv_label[64];
+} label_log_drv_t;
+
+#define SS_TO_VOL 0x58
+
+#define SET_SURF_DELAY 0x60
+typedef struct {
+ __u16 delay;
+ __u8 reserved[510];
+} surf_delay_t;
+
+#define SET_OVERHEAT_DELAY 0x61
+typedef struct {
+ __u16 delay;
+} overhead_delay_t;
+
+#define SET_MP_DELAY
+typedef struct {
+ __u16 delay;
+ __u8 reserved[510];
+} mp_delay_t;
+
+#define PASSTHRU_A 0x91
+typedef struct {
+ __u8 target;
+ __u8 bus;
+ __u8 lun;
+ __u32 timeout;
+ __u32 flags;
+ __u8 status;
+ __u8 error;
+ __u8 cdb_len;
+ __u8 sense_error;
+ __u8 sense_key;
+ __u32 sense_info;
+ __u8 sense_code;
+ __u8 sense_qual;
+ __u8 residual;
+ __u8 reserved[4];
+ __u8 cdb[12];
+} scsi_param_t;
+
+#pragma pack()
+
+#endif /* ARRAYCMD_H */
diff -u --recursive --new-file v2.0.36/linux/drivers/block/ida_ioctl.h linux/drivers/block/ida_ioctl.h
--- v2.0.36/linux/drivers/block/ida_ioctl.h Wed Dec 31 16:00:00 1969
+++ linux/drivers/block/ida_ioctl.h Sun Jun 13 10:21:00 1999
@@ -0,0 +1,80 @@


+/*
+ * Disk Array driver for Compaq SMART2 Controllers
+ * Copyright 1998 Compaq Computer Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Questions/Comments/Bugfixes to arr...@compaq.com
+ *
+ * If you want to make changes, improve or add functionality to this
+ * driver, you'll probably need the Compaq Array Controller Interface
+ * Specificiation (Document number ECG086/1198)
+ */

+#ifndef IDA_IOCTL_H
+#define IDA_IOCTL_H
+
+#include "ida_cmd.h"
+#include "cpqarray.h"
+
+#define IDAGETDRVINFO 0x27272828
+#define IDAPASSTHRU 0x28282929
+#define IDAGETCTLRSIG 0x29293030
+#define IDAREVALIDATEVOLS 0x30303131
+
+/*
+ * Normally, the ioctl determines the logical unit for this command by
+ * the major,minor number of the fd passed to ioctl. If you need to send
+ * a command to a different/nonexistant unit (such as during config), you
+ * can override the normal behavior by setting the unit valid bit. (Normally,
+ * it should be zero) The controller to which the command is sent is still
+ * determined by the major number of the open device.
+ */
+
+#define UNITVALID 0x80
+typedef struct {
+ __u8 cmd;
+ __u8 rcode;
+ __u8 unit;
+
+/* currently, sg_cnt is assumed to be 1: only the 0th element of sg is used */
+ struct {
+ void *addr;
+ size_t size;
+ } sg[SG_MAX];
+ int sg_cnt;
+
+ union ctlr_cmds {
+ drv_info_t drv;
+ unsigned char buf[512];
+
+ id_ctlr_t id_ctlr;
+ drv_param_t drv_param;
+ id_log_drv_t id_log_drv;
+ id_log_drv_ext_t id_log_drv_ext;
+ sense_log_drv_stat_t sense_log_drv_stat;
+ id_phys_drv_t id_phys_drv;
+ blink_drv_leds_t blink_drv_leds;
+ sense_blink_leds_t sense_blink_leds;
+ config_t config;
+ reorder_log_drv_t reorder_log_drv;
+ label_log_drv_t label_log_drv;
+ surf_delay_t surf_delay;
+ overhead_delay_t overhead_delay;
+ mp_delay_t mp_delay;
+ scsi_param_t scsi_param;
+ } c;
+} ida_ioctl_t;
+
+#endif /* IDA_IOCTL_H */
diff -u --recursive --new-file v2.0.36/linux/drivers/block/ide.c linux/drivers/block/ide.c
--- v2.0.36/linux/drivers/block/ide.c Sun Nov 15 21:51:46 1998
+++ linux/drivers/block/ide.c Sun Jun 13 10:21:00 1999
@@ -277,6 +277,12 @@
X * fix MC_ERR handling
X * fix mis-detection of NEC cdrom as floppy
X * issue ATAPI reset and re-probe after "no response"
+ * Version 5.53.3 changes by Andrew D. Balsa to enable DMA mode 2 and
+ * UDMA on SiS and TX chipsets.
+ * Version 5.53.4 moved Promise/33 auto-detection and DMA support
+ * to trition.c and added UDMA to current DMA support.
+ * update Promise Ultra33 and added AEC6210U/UF UDMA cards.
+ * add configuration flag to allow booting of either card.
X *
X * Some additional driver compile-time options are in ide.h
X *
@@ -607,8 +613,12 @@
X unsigned long chs_sects = id->cyls * id->heads * id->sectors;
X unsigned long _10_percent = chs_sects / 10;
X
- /* very large drives (8GB+) may lie about the number of cylinders */
- if (id->cyls == 16383 && id->heads == 16 && id->sectors == 63 && lba_sects > chs_sects) {
+ /*
+ * very large drives (8GB+) may lie about the number of cylinders
+ * This is a split test for drives 8 Gig and Bigger only.
+ */
+ if ((id->lba_capacity >= 16514064) && (id->cyls == 0x3fff) &&
+ (id->heads == 16) && (id->sectors == 63)) {
X id->cyls = lba_sects / (16 * 63); /* correct cyls */
X return 1; /* lba_capacity is our only option */
X }
@@ -649,6 +659,15 @@
X drive->cyl = id->lba_capacity / (drive->head * drive->sect);
X capacity = id->lba_capacity;
X drive->select.b.lba = 1;
+#if 0
+ /*
+ * This is the correct place to perform this task;
+ * however, we do this later for reporting.
+ */
+ if (*(int *)&id->cur_capacity0 != id->lba_capacity) {
+ *(int *)&id->cur_capacity0 = id->lba_capacity;
+ }
+#endif
X }
X }
X return (capacity - drive->sect0);
@@ -2192,17 +2211,18 @@
X case HDIO_GET_MULTCOUNT:
X return write_fs_long(arg, drive->mult_count);
X
+ case HDIO_OBSOLETE_IDENTITY:
X case HDIO_GET_IDENTITY:
X if (!arg || (MINOR(inode->i_rdev) & PARTN_MASK))
X return -EINVAL;
X if (drive->id == NULL)
X return -ENOMSG;
- err = verify_area(VERIFY_WRITE, (char *)arg, sizeof(*drive->id));
+ err = verify_area(VERIFY_WRITE, (char *)arg, (cmd == HDIO_GET_IDENTITY) ? sizeof(*drive->id) : 142);
X if (!err)
- memcpy_tofs((char *)arg, (char *)drive->id, sizeof(*drive->id));
+ memcpy_tofs((char *)arg, (char *)drive->id, (cmd == HDIO_GET_IDENTITY) ? sizeof(*drive->id) : 142);
X return err;
X
- case HDIO_GET_NOWERR:
+ case HDIO_GET_NOWERR:
X return write_fs_long(arg, drive->bad_wstat == BAD_R_STAT);
X
X case HDIO_SET_DMA:
@@ -2545,9 +2565,8 @@
X drive->sect = drive->bios_sect = id->sectors;
X }
X /* Handle logical geometry translation by the drive */
- if ((id->field_valid & 1) && id->cur_cyls && id->cur_heads
- && (id->cur_heads <= 16) && id->cur_sectors)
- {
+ if ((id->field_valid & 1) && id->cur_cyls &&
+ id->cur_heads && (id->cur_heads <= 16) && id->cur_sectors) {
X /*
X * Extract the physical drive geometry for our use.
X * Note that we purposely do *not* update the bios info.
@@ -2572,19 +2591,38 @@
X }
X }
X /* Use physical geometry if what we have still makes no sense */
- if ((!drive->head || drive->head > 16) && id->heads && id->heads <= 16) {
- drive->cyl = id->cyls;
- drive->head = id->heads;
- drive->sect = id->sectors;
+ if ((!drive->head || drive->head > 16) &&
+ id->heads && id->heads <= 16) {
+ if ((id->lba_capacity > 16514064) || (id->cyls == 0x3fff)) {
+ id->cyls = ((int)(id->lba_capacity/(id->heads * id->sectors)));
+ }
+ drive->cyl = id->cur_cyls = id->cyls;
+ drive->head = id->cur_heads = id->heads;
+ drive->sect = id->cur_sectors = id->sectors;
X }
X
X /* calculate drive capacity, and select LBA if possible */
- (void) current_capacity (drive);
+ capacity = current_capacity (drive);
X
- /* Correct the number of cyls if the bios value is too small */
- if (drive->sect == drive->bios_sect && drive->head == drive->bios_head) {
- if (drive->cyl > drive->bios_cyl)
- drive->bios_cyl = drive->cyl;
+ /*
+ * if possible, give fdisk access to more of the drive,
+ * by correcting bios_cyls:
+ */
+ if ((capacity >= (id->cyls * id->heads * id->sectors)) &&
+ (!drive->forced_geom) && drive->bios_sect && drive->bios_head) {
+ drive->bios_cyl = (capacity / drive->bios_sect) / drive->bios_head;
+#ifdef DEBUG
+ printk("FDISK Fixing Geometry :: CHS=%d/%d/%d to CHS=%d/%d/%d\n",
+ drive->id->cur_cyls,
+ drive->id->cur_heads,
+ drive->id->cur_sectors,
+ drive->bios_cyl,
+ drive->bios_head,
+ drive->bios_sect);
+#endif
+ drive->id->cur_cyls = drive->bios_cyl;
+ drive->id->cur_heads = drive->bios_head;
+ drive->id->cur_sectors = drive->bios_sect;
X }
X
X if (!strncmp(id->model, "BMI ", 4) &&
@@ -2592,27 +2630,54 @@
X drive->select.b.lba)
X drive->no_geom = 1;
X
- printk ("%s: %.40s, %ldMB w/%dkB Cache, CHS=%d/%d/%d",
- drive->name, id->model, current_capacity(drive)/2048L, id->buf_size/2,
- drive->bios_cyl, drive->bios_head, drive->bios_sect);
-
X drive->mult_count = 0;
X if (id->max_multsect) {
+#ifdef CONFIG_IDEDISK_MULTI_MODE
+ id->multsect = ((id->max_multsect/2) > 1) ? id->max_multsect : 0;
+ id->multsect_valid = id->multsect ? 1 : 0;
+ drive->mult_req = id->multsect_valid ? id->max_multsect : INITIAL_MULT_COUNT;
+ drive->special.b.set_multmode = drive->mult_req ? 1 : 0;
+#else /* original, pre IDE-NFG, per request of AC */
X drive->mult_req = INITIAL_MULT_COUNT;
X if (drive->mult_req > id->max_multsect)
X drive->mult_req = id->max_multsect;
X if (drive->mult_req || ((id->multsect_valid & 1) && id->multsect))
X drive->special.b.set_multmode = 1;
+#endif
X }
+
+ drive->no_io_32bit = id->dword_io ? 1 : 0;
+
X if (drive->autotune != 2 && HWIF(drive)->dmaproc != NULL) {
- if (!(HWIF(drive)->dmaproc(ide_dma_check, drive))) {
- if ((id->field_valid & 4) && (id->dma_ultra & (id->dma_ultra >> 8) & 7))
- printk(", UDMA");
- else
- printk(", DMA");
+ (void) HWIF(drive)->dmaproc(ide_dma_check, drive);
+ }
+
+ printk ("%s: %.40s, %ldMB w/%dkB Cache, CHS=%d/%d/%d",
+ drive->name, id->model,
+ capacity/2048L, id->buf_size/2,
+ drive->bios_cyl, drive->bios_head, drive->bios_sect);
+ if (drive->using_dma) {
+ if ((id->field_valid & 4) && (id->dma_ultra & (id->dma_ultra >> 8) & 7)) {
+ printk(", UDMA"); /* UDMA BIOS-enabled! */
+ } else if (id->field_valid & 4) {
+ printk(", (U)DMA"); /* Can be BIOS-enabled! */
+ } else {
+ printk(", DMA");
X }
X }
X printk("\n");
+ if (drive->select.b.lba) {
+ if (*(int *)&id->cur_capacity0 != id->lba_capacity) {
+#ifdef DEBUG
+ printk(" CurSects=%d, LBASects=%d, ",
+ *(int *)&id->cur_capacity0, id->lba_capacity);
+#endif
+ *(int *)&id->cur_capacity0 = id->lba_capacity;
+#ifdef DEBUG
+ printk( "Fixed CurSects=%d\n", *(int *)&id->cur_capacity0);
+#endif
+ }
+ }
X }
X
X /*
@@ -3314,6 +3379,13 @@
X * an IDE disk drive, or if a geometry was "forced" on the commandline.
X * Returns 1 if the geometry translation was successful.
X */
+
+/*
+ * We update the values if the current CHS as determined by the kernel.
+ * This now allows for the hdparm tool to read the actual settings of the
+ * being used by the kernel. This removes the need for doing guess
+ * translations based on the raw values of the drive.
+ */
X int ide_xlate_1024 (kdev_t i_rdev, int xparm, const char *msg)
X {
X ide_drive_t *drive;
@@ -3321,14 +3393,42 @@
X const byte *heads = head_vals;
X unsigned long tracks;
X
- if ((drive = get_info_ptr(i_rdev)) == NULL || drive->forced_geom)
+ drive = get_info_ptr(i_rdev);
+ if (!drive)
X return 0;
X
- if (xparm > 1 && xparm <= drive->bios_head && drive->bios_sect == 63)
+ if (drive->forced_geom) {
+ /*
+ * Update the current 3D drive values.
+ */
+ drive->id->cur_cyls = drive->bios_cyl;
+ drive->id->cur_heads = drive->bios_head;
+ drive->id->cur_sectors = drive->bios_sect;


+ return 0;
+ }
+

+ if (xparm > 1 && xparm <= drive->bios_head && drive->bios_sect == 63) {
+ /*
+ * Update the current 3D drive values.
+ */
+ drive->id->cur_cyls = drive->bios_cyl;
+ drive->id->cur_heads = drive->bios_head;
+ drive->id->cur_sectors = drive->bios_sect;
X return 0; /* we already have a translation */
+ }
X
X printk("%s ", msg);
X
+ if (xparm < 0 && (drive->bios_cyl * drive->bios_head * drive->bios_sect) < (1024 * 16 * 63)) {
+ /*
+ * Update the current 3D drive values.
+ */
+ drive->id->cur_cyls = drive->bios_cyl;
+ drive->id->cur_heads = drive->bios_head;
+ drive->id->cur_sectors = drive->bios_sect;
+ return 0; /* small disk: no translation needed */
+ }
+
X if (drive->id) {
X drive->cyl = drive->id->cyls;
X drive->head = drive->id->heads;
@@ -3366,6 +3466,12 @@
X }
X drive->part[0].nr_sects = current_capacity(drive);
X printk("[%d/%d/%d]", drive->bios_cyl, drive->bios_head, drive->bios_sect);
+ /*
+ * Update the current 3D drive values.
+ */
+ drive->id->cur_cyls = drive->bios_cyl;
+ drive->id->cur_heads = drive->bios_head;
+ drive->id->cur_sectors = drive->bios_sect;
X return 1;
X }
X
@@ -3535,43 +3641,6 @@
X }
X
X #endif /* defined(CONFIG_BLK_DEV_RZ1000) || defined(CONFIG_BLK_DEV_TRITON) */
-
-static void ide_probe_promise_20246(void)
-{
- byte fn, bus;
- unsigned short io[6], count = 0;
- unsigned int reg, tmp, i;
- ide_hwif_t *hwif;
-
- memset(io, 0, 6 * sizeof(unsigned short));
- if (pcibios_find_device(PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20246, 0, &bus, &fn))
- return;
- printk("ide: Promise Technology IDE Ultra-DMA 33 on PCI bus %d function %d\n", bus, fn);
- for (reg = PCI_BASE_ADDRESS_0; reg <= PCI_BASE_ADDRESS_5; reg += 4) {
- pcibios_read_config_dword(bus, fn, reg, &tmp);
- if (tmp & PCI_BASE_ADDRESS_SPACE_IO)
- io[count++] = tmp & PCI_BASE_ADDRESS_IO_MASK;
- }
- for (i = 2; i < 4; i++) {
- hwif = ide_hwifs + i;
- if (hwif->chipset == ide_generic) {
- printk("ide%d: overridden with command line parameter\n", i);
- return;
- }
- tmp = (i - 2) * 2;
- if (!io[tmp] || !io[tmp + 1]) {
- printk("ide%d: invalid port address %x, %x -- aborting\n", i, io[tmp], io[tmp + 1]);
- return;
- }
- hwif->io_base = io[tmp];
- hwif->ctl_port = io[tmp + 1] + 2;
- hwif->noprobe = 0;
- }
-#ifdef CONFIG_BLK_DEV_TRITON
- ide_init_promise (bus, fn, &ide_hwifs[2], &ide_hwifs[3], io[4]);
-#endif /* CONFIG_BLK_DEV_TRITON */
-}
-
X #endif /* CONFIG_PCI */
X
X /*
@@ -3599,11 +3668,20 @@
X * So instead, we search for PCI_DEVICE_ID_INTEL_82371_0,
X * and then add 1.
X */
+#ifdef CONFIG_BLK_DEV_OFFBOARD
+ ide_probe_pci (PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20246, &ide_init_triton, 0);
+ ide_probe_pci (PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP850UF, &ide_init_triton, 0);
+#endif /* CONFIG_BLK_DEV_OFFBOARD */
X ide_probe_pci (PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371_0, &ide_init_triton, 1);
X ide_probe_pci (PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_1, &ide_init_triton, 0);
X ide_probe_pci (PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB, &ide_init_triton, 0);
+ ide_probe_pci (PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5513, &ide_init_triton, 0);
+ ide_probe_pci (PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1, &ide_init_triton, 0);
+#ifndef CONFIG_BLK_DEV_OFFBOARD
+ ide_probe_pci (PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20246, &ide_init_triton, 0);
+ ide_probe_pci (PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP850UF, &ide_init_triton, 0);
+#endif /* CONFIG_BLK_DEV_OFFBOARD */
X #endif /* CONFIG_BLK_DEV_TRITON */
- ide_probe_promise_20246();
X }
X #endif /* CONFIG_PCI */
X #ifdef CONFIG_BLK_DEV_CMD640
diff -u --recursive --new-file v2.0.36/linux/drivers/block/ide.h linux/drivers/block/ide.h
--- v2.0.36/linux/drivers/block/ide.h Sun Nov 15 21:51:46 1998
+++ linux/drivers/block/ide.h Sun Jun 13 10:21:00 1999
@@ -429,7 +429,7 @@
X typedef enum { ide_unknown, ide_generic, ide_triton,
X ide_cmd640, ide_dtc2278, ide_ali14xx,
X ide_qd6580, ide_umc8672, ide_ht6560b,
- ide_promise, ide_promise_udma }
+ ide_promise, ide_udma }
X hwif_chipset_t;
X
X typedef struct hwif_s {
@@ -743,5 +743,4 @@
X
X #ifdef CONFIG_BLK_DEV_TRITON
X void ide_init_triton (byte, byte);
-void ide_init_promise (byte bus, byte fn, ide_hwif_t *hwif0, ide_hwif_t *hwif1, unsigned short dma);
X #endif /* CONFIG_BLK_DEV_TRITON */
diff -u --recursive --new-file v2.0.36/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c
--- v2.0.36/linux/drivers/block/ll_rw_blk.c Sun Nov 15 10:49:32 1998
+++ linux/drivers/block/ll_rw_blk.c Sun Jun 13 10:21:00 1999
@@ -82,6 +82,30 @@
X int * hardsect_size[MAX_BLKDEV] = { NULL, NULL, };
X
X /*
+ * Max number of sectors per request
+ */
+int * max_sectors[MAX_BLKDEV] = { NULL, NULL, };
+
+/*
+ * Max number of segments per request
+ */
+int * max_segments[MAX_BLKDEV] = { NULL, NULL, };
+
+static inline int get_max_sectors(kdev_t dev)
+{
+ if (!max_sectors[MAJOR(dev)])
+ return MAX_SECTORS;
+ return max_sectors[MAJOR(dev)][MINOR(dev)];
+}
+
+static inline int get_max_segments(kdev_t dev)
+{
+ if (!max_segments[MAJOR(dev)])
+ return MAX_SEGMENTS;
+ return max_segments[MAJOR(dev)][MINOR(dev)];
+}
+
+/*
X * remove the plug and let it rip..
X */
X void unplug_device(void * data)
@@ -233,22 +257,29 @@
X
X void add_request(struct blk_dev_struct * dev, struct request * req)
X {
+ int major = MAJOR(req->rq_dev);
+ int minor = MINOR(req->rq_dev);
X struct request * tmp;
X short disk_index;
X
- switch (MAJOR(req->rq_dev)) {
+ switch (major) {
+ case DAC960_MAJOR+0:
+ disk_index = (minor & 0x00f8) >> 3;
+ if (disk_index < 4)
+ drive_stat_acct(req->cmd, req->nr_sectors, disk_index);
+ break;
X case SCSI_DISK_MAJOR:
- disk_index = (MINOR(req->rq_dev) & 0x0070) >> 4;
+ disk_index = (minor & 0x0070) >> 4;
X if (disk_index < 4)
X drive_stat_acct(req->cmd, req->nr_sectors, disk_index);
X break;
X case IDE0_MAJOR: /* same as HD_MAJOR */
X case XT_DISK_MAJOR:
- disk_index = (MINOR(req->rq_dev) & 0x0040) >> 6;
+ disk_index = (minor & 0x0040) >> 6;
X drive_stat_acct(req->cmd, req->nr_sectors, disk_index);
X break;
X case IDE1_MAJOR:
- disk_index = ((MINOR(req->rq_dev) & 0x0040) >> 6) + 2;
+ disk_index = ((minor & 0x0040) >> 6) + 2;
X drive_stat_acct(req->cmd, req->nr_sectors, disk_index);
X default:
X break;
@@ -274,30 +305,39 @@
X tmp->next = req;
X
X /* for SCSI devices, call request_fn unconditionally */
- if (scsi_blk_major(MAJOR(req->rq_dev)))
+ if (scsi_blk_major(major))
X (dev->request_fn)();
X
+ if ( (major >= DAC960_MAJOR+0 && major <= DAC960_MAJOR+7) ||
+ (major >= COMPAQ_SMART2_MAJOR+0 && major <= COMPAQ_SMART2_MAJOR+7))
+ (dev->request_fn)();
+
X sti();
X }
X
-#define MAX_SECTORS 244
-
-static inline void attempt_merge (struct request *req)
+static inline void attempt_merge (struct request *req,
+ int max_sectors,
+ int max_segments)
X {
X struct request *next = req->next;
+ int total_segments;
X
X if (!next)
X return;
X if (req->sector + req->nr_sectors != next->sector)
X return;
- if (next->sem || req->cmd != next->cmd || req->rq_dev != next->rq_dev || req->nr_sectors + next->nr_sectors >= MAX_SECTORS)
+ if (next->sem || req->cmd != next->cmd || req->rq_dev != next->rq_dev ||
+ req->nr_sectors + next->nr_sectors > max_sectors)
+ return;
+ total_segments = req->nr_segments + next->nr_segments;
+ if (req->bhtail->b_data + req->bhtail->b_size == next->bh->b_data)
+ total_segments--;
+ if (total_segments > max_segments)
X return;
-#if 0
- printk ("%s: merge %ld, %ld + %ld == %ld\n", kdevname(req->rq_dev), req->sector, req->nr_sectors, next->nr_sectors, req->nr_sectors + next->nr_sectors);
-#endif
X req->bhtail->b_reqnext = next->bh;
X req->bhtail = next->bhtail;
X req->nr_sectors += next->nr_sectors;
+ req->nr_segments = total_segments;
X next->rq_status = RQ_INACTIVE;
X req->next = next->next;
X wake_up (&wait_for_request);
@@ -307,7 +347,7 @@
X {
X unsigned int sector, count;
X struct request * req;
- int rw_ahead, max_req;
+ int rw_ahead, max_req, max_sectors, max_segments;
X
X count = bh->b_size >> 9;
X sector = bh->b_rsector;
@@ -324,7 +364,7 @@
X lock_buffer(bh);
X
X if (blk_size[major])
- if (blk_size[major][MINOR(bh->b_rdev)] < (sector + count)>>1) {
+ if (blk_size[major][MINOR(bh->b_rdev)] < (sector + count)>>1) {
X bh->b_state &= (1 << BH_Lock) | (1 << BH_FreeOnIO);
X /* This may well happen - the kernel calls bread()
X without checking the size of the device, e.g.,
@@ -390,6 +430,9 @@
X /*
X * Try to coalesce the new request with old requests
X */
+ max_sectors = get_max_sectors(bh->b_rdev);
+ max_segments = get_max_segments(bh->b_rdev);
+
X cli();
X req = blk_dev[major].current_request;
X if (!req) {
@@ -418,25 +461,52 @@
X
X case SCSI_DISK_MAJOR:
X case SCSI_CDROM_MAJOR:
-
+ case DAC960_MAJOR+0:
+ case DAC960_MAJOR+1:
+ case DAC960_MAJOR+2:
+ case DAC960_MAJOR+3:
+ case DAC960_MAJOR+4:
+ case DAC960_MAJOR+5:
+ case DAC960_MAJOR+6:
+ case DAC960_MAJOR+7:
+ case COMPAQ_SMART2_MAJOR+0:
+ case COMPAQ_SMART2_MAJOR+1:
+ case COMPAQ_SMART2_MAJOR+2:
+ case COMPAQ_SMART2_MAJOR+3:
+ case COMPAQ_SMART2_MAJOR+4:
+ case COMPAQ_SMART2_MAJOR+5:
+ case COMPAQ_SMART2_MAJOR+6:
+ case COMPAQ_SMART2_MAJOR+7:
X do {
X if (req->sem)
X continue;
X if (req->cmd != rw)
X continue;
- if (req->nr_sectors >= MAX_SECTORS)
+ if (req->nr_sectors + count > max_sectors)
X continue;
X if (req->rq_dev != bh->b_rdev)
X continue;
X /* Can we add it to the end of this request? */
X if (req->sector + req->nr_sectors == sector) {
+ if (req->bhtail->b_data + req->bhtail->b_size
+ != bh->b_data) {
+ if (req->nr_segments < max_segments)
+ req->nr_segments++;
+ else continue;
+ }
X req->bhtail->b_reqnext = bh;
X req->bhtail = bh;
X req->nr_sectors += count;
X /* Can we now merge this req with the next? */
- attempt_merge(req);
+ attempt_merge(req, max_sectors, max_segments);
X /* or to the beginning? */
X } else if (req->sector - count == sector) {
+ if (bh->b_data + bh->b_size
+ != req->bh->b_data) {
+ if (req->nr_segments < max_segments)
+ req->nr_segments++;
+ else continue;
+ }
X bh->b_reqnext = req->bh;
X req->bh = bh;
X req->buffer = bh->b_data;
@@ -470,6 +540,7 @@
X req->errors = 0;
X req->sector = sector;
X req->nr_sectors = count;
+ req->nr_segments = 1;
X req->current_nr_sectors = count;
X req->buffer = bh->b_data;
X req->sem = NULL;
@@ -634,6 +705,7 @@
X req[j]->errors = 0;
X req[j]->sector = rsector;
X req[j]->nr_sectors = buffersize >> 9;
+ req[j]->nr_segments = 1;
X req[j]->current_nr_sectors = buffersize >> 9;
X req[j]->buffer = buf;
X req[j]->sem = &sem;
diff -u --recursive --new-file v2.0.36/linux/drivers/block/paride/Config.in linux/drivers/block/paride/Config.in
--- v2.0.36/linux/drivers/block/paride/Config.in Sun Nov 15 10:49:32 1998
+++ linux/drivers/block/paride/Config.in Sun Jun 13 10:21:00 1999
@@ -16,6 +16,7 @@
X dep_tristate ' FIT TD-3000 protocol' CONFIG_PARIDE_FIT3 $CONFIG_PARIDE
X dep_tristate ' Shuttle EPAT/EPEZ protocol' CONFIG_PARIDE_EPAT $CONFIG_PARIDE
X dep_tristate ' Shuttle EPIA protocol' CONFIG_PARIDE_EPIA $CONFIG_PARIDE
+dep_tristate ' Freecom IQ ASIC-2 protocol' CONFIG_PARIDE_FRIQ $CONFIG_PARIDE
X dep_tristate ' FreeCom power protocol' CONFIG_PARIDE_FRPW $CONFIG_PARIDE
X dep_tristate ' KingByte KBIC-951A/971A protocols' CONFIG_PARIDE_KBIC $CONFIG_PARIDE
X dep_tristate ' KT PHd protocol' CONFIG_PARIDE_KTTI $CONFIG_PARIDE
diff -u --recursive --new-file v2.0.36/linux/drivers/block/paride/Makefile linux/drivers/block/paride/Makefile
--- v2.0.36/linux/drivers/block/paride/Makefile Sun Nov 15 21:51:46 1998
+++ linux/drivers/block/paride/Makefile Sun Jun 13 10:21:00 1999
@@ -147,6 +147,15 @@


X endif
X endif
X
+

+ifeq ($(CONFIG_PARIDE_FRIQ),y)
+ LX_OBJS += friq.o
+else
+ ifeq ($(CONFIG_PARIDE_FRIQ),m)
+ M_OBJS += friq.o
+ endif
+endif
+
X ifeq ($(CONFIG_PARIDE_ON20),y)
X LX_OBJS += on20.o
X else
diff -u --recursive --new-file v2.0.36/linux/drivers/block/paride/friq.c linux/drivers/block/paride/friq.c
--- v2.0.36/linux/drivers/block/paride/friq.c Wed Dec 31 16:00:00 1969
+++ linux/drivers/block/paride/friq.c Sun Jun 13 10:21:00 1999
@@ -0,0 +1,282 @@
+/*
+ friq.c (c) 1998 Grant R. Guenther <gr...@torque.net>
+ Under the terms of the GNU public license
+
+ friq.c is a low-level protocol driver for the Freecom "IQ"
+ parallel port IDE adapter. Early versions of this adapter
+ use the 'frpw' protocol.
+
+ Freecom uses this adapter in a battery powered external
+ CD-ROM drive. It is also used in LS-120 drives by
+ Maxell and Panasonic, and other devices.
+
+ The battery powered drive requires software support to
+ control the power to the drive. This module enables the
+ drive power when the high level driver (pcd) is loaded
+ and disables it when the module is unloaded. Note, if
+ the friq module is built in to the kernel, the power
+ will never be switched off, so other means should be
+ used to conserve battery power.
+
+*/
+
+/* Changes:
+
+ 1.01 GRG 1998.12.20 Added support for soft power switch
+*/
+
+#define FRIQ_VERSION "1.01"
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <asm/io.h>
+
+#include "paride.h"
+
+#define CMD(x) w2(4);w0(0xff);w0(0xff);w0(0x73);w0(0x73);\
+ w0(0xc9);w0(0xc9);w0(0x26);w0(0x26);w0(x);w0(x);
+
+#define j44(l,h) (((l>>4)&0x0f)|(h&0xf0))
+
+/* cont = 0 - access the IDE register file
+ cont = 1 - access the IDE command set
+*/
+
+static int cont_map[2] = { 0x08, 0x10 };
+
+static int friq_read_regr( PIA *pi, int cont, int regr )
+
+{ int h,l,r;
+
+ r = regr + cont_map[cont];
+
+ CMD(r);
+ w2(6); l = r1();
+ w2(4); h = r1();
+ w2(4);
+
+ return j44(l,h);
+
+}
+
+static void friq_write_regr( PIA *pi, int cont, int regr, int val)
+
+{ int r;
+
+ r = regr + cont_map[cont];
+
+ CMD(r);
+ w0(val);
+ w2(5);w2(7);w2(5);w2(4);
+}
+
+static void friq_read_block_int( PIA *pi, char * buf, int count, int regr )
+
+{ int h, l, k, ph;
+
+ switch(pi->mode) {
+
+ case 0: CMD(regr);
+ for (k=0;k<count;k++) {
+ w2(6); l = r1();
+ w2(4); h = r1();
+ buf[k] = j44(l,h);
+ }
+ w2(4);
+ break;
+
+ case 1: ph = 2;
+ CMD(regr+0xc0);
+ w0(0xff);
+ for (k=0;k<count;k++) {
+ w2(0xa4 + ph);
+ buf[k] = r0();
+ ph = 2 - ph;
+ }
+ w2(0xac); w2(0xa4); w2(4);
+ break;
+
+ case 2: CMD(regr+0x80);
+ for (k=0;k<count-2;k++) buf[k] = r4();
+ w2(0xac); w2(0xa4);
+ buf[count-2] = r4();
+ buf[count-1] = r4();
+ w2(4);
+ break;
+
+ case 3: CMD(regr+0x80);
+ for (k=0;k<(count/2)-1;k++) ((u16 *)buf)[k] = r4w();
+ w2(0xac); w2(0xa4);
+ buf[count-2] = r4();
+ buf[count-1] = r4();
+ w2(4);
+ break;
+
+ case 4: CMD(regr+0x80);
+ for (k=0;k<(count/4)-1;k++) ((u32 *)buf)[k] = r4l();
+ buf[count-4] = r4();
+ buf[count-3] = r4();
+ w2(0xac); w2(0xa4);
+ buf[count-2] = r4();
+ buf[count-1] = r4();
+ w2(4);
+ break;
+
+ }
+}
+
+static void friq_read_block( PIA *pi, char * buf, int count)
+
+{ friq_read_block_int(pi,buf,count,0x08);
+}
+
+static void friq_write_block( PIA *pi, char * buf, int count )
+
+{ int k;
+
+ switch(pi->mode) {
+
+ case 0:
+ case 1: CMD(8); w2(5);
+ for (k=0;k<count;k++) {
+ w0(buf[k]);
+ w2(7);w2(5);
+ }
+ w2(4);
+ break;
+
+ case 2: CMD(0xc8); w2(5);
+ for (k=0;k<count;k++) w4(buf[k]);
+ w2(4);
+ break;
+
+ case 3: CMD(0xc8); w2(5);
+ for (k=0;k<count/2;k++) w4w(((u16 *)buf)[k]);
+ w2(4);
+ break;
+
+ case 4: CMD(0xc8); w2(5);
+ for (k=0;k<count/4;k++) w4l(((u32 *)buf)[k]);
+ w2(4);
+ break;
+ }
+}
+
+static void friq_connect ( PIA *pi )
+
+{ pi->saved_r0 = r0();
+ pi->saved_r2 = r2();
+ w2(4);
+}
+
+static void friq_disconnect ( PIA *pi )
+
+{ CMD(0x20);
+ w0(pi->saved_r0);
+ w2(pi->saved_r2);
+}
+
+static int friq_test_proto( PIA *pi, char * scratch, int verbose )
+
+{ int j, k, r;
+ int e[2] = {0,0};
+
+ pi->saved_r0 = r0();
+ w0(0xff); udelay(20); CMD(0x3d); /* turn the power on */
+ udelay(500);
+ w0(pi->saved_r0);
+
+ friq_connect(pi);
+ for (j=0;j<2;j++) {
+ friq_write_regr(pi,0,6,0xa0+j*0x10);
+ for (k=0;k<256;k++) {
+ friq_write_regr(pi,0,2,k^0xaa);
+ friq_write_regr(pi,0,3,k^0x55);
+ if (friq_read_regr(pi,0,2) != (k^0xaa)) e[j]++;
+ }
+ }
+ friq_disconnect(pi);
+
+ friq_connect(pi);
+ friq_read_block_int(pi,scratch,512,0x10);
+ r = 0;
+ for (k=0;k<128;k++) if (scratch[k] != k) r++;
+ friq_disconnect(pi);
+
+ if (verbose) {
+ printk("%s: friq: port 0x%x, mode %d, test=(%d,%d,%d)\n",
+ pi->device,pi->port,pi->mode,e[0],e[1],r);
+ }
+
+ return (r || (e[0] && e[1]));
+}
+
+
+static void friq_log_adapter( PIA *pi, char * scratch, int verbose )
+
+{ char *mode_string[6] = {"4-bit","8-bit",
+ "EPP-8","EPP-16","EPP-32"};
+
+ printk("%s: friq %s, Freecom IQ ASIC-2 adapter at 0x%x, ", pi->device,
+ FRIQ_VERSION,pi->port);
+ printk("mode %d (%s), delay %d\n",pi->mode,
+ mode_string[pi->mode],pi->delay);
+
+ pi->private = 1;
+ friq_connect(pi);
+ CMD(0x9e); /* disable sleep timer */
+ friq_disconnect(pi);
+
+}
+
+static void friq_init_proto( PIA *pi)
+
+{ MOD_INC_USE_COUNT;
+ pi->private = 0;
+}
+
+static void friq_release_proto( PIA *pi)
+
+{ if (pi->private) { /* turn off the power */
+ friq_connect(pi);
+ CMD(0x1d); CMD(0x1e);
+ friq_disconnect(pi);
+ pi->private = 0;
+ }
+
+ MOD_DEC_USE_COUNT;
+}
+
+struct pi_protocol friq = {"friq",0,5,2,1,1,
+ friq_write_regr,
+ friq_read_regr,
+ friq_write_block,
+ friq_read_block,
+ friq_connect,
+ friq_disconnect,
+ 0,
+ 0,
+ friq_test_proto,
+ friq_log_adapter,
+ friq_init_proto,
+ friq_release_proto
+ };
+
+
+#ifdef MODULE
+
+int init_module(void)
+
+{ return pi_register( &friq ) - 1;
+}
+
+void cleanup_module(void)
+
+{ pi_unregister( &friq );
+}
+
+#endif
+
+/* end of friq.c */
diff -u --recursive --new-file v2.0.36/linux/drivers/block/paride/frpw.c linux/drivers/block/paride/frpw.c
--- v2.0.36/linux/drivers/block/paride/frpw.c Sun Nov 15 21:51:46 1998
+++ linux/drivers/block/paride/frpw.c Sun Jun 13 10:21:00 1999
@@ -5,6 +5,12 @@
X frpw.c is a low-level protocol driver for the Freecom "Power"
X parallel port IDE adapter.
X
+ Some applications of this adapter may require a "printer" reset
+ prior to loading the driver. This can be done by loading and
+ unloading the "lp" driver, or it can be done by this driver
+ if you define FRPW_HARD_RESET. The latter is not recommended
+ as it may upset devices on other ports.
+
X */
X
X /* Changes:
@@ -13,10 +19,11 @@
X fix chip detect
X added EPP-16 and EPP-32
X 1.02 GRG 1998.09.23 added hard reset to initialisation process
+ 1.03 GRG 1998.12.14 made hard reset conditional
X
X */
X
-#define FRPW_VERSION "1.02"
+#define FRPW_VERSION "1.03"
X
X #include <linux/module.h>
X #include <linux/delay.h>
@@ -185,8 +192,10 @@
X
X { int olddelay, a, b;
X
+#ifdef FRPW_HARD_RESET
X w0(0); w2(8); udelay(50); w2(0xc); /* parallel bus reset */
X udelay(1500000);
+#endif
X
X olddelay = pi->delay;
X pi->delay = 10;
diff -u --recursive --new-file v2.0.36/linux/drivers/block/paride/jumbo linux/drivers/block/paride/jumbo
--- v2.0.36/linux/drivers/block/paride/jumbo Sun Nov 15 21:51:46 1998
+++ linux/drivers/block/paride/jumbo Sun Jun 13 10:21:00 1999
@@ -53,11 +53,11 @@
X FK="-D__KERNEL__ -I ../../../include"
X FLCH=-D_LINUX_CONFIG_H
X #
-echo cc $FK $FSMP $FLCH $FPARP $FPROTO -Wall -O2 -o Jb.o -c paride.c
-cc $FK $FSMP $FLCH $FPARP $FPROTO -Wall -O2 -o Jb.o -c paride.c
+echo cc $FK $FSMP $FLCH $FPARP $FPROTO $FMODV -Wall -O2 -o Jb.o -c paride.c
+cc $FK $FSMP $FLCH $FPARP $FPROTO $FMODV -Wall -O2 -o Jb.o -c paride.c
X #
-echo cc $FK $FSMP -Wall -O2 -o Jp.o -c $PROTO.c
-cc $FK $FSMP -Wall -O2 -o Jp.o -c $PROTO.c
+echo cc $FK $FSMP $FMODV -Wall -O2 -o Jp.o -c $PROTO.c
+cc $FK $FSMP $FMODV -Wall -O2 -o Jp.o -c $PROTO.c
X #
X echo cc $FK $FSMP $FMODV -DMODULE -DPARIDE_JUMBO -Wall -O2 -o Jd.o -c $HLD.c
X cc $FK $FSMP $FMODV -DMODULE -DPARIDE_JUMBO -Wall -O2 -o Jd.o -c $HLD.c
diff -u --recursive --new-file v2.0.36/linux/drivers/block/paride/on26.c linux/drivers/block/paride/on26.c
--- v2.0.36/linux/drivers/block/paride/on26.c Sun Nov 15 21:51:46 1998
+++ linux/drivers/block/paride/on26.c Sun Jun 13 10:21:00 1999
@@ -11,10 +11,12 @@
X
X 1.01 GRG 1998.05.06 init_proto, release_proto
X 1.02 GRG 1998.09.23 updates for the -E rev chip
+ 1.03 GRG 1998.12.14 fix for slave drives
+ 1.04 GRG 1998.12.20 yet another bug fix
X
X */
X
-#define ON26_VERSION "1.02"
+#define ON26_VERSION "1.04"
X
X #include <linux/module.h>
X #include <linux/delay.h>
@@ -118,9 +120,11 @@
X w2(pi->saved_r2);
X }
X
+#define RESET_WAIT 200
+
X static int on26_test_port( PIA *pi) /* hard reset */
X
-{ int i, m, d;
+{ int i, m, d, x, y;
X
X pi->saved_r0 = r0();
X pi->saved_r2 = r2();
@@ -151,11 +155,18 @@
X
X on26_write_regr(pi,0,6,0xa0);
X
- for (i=0;i<100;i++) {
- if (!(on26_read_regr(pi,0,7) & 0x80)) break;
+ for (i=0;i<RESET_WAIT;i++) {
+ on26_write_regr(pi,0,6,0xa0);
+ x = on26_read_regr(pi,0,7);
+ on26_write_regr(pi,0,6,0xb0);
+ y = on26_read_regr(pi,0,7);
+ if (!((x&0x80)||(y&0x80))) break;
X udelay(100000);
X }
X
+ if (i == RESET_WAIT)
+ printk("on26: Device reset failed (%x,%x)\n",x,y);
+
X w0(4); P1; w0(4); P1;
X }
X
@@ -189,7 +200,7 @@
X case 1: w0(1); P1; w0(1); P2; w0(2); P1; w0(0x19); P2; w0(0); P1;
X udelay(10);
X for (k=0;k<count/2;k++) {
- w2(0x26); buf[2*k] = r0();
+ w2(0x26); buf[2*k] = r0();
X w2(0x24); buf[2*k+1] = r0();
X }
X w0(2); P1; w0(9); P2;
diff -u --recursive --new-file v2.0.36/linux/drivers/block/paride/paride.c linux/drivers/block/paride/paride.c
--- v2.0.36/linux/drivers/block/paride/paride.c Sun Nov 15 10:49:32 1998
+++ linux/drivers/block/paride/paride.c Sun Jun 13 10:21:00 1999
@@ -11,10 +11,12 @@
X
X 1.01 GRG 1998.05.03 Use spinlocks
X 1.02 GRG 1998.05.05 init_proto, release_proto, ktti
+ 1.03 GRG 1998.08.15 eliminate compiler warning
+ 1.04 GRG 1998.11.28 added support for FRIQ
X
X */
X
-#define PI_VERSION "1.02"
+#define PI_VERSION "1.04"
X
X #include <linux/module.h>
X #include <linux/config.h>
@@ -449,6 +451,11 @@
X pi_register(&frpw);
X };
X #endif
+#ifdef CONFIG_PARIDE_FRIQ
+ { extern struct pi_protocol friq;
+ pi_register(&friq);
+ };
+#endif
X #ifdef CONFIG_PARIDE_FIT2
X { extern struct pi_protocol fit2;
X pi_register(&fit2);
diff -u --recursive --new-file v2.0.36/linux/drivers/block/paride/pseudo.h linux/drivers/block/paride/pseudo.h
--- v2.0.36/linux/drivers/block/paride/pseudo.h Sun Nov 15 10:49:32 1998
+++ linux/drivers/block/paride/pseudo.h Sun Jun 13 10:21:00 1999
@@ -16,19 +16,21 @@
X when either it returns true, or timeout jiffies have passed,
X continuation() will be invoked.
X
- If nice is true, the test will done approximately once a
+ If nice is 1, the test will done approximately once a
X jiffy. If nice is 0, the test will also be done whenever
- the scheduler runs (by adding it to a task queue).
+ the scheduler runs (by adding it to a task queue). If
+ nice is greater than 1, the test will be done once every
+ (nice-1) jiffies.
X
X */
X
X /* Changes:
X
X 1.01 1998.05.03 Switched from cli()/sti() to spinlocks
-
+ 1.02 1998.12.14 Added support for nice > 1
X */
X
-#define PS_VERSION "1.01"
+#define PS_VERSION "1.02"
X
X #include <linux/sched.h>
X #include <linux/timer.h>
@@ -37,13 +39,13 @@
X static void ps_timer_int( unsigned long data);
X static void ps_tq_int( void *data);
X
-static int ps_use_tq = 1;
X static void (* ps_continuation)(void);
X static int (* ps_ready)(void);
X static int ps_then;
X static int ps_timeout;
X static int ps_timer_active = 0;
X static int ps_tq_active = 0;
+static int ps_nice = 0;
X
X /* static spinlock_t ps_spinlock = SPIN_LOCK_UNLOCKED; */
X
@@ -62,9 +64,9 @@
X ps_ready = ready;
X ps_then = jiffies;
X ps_timeout = jiffies + timeout;
- ps_use_tq = !nice;
+ ps_nice = nice;
X
- if (ps_use_tq && !ps_tq_active) {
+ if (!ps_nice && !ps_tq_active) {
X #ifdef HAVE_DISABLE_HLT
X disable_hlt();
X #endif
@@ -74,7 +76,7 @@
X
X if (!ps_timer_active) {
X ps_timer_active = 1;
- ps_timer.expires = jiffies;
+ ps_timer.expires = jiffies + (ps_nice>0)?(ps_nice-1):0;
X add_timer(&ps_timer);
X }
X
@@ -136,7 +138,7 @@
X return;
X }
X ps_timer_active = 1;
- ps_timer.expires = jiffies;
+ ps_timer.expires = jiffies + (ps_nice>0)?(ps_nice-1):0;
X add_timer(&ps_timer);
X spin_unlock_irqrestore(&ps_spinlock,flags);
X }
diff -u --recursive --new-file v2.0.36/linux/drivers/block/paride/pt.c linux/drivers/block/paride/pt.c
--- v2.0.36/linux/drivers/block/paride/pt.c Sun Nov 15 21:51:46 1998
+++ linux/drivers/block/paride/pt.c Sun Jun 13 10:21:00 1999
@@ -464,7 +464,7 @@
X
X { int k, e, s;
X
- k = 0;
+ k = 0; e = 0; s = 0;
X while (k < tmo) {
X pt_sleep(pause);
X k++;
diff -u --recursive --new-file v2.0.36/linux/drivers/block/proc_array.c linux/drivers/block/proc_array.c
--- v2.0.36/linux/drivers/block/proc_array.c Wed Dec 31 16:00:00 1969
+++ linux/drivers/block/proc_array.c Sun Jun 13 10:21:00 1999
@@ -0,0 +1,119 @@
+/*
+ * Taken from linux/fs/proc/net.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ * gjh 3/'93 he...@peanuts.informatik.uni-tuebingen.de (Gerald J. Heim)
+ * most of this file is stolen from base.c
+ * it works, but you shouldn't use it as a guideline
+ * for new proc-fs entries. once i'll make it better.
+ * fvk 3/'93 wal...@uwalt.nl.mugnet.org (Fred N. van Kempen)
+ * cleaned up the whole thing, moved "net" specific code to
+ * the NET kernel layer (where it belonged in the first place).
+ * Michael K. Johnson (john...@stolaf.edu) 3/93
+ * Added support from my previous inet.c. Cleaned things up
+ * quite a bit, modularized the code.
+ * fvk 4/'93 wal...@uwalt.nl.mugnet.org (Fred N. van Kempen)
+ * Renamed "route_get_info()" to "rt_get_info()" for consistency.
+ * Alan Cox (gw4...@gw4pts.ampr.org) 4/94
+ * Dusted off the code and added IPX. Fixed the 4K limit.
+ * Erik Schoenfelder (scho...@ibr.cs.tu-bs.de)
+ * /proc/net/snmp.
+ * Alan Cox (gw4...@gw4pts.ampr.org) 1/95
+ * Added Appletalk slots
+ *
+ * proc diskarray directory handling functions
+ */
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+#include <linux/fcntl.h>
+#include <linux/mm.h>
+
+#include <asm/segment.h>
+
+#define PROC_BLOCK_SIZE (3*1024) /* 4K page size but our output routines use some slack for overruns */
+
+static int proc_readdiskarray(struct inode * inode, struct file * file,
+ char * buf, int count)
+{
+ char * page;
+ int bytes=count;
+ int copied=0;
+ char *start;
+ struct proc_dir_entry * dp;
+
+ if (count < 0)
+ return -EINVAL;
+ dp = (struct proc_dir_entry *) inode->u.generic_ip;
+ if (!(page = (char*) __get_free_page(GFP_KERNEL)))
+ return -ENOMEM;
+
+ while (bytes>0)
+ {
+ int length, thistime=bytes;
+ if (bytes > PROC_BLOCK_SIZE)
+ thistime=PROC_BLOCK_SIZE;
+
+ length = dp->get_info(page, &start,
+ file->f_pos,
+ thistime, (int)dp);
+
+ /*
+ * We have been given a non page aligned block of
+ * the data we asked for + a bit. We have been given
+ * the start pointer and we know the length..
+ */
+
+ if (length <= 0)
+ break;
+ /*
+ * Copy the bytes
+ */
+ memcpy_tofs(buf+copied, start, length);
+ file->f_pos += length; /* Move down the file */
+ bytes -= length;
+ copied += length;
+ if (length<thistime)
+ break; /* End of file */
+ }
+ free_page((unsigned long) page);
+ return copied;
+}
+
+static struct file_operations proc_diskarray_operations = {


+ NULL, /* lseek - default */

+ proc_readdiskarray, /* read - bad */
+ NULL, /* write - bad */
+ NULL, /* readdir */
+ NULL, /* select - default */
+ NULL, /* ioctl - default */


+ NULL, /* mmap */

+ NULL, /* no special open code */
+ NULL, /* no special release code */
+ NULL /* can't fsync */
+};
+
+/*
+ * proc directories can do almost nothing..
+ */
+struct inode_operations proc_diskarray_inode_operations = {
+ &proc_diskarray_operations, /* default diskarray file-ops */
+ NULL, /* create */
+ NULL, /* lookup */
+ NULL, /* link */
+ NULL, /* unlink */
+ NULL, /* symlink */
+ NULL, /* mkdir */
+ NULL, /* rmdir */
+ NULL, /* mknod */
+ NULL, /* rename */
+ NULL, /* readlink */
+ NULL, /* follow_link */
+ NULL, /* readpage */
+ NULL, /* writepage */
+ NULL, /* bmap */
+ NULL, /* truncate */
+ NULL /* permission */
+};
diff -u --recursive --new-file v2.0.36/linux/drivers/block/triton.c linux/drivers/block/triton.c
--- v2.0.36/linux/drivers/block/triton.c Sun Nov 15 10:49:32 1998
+++ linux/drivers/block/triton.c Sun Jun 13 10:21:00 1999
@@ -1,107 +1,18 @@
X /*
X * linux/drivers/block/triton.c Version 1.13 Aug 12, 1996
+ * Version 1.13a June 1998 - new chipsets
+ * Version 1.13b July 1998 - DMA blacklist
X *
X * Copyright (c) 1995-1996 Mark Lord
X * May be copied or modified under the terms of the GNU General Public License
X */
X
X /*
- * This module provides support for the Bus Master IDE DMA function
- * of the Intel PCI Triton I/II chipsets (i82371FB or i82371SB).
- *
- * Pretty much the same code will work for the OPTi "Viper" chipset.
- * Look for DMA support for this in linux kernel 2.1.xx, when it appears.
- *
- * DMA is currently supported only for hard disk drives (not cdroms).
- *
- * Support for cdroms will likely be added at a later date,
- * after broader experience has been obtained with hard disks.
- *
- * Up to four drives may be enabled for DMA, and the Triton chipset will
- * (hopefully) arbitrate the PCI bus among them. Note that the i82371 chip
- * provides a single "line buffer" for the BM IDE function, so performance of
- * multiple (two) drives doing DMA simultaneously will suffer somewhat,
- * as they contest for that resource bottleneck. This is handled transparently
- * inside the i82371 chip.
- *
- * By default, DMA support is prepared for use, but is currently enabled only
- * for drives which support multi-word DMA mode2 (mword2), or which are
- * recognized as "good" (see table below). Drives with only mode0 or mode1
- * (single or multi) DMA should also work with this chipset/driver (eg. MC2112A)
- * but are not enabled by default. Use "hdparm -i" to view modes supported
- * by a given drive.
- *
- * The hdparm-2.4 (or later) utility can be used for manually enabling/disabling
- * DMA support, but must be (re-)compiled against this kernel version or later.
- *
- * To enable DMA, use "hdparm -d1 /dev/hd?" on a per-drive basis after booting.
- * If problems arise, ide.c will disable DMA operation after a few retries.
- * This error recovery mechanism works and has been extremely well exercised.
- *
- * IDE drives, depending on their vintage, may support several different modes
- * of DMA operation. The boot-time modes are indicated with a "*" in
- * the "hdparm -i" listing, and can be changed with *knowledgeable* use of
- * the "hdparm -X" feature. There is seldom a need to do this, as drives
- * normally power-up with their "best" PIO/DMA modes enabled.
- *
- * Testing was done with an ASUS P55TP4XE/100 system and the following drives:
- *
- * Quantum Fireball 1080A (1Gig w/83kB buffer), DMA mode2, PIO mode4.
- * - DMA mode2 works well (7.4MB/sec), despite the tiny on-drive buffer.
- * - This drive also does PIO mode4, at about the same speed as DMA mode2.
- * An awesome drive for the price!
- *
- * Fujitsu M1606TA (1Gig w/256kB buffer), DMA mode2, PIO mode4.
- * - DMA mode2 gives horrible performance (1.6MB/sec), despite the good
- * size of the on-drive buffer and a boasted 10ms average access time.
- * - PIO mode4 was better, but peaked at a mere 4.5MB/sec.
- *
- * Micropolis MC2112A (1Gig w/508kB buffer), drive pre-dates EIDE and ATA2.
- * - DMA works fine (2.2MB/sec), probably due to the large on-drive buffer.
- * - This older drive can also be tweaked for fastPIO (3.7MB/sec) by using
- * maximum clock settings (5,4) and setting all flags except prefetch.
- *
- * Western Digital AC31000H (1Gig w/128kB buffer), DMA mode1, PIO mode3.
- * - DMA does not work reliably. The drive appears to be somewhat tardy
- * in deasserting DMARQ at the end of a sector. This is evident in
- * the observation that WRITEs work most of the time, depending on
- * cache-buffer occupancy, but multi-sector reads seldom work.
- *
- * Testing was done with a Gigabyte GA-586 ATE system and the following drive:
- * (Uwe Bonnes - b...@elektron.ikp.physik.th-darmstadt.de)
- *
- * Western Digital AC31600H (1.6Gig w/128kB buffer), DMA mode2, PIO mode4.
- * - much better than its 1Gig cousin, this drive is reported to work
- * very well with DMA (7.3MB/sec).
- *
- * Other drives:
- *
- * Maxtor 7540AV (515Meg w/32kB buffer), DMA modes mword0/sword2, PIO mode3.
- * - a budget drive, with budget performance, around 3MB/sec.
- *
- * Western Digital AC2850F (814Meg w/64kB buffer), DMA mode1, PIO mode3.
- * - another "caviar" drive, similar to the AC31000, except that this one
- * worked with DMA in at least one system. Throughput is about 3.8MB/sec
- * for both DMA and PIO.
- *
- * Conner CFS850A (812Meg w/64kB buffer), DMA mode2, PIO mode4.
- * - like most Conner models, this drive proves that even a fast interface
- * cannot improve slow media. Both DMA and PIO peak around 3.5MB/sec.
- *
- * Maxtor 71260AT (1204Meg w/256kB buffer), DMA mword0/sword2, PIO mode3.
- * - works with DMA, on some systems (but not always on others, eg. Dell),
- * giving 3-4MB/sec performance, about the same as mode3.
- *
- * If you have any drive models to add, email your results to: ml...@pobox.com
- * Keep an eye on /var/adm/messages for "DMA disabled" messages.
- *
- * Some people have reported trouble with Intel Zappa motherboards.
- * This can be fixed by upgrading the AMI BIOS to version 1.00.04.BS0,
- * available from ftp://ftp.intel.com/pub/bios/10004bs0.exe
- * (thanks to Glen Morrell <gl...@spin.Stanford.edu> for researching this).
- *
- * And, yes, Intel Zappa boards really *do* use the Triton IDE ports.
+ * This module provides support for Bus Master IDE DMA functions in various
+ * motherboard chipsets and PCI controller cards.
+ * Please check /Documentation/ide.txt and /Documentation/udma.txt for details.
X */
+
X #include <linux/config.h>
X #include <linux/types.h>
X #include <linux/kernel.h>
@@ -120,6 +31,13 @@
X #include "ide.h"
X
X #undef DISPLAY_TRITON_TIMINGS /* define this to display timings */
+#undef DISPLAY_APOLLO_TIMINGS /* define this for extensive debugging information */
+
+#if defined(CONFIG_PROC_FS) && defined(DISPLAY_APOLLO_TIMINGS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+#include <linux/via_ide_dma.h>
+#endif
X
X /*
X * good_dma_drives() lists the model names (from "hdparm -i")
@@ -132,6 +50,27 @@
X NULL};
X
X /*
+ * bad_dma_drives() lists the model names (from "hdparm -i")
+ * of drives which supposedly support (U)DMA but which are
+ * known to corrupt data with this interface under Linux.
+ *
+ * Note: the list was generated by statistical analysis of problem
+ * reports. It's not clear if there are problems with the drives,
+ * or with some combination of drive/controller or what.
+ *
+ * You can forcibly override this if you wish. This is the kernel
+ * 'Tread carefully' list.
+ *
+ * Finally see http://www.wdc.com/quality/err-rec.html if you have
+ * one of the listed drives.
+ */
+const char *bad_dma_drives[] = {"WDC AC11000H",
+ "WDC AC22100H",
+ "WDC AC32500H",
+ "WDC AC33100H",
+ NULL};
+
+/*
X * Our Physical Region Descriptor (PRD) table should be large enough
X * to handle the biggest I/O request we are likely to see. Since requests
X * can have no more than 256 sectors, and since the typical blocksize is
@@ -150,6 +89,7 @@
X #define PRD_BYTES 8
X #define PRD_ENTRIES (PAGE_SIZE / (2 * PRD_BYTES))
X #define DEFAULT_BMIBA 0xe800 /* in case BIOS did not init it */
+#define DEFAULT_BMCRBA 0xcc00 /* VIA's default value */
X
X /*
X * dma_intr() is the handler for disk read/write DMA interrupts
@@ -161,8 +101,8 @@
X struct request *rq = HWGROUP(drive)->rq;
X unsigned short dma_base = HWIF(drive)->dma_base;
X
- dma_stat = inb(dma_base+2); /* get DMA status */
X outb(inb(dma_base)&~1, dma_base); /* stop DMA operation */
+ dma_stat = inb(dma_base+2); /* get DMA status */
X stat = GET_STAT(); /* get drive status */
X if (OK_STAT(stat,DRIVE_READY,drive->bad_wstat|DRQ_STAT)) {
X if ((dma_stat & 7) == 4) { /* verify good DMA status */
@@ -244,23 +184,37 @@
X return 1; /* let the PIO routines handle this weirdness */
X }
X
+/*
+ * We will only enable drives with multi-word (mode2) (U)DMA capabilities,
+ * and ignore the very rare cases of drives that can only do single-word
+ * (modes 0 & 1) (U)DMA transfers. We also discard "blacklisted" hard disks.
+ */
X static int config_drive_for_dma (ide_drive_t *drive)
X {
X const char **list;
X struct hd_driveid *id = drive->id;
X
X if (id && (id->capability & 1)) {
- /* Enable DMA on any drive that has UltraDMA (mode 0/1/2) enabled */
+ /* Consult the list of known "bad" drives */
+ list = bad_dma_drives;
+ while (*list) {
+ if (!strcmp(*list++,id->model)) {
+ drive->using_dma = 0; /* no DMA */
+ printk("ide: Disabling DMA modes on %s drive (%s).\n", drive->name, id->model);
+ return 1; /* DMA disabled */
+ }
+ }
+ /* Enable DMA on any drive that has mode 2 UltraDMA enabled */
X if (id->field_valid & 4) /* UltraDMA */
- if ((id->dma_ultra & (id->dma_ultra >> 8) & 7)) {
+ if ((id->dma_ultra & 0x404) == 0x404) {
X drive->using_dma = 1;
- return 0; /* dma enabled */
+ return 0; /* DMA enabled */
X }
- /* Enable DMA on any drive that has mode2 DMA (multi or single) enabled */
+ /* Enable DMA on any drive that has mode2 DMA enabled */
X if (id->field_valid & 2) /* regular DMA */
- if ((id->dma_mword & 0x404) == 0x404 || (id->dma_1word & 0x404) == 0x404) {
+ if ((id->dma_mword & 0x404) == 0x404) {
X drive->using_dma = 1;
- return 0; /* dma enabled */
+ return 0; /* DMA enabled */
X }
X /* Consult the list of known "good" drives */
X list = good_dma_drives;
@@ -387,22 +341,135 @@
X }
X
X /*
+ * Set VIA Chipset Timings for (U)DMA modes enabled.
+ */
+static int set_via_timings (byte bus, byte fn, byte post, byte flush)
+{
+ byte via_config = 0;
+ int rc = 0;
+
+ /* setting IDE read prefetch buffer and IDE post write buffer */
+ if ((rc = pcibios_read_config_byte(bus, fn, 0x41, &via_config)))
+ return (1);
+ if ((rc = pcibios_write_config_byte(bus, fn, 0x41, via_config | post)))
+ return (1);
+
+ /* setting Channel read and End-of-sector FIFO flush: */
+ if ((rc = pcibios_read_config_byte(bus, fn, 0x46, &via_config)))
+ return (1);
+ if ((rc = pcibios_write_config_byte(bus, fn, 0x46, via_config | flush)))
+ return (1);
+
+ return (0);
+}
+
+/*
X * ide_init_triton() prepares the IDE driver for DMA operation.
X * This routine is called once, from ide.c during driver initialization,
- * for each triton chipset which is found (unlikely to be more than one).
+ * for each BM-DMA chipset which is found (rarely more than one).
X */
X void ide_init_triton (byte bus, byte fn)
X {
X int rc = 0, h;
X int dma_enabled = 0;
- unsigned short pcicmd;
- unsigned int bmiba, timings;
+ unsigned short io[6], count = 0, step_count = 0;
+ unsigned short pcicmd, vendor, device, class;
+ unsigned int bmiba, timings, reg, tmp;
+ unsigned int addressbios = 0;
+
+#ifdef DISPLAY_APOLLO_TIMINGS
+ bmide_bus = bus;
+ bmide_fn = fn;
+#endif /* DISPLAY_APOLLO_TIMINGS */
+
+/*
+ * We pick up the vendor, device, and class info for selecting the correct
+ * controller that is supported. Since we can access this routine more than
+ * once with the use of onboard and off-board EIDE controllers, a method
+ * of determining "who is who for what" is needed.
+ */
+
+ pcibios_read_config_word (bus, fn, PCI_VENDOR_ID, &vendor);
+ pcibios_read_config_word (bus, fn, PCI_DEVICE_ID, &device);
+ pcibios_read_config_word (bus, fn, PCI_CLASS_DEVICE, &class);
+
+ switch(vendor) {
+ case PCI_VENDOR_ID_INTEL:
+ printk("ide: Intel 82371 (single FIFO) DMA Bus Mastering IDE ");
+ break;
+ case PCI_VENDOR_ID_SI:
+ printk("ide: SiS 5513 (dual FIFO) DMA Bus Mastering IDE ");
+ break;
+ case PCI_VENDOR_ID_VIA:
+ printk("ide: VIA VT82C586B (split FIFO) UDMA Bus Mastering IDE ");
+ break;
+ case PCI_VENDOR_ID_PROMISE:
+ /* PCI_CLASS_STORAGE_RAID == class */
+ /*
+ * I have been able to make my Promise Ultra33 UDMA card change class.
+ * It has reported as both PCI_CLASS_STORAGE_RAID and PCI_CLASS_STORAGE_IDE.
+ * Since the PCI_CLASS_STORAGE_RAID mode should automatically mirror the
+ * two halves of the PCI_CONFIG register data, but sometimes it forgets.
+ * Thus we guarantee that they are identical, with a quick check and
+ * correction if needed.
+ * PDC20246 (primary) PDC20247 (secondary) IDE hwif's.
+ *
+ * Note that Promise "stories,fibs,..." about this device not being
+ * capable of ATAPI and AT devices.
+ */
+ if (PCI_CLASS_STORAGE_RAID == class) {
+ unsigned char irq1 = 0, irq2 = 0;
+ pcibios_read_config_byte (bus, fn, PCI_INTERRUPT_LINE, &irq1);
+ pcibios_read_config_byte (bus, fn, (PCI_INTERRUPT_LINE)|0x80, &irq2);
+ if (irq1 != irq2) {
+ pcibios_write_config_byte(bus, fn, (PCI_INTERRUPT_LINE)|0x80, irq1);
+ }
+ }
+ case PCI_VENDOR_ID_ARTOP:
+ /* PCI_CLASS_STORAGE_SCSI == class */
+ /*
+ * I have found that by stroking rom_enable_bit on both the AEC6210U/UF and
+ * PDC20246 controller cards, the features desired are almost guaranteed
+ * to be enabled and compatible. This ROM may not be registered in the
+ * config data, but it can be turned on. Registration failure has only
+ * been observed if and only if Linux sets up the pci_io_address in the
+ * 0x6000 range. If they are setup in the 0xef00 range it is reported.
+ * WHY??? got me.........
+ */
+ printk("ide: %s UDMA Bus Mastering ",
+ (vendor == PCI_VENDOR_ID_ARTOP) ? "AEC6210" : "PDC20246");
+ pcibios_read_config_dword(bus, fn, PCI_ROM_ADDRESS, &addressbios);
+ if (addressbios) {
+ pcibios_write_config_byte(bus, fn, PCI_ROM_ADDRESS, addressbios | PCI_ROM_ADDRESS_ENABLE);
+ printk("with ROM enabled at 0x%08x", addressbios);
+ }
+ /*
+ * This was stripped out of 2.1.XXX kernel code and parts from a patch called
+ * promise_update. This finds the PCI_BASE_ADDRESS spaces and makes them
+ * available for configuration later.
+ * PCI_BASE_ADDRESS_0 hwif0->io_base
+ * PCI_BASE_ADDRESS_1 hwif0->ctl_port


SHAR_EOF
true || echo 'restore of patch-2.0.37 failed'
fi

echo 'End of part 07'
echo 'File patch-2.0.37 is continued in part 08'
echo 08 > _shar_seq_.tmp
exit 0

Thomas...@ciw.uni-karlsruhe.de

unread,
Jun 16, 1999, 3:00:00 AM6/16/99
to
Archive-name: v2.0/patch-2.0.37/part09

#!/bin/sh
# this is part 09 of a 45 - part archive


# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.0.37 continued
if test ! -r _shar_seq_.tmp; then
echo 'Please unpack part 1 first!'
exit 1
fi
(read Scheck

if test "$Scheck" != 09; then


echo Please unpack part "$Scheck" next!
exit 1
else
exit 0
fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.0.37'
else
echo 'x - continuing with patch-2.0.37'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.0.37' &&

X printk(KERN_DEBUG "ISILoad:Firmware loader Opened!!!\n");
X #endif
+ MOD_INC_USE_COUNT;
X return 0;
X }
X
@@ -124,6 +125,7 @@
X #ifdef ISICOM_DEBUG
X printk(KERN_DEBUG "ISILoad:Firmware loader Close(Release)d\n",);
X #endif
+ MOD_DEC_USE_COUNT;
X }
X
X static int ISILoad_ioctl(struct inode *inode, struct file *filp,
diff -u --recursive --new-file v2.0.36/linux/drivers/char/keyboard.c linux/drivers/char/keyboard.c
--- v2.0.36/linux/drivers/char/keyboard.c Mon Aug 11 13:42:11 1997
+++ linux/drivers/char/keyboard.c Sun Jun 13 10:21:00 1999
@@ -374,8 +374,13 @@
X mark_bh(CONSOLE_BH);
X add_keyboard_randomness(scancode);
X
- tty = ttytab[fg_console];
- kbd = kbd_table + fg_console;
+ tty = ttytab? ttytab[fg_console]: NULL;
+ if (tty && (!tty->driver_data)) {
+ /* This is to workaround ugly bug in tty_io.c, which
+ does not do locking when it should */
+ tty = NULL;
+ }
+ kbd = kbd_table + fg_console;
X if ((raw_mode = (kbd->kbdmode == VC_RAW))) {
X put_queue(scancode);
X /* we do not return yet, because we want to maintain
diff -u --recursive --new-file v2.0.36/linux/drivers/char/random.c linux/drivers/char/random.c
--- v2.0.36/linux/drivers/char/random.c Sun Nov 15 21:51:46 1998
+++ linux/drivers/char/random.c Sun Jun 13 10:21:00 1999
@@ -1004,7 +1004,17 @@
X buf += i;
X add_timer_randomness(r, &extract_timer_state, nbytes);
X if (to_user && need_resched)
+ {
+ if(current->signal & ~current->blocked)
+ {
+ if(nbytes==0)
+ ret = -ERESTARTSYS;
+ else
+ ret -= nbytes;
+ break;
+ }
X schedule();
+ }
X }
X
X /* Wipe data from memory */
diff -u --recursive --new-file v2.0.36/linux/drivers/char/selection.h linux/drivers/char/selection.h
--- v2.0.36/linux/drivers/char/selection.h Mon Jul 13 13:46:28 1998
+++ linux/drivers/char/selection.h Sun Jun 13 10:21:00 1999
@@ -66,12 +66,13 @@
X #ifdef CONFIG_TGA_CONSOLE
X
X # ifdef CONFIG_VGA_CONSOLE
-extern int curr_cons;
X extern const struct console_desc cons_devices[];
X # endif
X
X extern unsigned long video_mem_term;
X
+int tga_blitc (unsigned int, unsigned long);
+
X /*
X * TGA console screen memory access
X *
@@ -110,8 +111,8 @@
X * TGA might need the char blitted to the screen,
X * but check first, we could be running on a VGA.
X */
- if (con_blitc && IS_VIDEO_MEMORY(addr))
- con_blitc(val, (unsigned long) addr);
+ if (tga_blitc && IS_VIDEO_MEMORY(addr))
+ tga_blitc(val, (unsigned long) addr);
X } else
X writew(val, (unsigned long) addr);
X }
diff -u --recursive --new-file v2.0.36/linux/drivers/char/serial.c linux/drivers/char/serial.c
--- v2.0.36/linux/drivers/char/serial.c Mon Jul 13 13:46:28 1998
+++ linux/drivers/char/serial.c Sun Jun 13 10:21:00 1999
@@ -19,6 +19,9 @@
X * flags INPCK, BRKINT, PARMRK, IGNPAR and IGNBRK.
X * Bernd Anhäupl 05/17/96.
X *
+ * Added Support for PCI serial boards which contain 16x50 Chips
+ * 31.10.1998 Henning P. Schmiedehausen <h...@tanstaafl.de>
+ *
X * This module exports the following rs232 io functions:
X *
X * int rs_init(void);
@@ -43,13 +46,18 @@
X #include <linux/ioport.h>
X #include <linux/mm.h>
X
+#ifdef CONFIG_SERIAL_PCI
+#include <linux/pci.h>
+#include <linux/bios32.h>
+#endif
+
X #include <asm/system.h>
X #include <asm/io.h>
X #include <asm/segment.h>
X #include <asm/bitops.h>
X
X static char *serial_name = "Serial driver";
-static char *serial_version = "4.13";
+static char *serial_version = "4.13p1";
X
X DECLARE_TASK_QUEUE(tq_serial);
X
@@ -83,6 +91,10 @@
X #undef SERIAL_DEBUG_OPEN
X #undef SERIAL_DEBUG_FLOW
X
+#ifdef CONFIG_SERIAL_PCI
+# undef SERIAL_DEBUG_PCI
+#endif
+
X #define RS_STROBE_TIME (10*HZ)
X #define RS_ISR_PASS_LIMIT 256
X
@@ -121,6 +133,14 @@
X */
X #define BASE_BAUD ( 1843200 / 16 )
X
+/*
+ * Well, it is not a 24,756 MHz clock but it is at least a start.
+ * This PCI board here has a 14,7456 MHz crystal oscillator which is
+ * eight times as fast as the standard serial clock...
+ */
+
+#define PCI_BAUD ( 14745600 / 16 )
+
X /* Standard COM flags (except for COM4, because of the 8514 problem) */
X #define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST )
X #define STD_COM4_FLAGS ASYNC_BOOT_AUTOCONF
@@ -130,6 +150,29 @@
X #define BOCA_FLAGS 0
X #define HUB6_FLAGS 0
X
+#ifdef CONFIG_SERIAL_PCI
+
+#define PCI_FLAGS (ASYNC_PCI|ASYNC_BOOT_AUTOCONF)
+
+#ifndef PCI_DEVICE_ID_PLX_SPCOM200
+#define PCI_DEVICE_ID_PLX_SPCOM200 0x1103
+#endif
+
+/*
+ * The chips we know about
+ */
+
+#define PCISER_PLX9050 0 /* PLX 9050 local bus bridge as serial card */
+#define PCISER_PCCOM4 1 /* "PC COM PCI Bus 4 port serial Adapter" -- from Alvin Sim <al...@alloycp.com.au> */
+
+struct pci_serial_boards pci_serial_tbl[] = {
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_SPCOM200, "SPCom 200", PCISER_PLX9050, pci_space_0|pci_space_1, 1, 0, 128, PCI_BAUD },
+ { PCI_VENDOR_ID_DCI, PCI_DEVICE_ID_DCI_PCCOM4, "PC COM 4", PCISER_PCCOM4, pci_space_0, 4, 8, 128, BASE_BAUD },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0 }
+};
+
+#endif
+
X /*
X * The following define the access methods for the HUB6 card. All
X * access is through two ports for all 24 possible chips. The card is
@@ -202,10 +245,42 @@
X { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,4) }, /* ttyS42 */
X { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,5) }, /* ttyS43 */
X #endif
+
+#ifdef CONFIG_SERIAL_PCI
+ { 0, BASE_BAUD, 0x0, 0, 0 }, /* ttyS32 or bigger... */
+ { 0, BASE_BAUD, 0x0, 0, 0 }, /* ttyS33 */
+ { 0, BASE_BAUD, 0x0, 0, 0 }, /* ttyS34 */
+ { 0, BASE_BAUD, 0x0, 0, 0 }, /* ttyS35 */
+ { 0, BASE_BAUD, 0x0, 0, 0 }, /* ttyS36 */
+ { 0, BASE_BAUD, 0x0, 0, 0 }, /* ttyS37 */
+ { 0, BASE_BAUD, 0x0, 0, 0 }, /* ttyS38 */
+ { 0, BASE_BAUD, 0x0, 0, 0 }, /* ttyS39 */
+#endif
X };
X
X #define NR_PORTS (sizeof(rs_table)/sizeof(struct async_struct))
X
+#ifdef CONFIG_SERIAL_PCI
+
+/*
+ * currently you can have up to four PCI serial boards in your
+ * system. Increase the size of this structure to have more
+ */
+
+struct pci_struct pci_rs_chips[] = {
+ {0, 0,},
+ {0, 0,},
+ {0, 0,},
+ {0, 0,},
+};
+
+#define PCI_NR_BOARDS (sizeof(pci_rs_chips)/sizeof(struct pci_struct))
+#define PCI_NR_PORTS 8
+
+#define PCI_PORT_START (NR_PORTS - PCI_NR_PORTS)
+
+#endif
+
X static struct tty_struct *serial_table[NR_PORTS];
X static struct termios *serial_termios[NR_PORTS];
X static struct termios *serial_termios_locked[NR_PORTS];
@@ -1731,6 +1806,26 @@
X
X
X /*
+ * rs_break() --- routine which turns the break handling on or off
+ * adapted from 2.1.124
+ */
+static void rs_break(struct async_struct * info, int break_state)
+{
+ unsigned long flags;
+
+ if (!info->port)
+ return;
+ save_flags(flags);cli();
+ if (break_state == -1)
+ serial_out(info, UART_LCR,
+ serial_inp(info, UART_LCR) | UART_LCR_SBC);
+ else
+ serial_out(info, UART_LCR,
+ serial_inp(info, UART_LCR) & ~UART_LCR_SBC);
+ restore_flags(flags);
+}
+
+/*
X * This routine sends a break character out the serial port.
X */
X static void send_break( struct async_struct * info, int duration)
@@ -1922,6 +2017,20 @@
X }
X
X switch (cmd) {
+ case TIOCSBRK: /* Turn break on, unconditionally */
+ retval = tty_check_change(tty);
+ if (retval)
+ return retval;
+ tty_wait_until_sent(tty, 0);
+ rs_break(info,-1);
+ return 0;
+ case TIOCCBRK: /* Turn break off, unconditionally */
+ retval = tty_check_change(tty);
+ if (retval)
+ return retval;
+ tty_wait_until_sent(tty, 0);
+ rs_break(info,0);
+ return 0;
X case TCSBRK: /* SVID version: non-zero arg --> no break */
X retval = tty_check_change(tty);
X if (retval)
@@ -2478,6 +2587,10 @@
X static void show_serial_version(void)
X {
X printk(KERN_INFO "%s version %s with", serial_name, serial_version);
+#ifdef CONFIG_SERIAL_PCI
+ printk(" PCI");
+#define SERIAL_OPT
+#endif
X #ifdef CONFIG_HUB6
X printk(" HUB-6");
X #define SERIAL_OPT
@@ -2712,6 +2825,73 @@
X restore_flags(flags);
X }
X
+void display_uart_type(int type)
+{
+ switch (type) {
+ case PORT_8250:
+ printk(" is a 8250\n");
+ break;
+ case PORT_16450:
+ printk(" is a 16450\n");
+ break;
+ case PORT_16550:
+ printk(" is a 16550\n");
+ break;
+ case PORT_16550A:
+ printk(" is a 16550A\n");
+ break;
+ case PORT_16650:
+ printk(" is a 16650\n");
+ break;
+ default:
+ printk("\n");


+ break;
+ }
+}
+

+void init_port(struct async_struct *info, int num)
+{
+ info->magic = SERIAL_MAGIC;
+ info->line = num;
+ info->tty = 0;
+ info->type = PORT_UNKNOWN;
+ info->custom_divisor = 0;
+ info->close_delay = 5*HZ/10;
+ info->closing_wait = 30*HZ;
+ info->x_char = 0;
+ info->event = 0;
+ info->count = 0;
+ info->blocked_open = 0;
+ info->tqueue.routine = do_softint;
+ info->tqueue.data = info;
+ info->tqueue_hangup.routine = do_serial_hangup;
+ info->tqueue_hangup.data = info;
+ info->callout_termios =callout_driver.init_termios;
+ info->normal_termios = serial_driver.init_termios;
+ info->open_wait = 0;
+ info->close_wait = 0;
+ info->delta_msr_wait = 0;
+ info->icount.cts = info->icount.dsr =
+ info->icount.rng = info->icount.dcd = 0;
+ info->next_port = 0;
+ info->prev_port = 0;
+ if (info->irq == 2)
+ info->irq = 9;
+
+ if (info->type == PORT_UNKNOWN) {
+ if (!(info->flags & ASYNC_BOOT_AUTOCONF))
+ return;
+ autoconfig(info);
+ if (info->type == PORT_UNKNOWN)
+ return;
+ }
+ printk(KERN_INFO "ttyS%02d%s%s at 0x%04x (irq = %d)", info->line,
+ (info->flags & ASYNC_FOURPORT) ? " FourPort" : "",
+ (info->flags & ASYNC_PCI) ? " PCI" : "",
+ info->port, info->irq);
+ display_uart_type(info->type);
+}
+
X int register_serial(struct serial_struct *req);
X void unregister_serial(int line);
X
@@ -2722,9 +2902,212 @@
X #include <linux/symtab_end.h>
X };
X
+#ifdef CONFIG_SERIAL_PCI
+
+/*
+ * Query PCI space for known serial boards
+ * If found, add them to the PCI device space in rs_table[]
+ *
+ * Accept a maximum of eight boards


+ *
+ */
+

+static void probe_serial_pci(void)
+{
+ u16 vendor, device;
+ static int pci_index = 0;
+ unsigned char pci_bus, pci_device_fn;
+ struct async_struct *pci_boards = &rs_table[PCI_PORT_START];
+ unsigned int port_num = 0;
+ unsigned int card_num = 0;
+
+ u32 device_ioaddr;
+ u8 device_irq;
+
+ enum pci_spc pci_space = pci_space_0;
+ unsigned int pci_space_offset = 0;
+
+
+#ifdef SERIAL_DEBUG_PCI
+ printk(KERN_DEBUG "Entered probe_serial_pci()\n");
+#endif
+
+ if (! pcibios_present()) {
+#ifdef SERIAL_DEBUG_PCI
+ printk(KERN_DEBUG "Leaving probe_serial_pci() (no pcibios)\n");
+#endif
+ return;
+ }
+
+/*
+ * Start scanning the PCI bus for serial controllers ...


+ *
+ */
+

+ for (;pci_index < 0xff; pci_index++) {
+ int i = 0;
+
+ if (pcibios_find_class(PCI_CLASS_COMMUNICATION_SERIAL << 8,
+ pci_index,
+ &pci_bus,
+ &pci_device_fn) != PCIBIOS_SUCCESSFUL)
+ break; /* for (; pci_index ... */
+
+ pcibios_read_config_word(pci_bus, pci_device_fn, PCI_VENDOR_ID, &vendor);
+ pcibios_read_config_word(pci_bus, pci_device_fn, PCI_DEVICE_ID, &device);
+
+ for (i = 0; pci_serial_tbl[i].board_name; i++) {
+ if (vendor == pci_serial_tbl[i].vendor_id &&
+ device == pci_serial_tbl[i].device_id)
+ break; /* for(i=0... */
+ }
+
+ if (pci_serial_tbl[i].board_name == 0) {
+#ifdef SERIAL_DEBUG_PCI
+ printk(KERN_DEBUG "Found Board (%x/%x) (not one of us)\n", vendor, device);
+#endif
+ continue; /* Found a serial communication controller but not one we know */
+ }
+
+/*
+ * At this point we found a serial board which we know
+ */
+
+ if(card_num >= PCI_NR_BOARDS) {
+ printk(KERN_ERR "Already %d boards configured, skipping\n", PCI_NR_BOARDS);
+ continue; /* for (;pci_index < 0xff */
+ }
+
+ pcibios_read_config_byte(pci_bus, pci_device_fn,
+ PCI_INTERRUPT_LINE, &device_irq);
+ pcibios_read_config_dword(pci_bus, pci_device_fn,
+ PCI_BASE_ADDRESS_1, &device_ioaddr);
+
+#ifdef SERIAL_DEBUG_PCI
+ printk(KERN_DEBUG "Device %s at #%x found\n", pci_serial_tbl[i].board_name, device_ioaddr);
+#endif
+
+ if (check_region(device_ioaddr, pci_serial_tbl[i].io_size)) {
+ printk(KERN_ERR "Could not reserve %d bytes of I/O Space at %x\n", pci_serial_tbl[i].io_size, device_ioaddr);
+ continue; /* for (;pci_index < 0xff */
+ }
+
+/*
+ * Every PCI device brings 128 bytes (at least) of IO-Space with it
+ * reserve a region for it. It is not exactly necessary as PCI will
+ * ensure that no other device will be mapped onto this space (LOL)
+ * but we do it nevertheless so it will show up nicely on
+ * /proc/ioports -- hps
+ */
+
+ if((device_ioaddr & 1) == 0) {
+#ifdef SERIAL_DEBUG_PCI
+ device_ioaddr &= ~0x7f;
+ printk(KERN_DEBUG "%s has its config registers memory-mapped at #%x (ignoring)\n",
+ pci_serial_tbl[i].board_name, device_ioaddr);
+#endif
+ continue; /* for (;pci_index < 0xff */
+ }
+
+ device_ioaddr &= ~0x7f; /* Mask out the flag bits
+ * from this register. At least on the PLX9050
+ * they're always 0 but this is here nevertheless
+ * for sanity's sake
+ */
+
+ request_region(device_ioaddr, pci_serial_tbl[i].io_size, "serial (PCI Controller)");
+
+ pci_rs_chips[card_num].start = device_ioaddr;
+ pci_rs_chips[card_num].type = &pci_serial_tbl[i];
+
+
+/*
+ * Every PCI device can bring up to four PCI memory or IO spaces (at
+ * least according to the documentation I have. So we will now check
+ * with our config whether this device has one of these spaces and we
+ * should configure UARTs inside -- hps
+ */
+
+ for(; pci_space <= pci_space_3; pci_space <<= 1, pci_space_offset+= 4) {
+ u32 uart_chip_base;
+ u32 uart_chip_count;
+
+ if((pci_serial_tbl[i].pci_space & pci_space) == 0)
+ continue; /* for(;pci_space... */
+
+ pcibios_read_config_dword(pci_bus, pci_device_fn,
+ PCI_BASE_ADDRESS_2+pci_space_offset, &uart_chip_base);
+
+ if((uart_chip_base & 1) == 0) {
+#ifdef SERIAL_DEBUG_PCI
+ chip_base &= ~0x0f;
+ printk(KERN_DEBUG "%s has a memory-mapped IO Chip at #%x (ignoring)\n",
+ pci_serial_tbl[i].board_name, chip_base);
+#endif
+ continue; /* for(;pci_space... */
+ }
+
+ uart_chip_base &= ~0x0f;
+
+/*
+ * uart_chip_base now points to the IO-Space.
+ *
+ * Alvin Sim <al...@alloycp.com.au> told me the following thing:
+ *
+ * UARTS can be "setserial"d by kernel 2.0.35, but ports needed to be
+ * manually specified. 4 ports start at 0x6100, in increments of 8
+ * addresses.
+ *
+ * so there is at least one board out there which can do more than one
+ * UART in a single PCI config space. My trustworthy SPCom 200 PCI has
+ * just one UART in one config space. So I added a check for more than
+ * one chip in a config space -- hps


+ *
+ */
+

+ for(uart_chip_count=0;uart_chip_count < pci_serial_tbl[i].dev_per_space; uart_chip_count++) {
+#ifdef SERIAL_DEBUG_PCI
+ printk(KERN_DEBUG "%s has an IO Chip at #%x\n",
+ pci_serial_tbl[i].board_name, uart_chip_base);
+#endif
+
+ if(port_num >= PCI_NR_PORTS) {
+ printk(KERN_ERR "Already %d ports configured, skipping\n", PCI_NR_PORTS);
+ break; /* for(;uart_chip_count... */
+ }
+
+ if (check_region(uart_chip_base, 8)) {
+ printk(KERN_ERR "Could not reserve %d bytes of I/O Space at %x\n", 8, uart_chip_base);
+ break; /* for(;uart_chip_count... */
+ }
+
+ request_region(uart_chip_base, 8, "serial (PCI)");
+ pci_boards[port_num].port = uart_chip_base;
+ pci_boards[port_num].irq = device_irq;
+ pci_boards[port_num].flags = PCI_FLAGS;
+ pci_boards[port_num].baud_base = pci_serial_tbl[i].baud_base;
+
+ port_num++;
+ uart_chip_base += pci_serial_tbl[i].dev_spacing;
+
+ } /* for(uart_chip_count... */
+ } /* for(pci_space ... */
+
+ card_num++;
+ } /* for */
+
+#ifdef SERIAL_DEBUG_PCI
+ printk(KERN_DEBUG "Leaving probe_serial_pci() (probe finished)\n");
+#endif
+ return;
+}
+
+#endif /* CONFIG_SERIAL_PCI */
+
X /*
X * The serial driver boot-time initialization code!
X */
+
X int rs_init(void)
X {
X int i;
@@ -2744,6 +3127,9 @@
X }
X
X show_serial_version();
+#ifdef CONFIG_SERIAL_PCI
+ probe_serial_pci();
+#endif
X
X /* Initialize the tty_driver structure */
X
@@ -2795,67 +3181,15 @@
X panic("Couldn't register callout driver\n");
X
X for (i = 0, info = rs_table; i < NR_PORTS; i++,info++) {
- info->magic = SERIAL_MAGIC;
- info->line = i;
- info->tty = 0;
- info->type = PORT_UNKNOWN;
- info->custom_divisor = 0;
- info->close_delay = 5*HZ/10;
- info->closing_wait = 30*HZ;
- info->x_char = 0;
- info->event = 0;
- info->count = 0;
- info->blocked_open = 0;
- info->tqueue.routine = do_softint;
- info->tqueue.data = info;
- info->tqueue_hangup.routine = do_serial_hangup;
- info->tqueue_hangup.data = info;
- info->callout_termios =callout_driver.init_termios;
- info->normal_termios = serial_driver.init_termios;
- info->open_wait = 0;
- info->close_wait = 0;
- info->delta_msr_wait = 0;
- info->icount.cts = info->icount.dsr =
- info->icount.rng = info->icount.dcd = 0;
- info->next_port = 0;
- info->prev_port = 0;
- if (info->irq == 2)
- info->irq = 9;
- if (info->type == PORT_UNKNOWN) {
- if (!(info->flags & ASYNC_BOOT_AUTOCONF))
- continue;
- autoconfig(info);
- if (info->type == PORT_UNKNOWN)
- continue;
- }
- printk(KERN_INFO "tty%02d%s at 0x%04x (irq = %d)", info->line,
- (info->flags & ASYNC_FOURPORT) ? " FourPort" : "",
- info->port, info->irq);
- switch (info->type) {
- case PORT_8250:
- printk(" is a 8250\n");
- break;
- case PORT_16450:
- printk(" is a 16450\n");
- break;
- case PORT_16550:
- printk(" is a 16550\n");
- break;
- case PORT_16550A:
- printk(" is a 16550A\n");
- break;
- case PORT_16650:
- printk(" is a 16650\n");
- break;
- default:
- printk("\n");
- break;
- }
- }
+ init_port(info, i);
+ };
+
X register_symtab(&serial_syms);
X return 0;
X }
X
+
+
X /*
X * register_serial and unregister_serial allows for serial ports to be
X * configured at run-time, to support PCMCIA modems.
@@ -2898,20 +3232,9 @@
X printk("register_serial(): autoconfig failed\n");
X return -1;
X }
- printk(KERN_INFO "tty%02d at 0x%04x (irq = %d)", info->line,
+ printk(KERN_INFO "ttyS%02d at 0x%04x (irq = %d)", info->line,
X info->port, info->irq);
- switch (info->type) {
- case PORT_8250:
- printk(" is a 8250\n"); break;
- case PORT_16450:
- printk(" is a 16450\n"); break;
- case PORT_16550:
- printk(" is a 16550\n"); break;
- case PORT_16550A:
- printk(" is a 16550A\n"); break;
- default:
- printk("\n"); break;
- }
+ display_uart_type(info->type);
X restore_flags(flags);
X return info->line;
X }
@@ -2926,7 +3249,7 @@
X if (info->tty)
X tty_hangup(info->tty);
X info->type = PORT_UNKNOWN;
- printk(KERN_INFO "tty%02d unloaded\n", info->line);
+ printk(KERN_INFO "ttyS%02d unloaded\n", info->line);
X restore_flags(flags);
X }
X
@@ -2960,6 +3283,18 @@
X if (rs_table[i].type != PORT_UNKNOWN)
X release_region(rs_table[i].port, 8);
X }
+
+#ifdef CONFIG_SERIAL_PCI
+ for (i = 0; i < PCI_NR_BOARDS; i++) {
+ if (pci_rs_chips[i].start != 0x0) {
+#ifdef SERIAL_DEBUG_PCI
+ printk(KERN_DEBUG "Releasing %d Bytes at #%x\n", pci_rs_chips[i].type->io_size, pci_rs_chips[i].start);
+#endif
+ release_region(pci_rs_chips[i].start, pci_rs_chips[i].type->io_size);
+ }
+ }
+#endif
+
X if (tmp_buf) {
X free_page((unsigned long) tmp_buf);
X tmp_buf = NULL;
diff -u --recursive --new-file v2.0.36/linux/drivers/char/tga.c linux/drivers/char/tga.c
--- v2.0.36/linux/drivers/char/tga.c Sun Nov 15 21:51:46 1998
+++ linux/drivers/char/tga.c Sun Jun 13 10:21:01 1999
@@ -40,6 +40,7 @@
X
X extern void register_console(void (*proc)(const char *));
X extern void console_print(const char *);
+extern void set_palette (void); /* vga.c */
X
X /* TGA hardware description (minimal) */
X /*
@@ -484,11 +485,6 @@
X tga_init_video();
X tga_clear_screen();
X
-#ifdef CONFIG_VGA_CONSOLE
- /* if both are configured, we are using a dispatch table,
- so we must set the index */
- curr_cons = 1;
-#endif
X }
X
X unsigned char PLLbits[7] = { 0x80, 0x04, 0x00, 0x24, 0x44, 0x80, 0xb8 };
diff -u --recursive --new-file v2.0.36/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c
--- v2.0.36/linux/drivers/char/tty_io.c Sun Nov 15 21:51:46 1998
+++ linux/drivers/char/tty_io.c Sun Jun 13 10:21:01 1999
@@ -964,7 +964,13 @@
X * Failures after this point use release_mem to clean up, so
X * there's no need to null out the local pointers.
X */
- driver->table[idx] = tty;
+ driver->table[idx] = tty; /* FIXME: this is broken and
+ probably causes ^D bug. tty->private_date does not (yet) point
+ to a console, if keypress comes now, await armagedon.
+
+ also, driver->table is accessed from interrupt for vt case,
+ and this does not look like atomic access at all. */
+
X if (!*tp_loc)
X *tp_loc = tp;
X if (!*ltp_loc)
@@ -1926,8 +1932,9 @@
X {
X int retval;
X struct tty_driver *p;
- int found = 0;
+ int i, found = 0;
X const char *othername = NULL;
+ struct termios *tp;
X
X if (*driver->refcount)
X return -EBUSY;
@@ -1957,6 +1964,18 @@
X if (driver->next)
X driver->next->prev = driver->prev;
X
+ for (i = 0; i < driver->num; i++) {
+ tp = driver->termios[i];
+ if (tp != NULL) {
+ kfree_s(tp, sizeof(struct termios));
+ driver->termios[i] = NULL;
+ }
+ tp = driver->termios_locked[i];
+ if (tp != NULL) {
+ kfree_s(tp, sizeof(struct termios));
+ driver->termios_locked[i] = NULL;
+ }
+ }
X return 0;
X }
X
diff -u --recursive --new-file v2.0.36/linux/drivers/isdn/isdn_net.c linux/drivers/isdn/isdn_net.c
--- v2.0.36/linux/drivers/isdn/isdn_net.c Sun Nov 15 21:51:46 1998
+++ linux/drivers/isdn/isdn_net.c Sun Jun 13 10:21:01 1999
@@ -1,4 +1,4 @@
-/* $Id: isdn_net.c,v 1.48.2.27 1998/11/05 22:11:53 fritz Exp $
+/* $Id: isdn_net.c,v 1.48.2.28 1998/11/27 15:38:12 paul Exp $
X
X * Linux ISDN subsystem, network interfaces and related functions (linklevel).
X *
@@ -21,6 +21,9 @@
X * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X *
X * $Log: isdn_net.c,v $
+ * Revision 1.48.2.28 1998/11/27 15:38:12 paul
+ * Also huptimeout with dialmode == manual
+ *
X * Revision 1.48.2.27 1998/11/05 22:11:53 fritz
X * Changed mail-address.
X *
@@ -350,11 +353,11 @@
X static int isdn_net_xmit(struct device *, isdn_net_local *, struct sk_buff *);
X static void dev_purge_queues(struct device *dev); /* move this to net/core/dev.c */
X
-char *isdn_net_revision = "$Revision: 1.48.2.27 $";
+char *isdn_net_revision = "$Revision: 1.48.2.28 $";
X
- /*
- * Code for raw-networking over ISDN
- */
+/*
+ * Code for raw-networking over ISDN
+ */
X
X static void
X isdn_net_unreachable(struct device *dev, struct sk_buff *skb, char *reason)
@@ -362,7 +365,6 @@
X int i;
X
X if(skb != NULL) {
-
X u_short proto = ntohs(skb->protocol);
X
X printk(KERN_DEBUG "isdn_net: %s: %s, send ICMP %s\n",
@@ -538,13 +540,14 @@
X if ((l->flags & ISDN_NET_CONNECTED) && (!l->dialstate)) {
X anymore = 1;
X l->huptimer++;
- /*
- * only do timeout-hangup
- * if interface is configured as AUTO
- */
- if ((ISDN_NET_DIALMODE(*l) == ISDN_NET_DM_AUTO) &&
- (l->onhtime) &&
- (l->huptimer > l->onhtime))
+ /*
+ * if there is some dialmode where timeout-hangup
+ * should _not_ be done, check for that here and
+ * 35 lines below (ifdef CONFIG_ISDN_BUDGET)
+ * eg: (ISDN_NET_DIALMODE(*l) != ISDN_NET_DM_NOTIMEOUT)
+ */
+ if ((l->onhtime) &&
+ (l->huptimer > l->onhtime))
X if (l->hupflags & ISDN_MANCHARGE &&
X l->hupflags & ISDN_CHARGEHUP) {
X while (jiffies - l->chargetime > l->chargeint)
diff -u --recursive --new-file v2.0.36/linux/drivers/isdn/isdn_ppp.c linux/drivers/isdn/isdn_ppp.c
--- v2.0.36/linux/drivers/isdn/isdn_ppp.c Sun Nov 15 21:51:46 1998
+++ linux/drivers/isdn/isdn_ppp.c Sun Jun 13 10:21:01 1999
@@ -1,4 +1,4 @@
-/* $Id: isdn_ppp.c,v 1.28.2.2 1998/11/03 14:31:23 fritz Exp $
+/* $Id: isdn_ppp.c,v 1.28.2.3 1998/12/30 17:49:00 paul Exp $
X *
X * Linux ISDN subsystem, functions for synchronous PPP (linklevel).
X *
@@ -19,6 +19,9 @@
X * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X *
X * $Log: isdn_ppp.c,v $
+ * Revision 1.28.2.3 1998/12/30 17:49:00 paul
+ * fixed syncPPP callback out
+ *
X * Revision 1.28.2.2 1998/11/03 14:31:23 fritz
X * Reduced stack usage in various functions.
X * Adapted statemachine to work with certified HiSax.
@@ -181,7 +184,7 @@
X static void isdn_ppp_free_mpqueue(isdn_net_dev *);
X #endif
X
-char *isdn_ppp_revision = "$Revision: 1.28.2.2 $";
+char *isdn_ppp_revision = "$Revision: 1.28.2.3 $";
X
X static struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS];
X static struct isdn_ppp_compressor *ipc_head = NULL;
@@ -303,7 +306,8 @@
X }
X } else {
X for (i = 0; i < ISDN_MAX_CHANNELS; i++)
- if (ippp_table[i]->minor == lp->pppbind && ippp_table[i]->state == IPPP_OPEN)
+ if (ippp_table[i]->minor == lp->pppbind &&
+ (ippp_table[i]->state & IPPP_OPEN) == IPPP_OPEN)
X break;
X }
X
diff -u --recursive --new-file v2.0.36/linux/drivers/net/3c59x.c linux/drivers/net/3c59x.c
--- v2.0.36/linux/drivers/net/3c59x.c Sun Nov 15 21:51:46 1998
+++ linux/drivers/net/3c59x.c Sun Jun 13 10:21:01 1999
@@ -15,18 +15,19 @@
X */
X
X static char *version =
-"3c59x.c:v0.99E 5/12/98 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/vortex.html\n";
+"3c59x.c:v0.99H 11/17/98 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/vortex.html\n";
X
X /* "Knobs" that adjust features and parameters. */
X /* Set the copy breakpoint for the copy-only-tiny-frames scheme.
X Setting to > 1512 effectively disables this feature. */
-static const rx_copybreak = 200;
+static const int rx_copybreak = 200;
X /* Allow setting MTU to a larger size, bypassing the normal ethernet setup. */
-static const mtu = 1500;
+static const int mtu = 1500;
X /* Maximum events (Rx packets, etc.) to handle at each interrupt. */
X static int max_interrupt_work = 20;
X
X /* Put out somewhat more debugging messages. (0: no msg, 1 minimal .. 6). */
+#define vortex_debug debug
X #ifdef VORTEX_DEBUG
X static int vortex_debug = VORTEX_DEBUG;
X #else
@@ -37,15 +38,6 @@
X debugging. */
X static int rx_nocopy = 0, rx_copy = 0, queued_packet = 0, rx_csumhits;
X
-/* Enable the automatic media selection code -- usually set. */
-#define AUTOMEDIA 1
-
-/* Allow the use of fragment bus master transfers instead of only
- programmed-I/O for Vortex cards. Full-bus-master transfers are always
- enabled by default on Boomerang cards. If VORTEX_BUS_MASTER is defined,
- the feature may be turned on using 'options'. */
-#define VORTEX_BUS_MASTER
-
X /* A few values that may be tweaked. */
X /* Time in jiffies before concluding the transmitter is hung. */
X #define TX_TIMEOUT ((400*HZ)/1000)
@@ -56,12 +48,12 @@
X #define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/
X
X #include <linux/config.h>
+#include <linux/version.h>
X #ifdef MODULE
X #ifdef MODVERSIONS
X #include <linux/modversions.h>
X #endif
X #include <linux/module.h>
-#include <linux/version.h>
X #else
X #define MOD_INC_USE_COUNT
X #define MOD_DEC_USE_COUNT
@@ -70,68 +62,61 @@
X #include <linux/kernel.h>
X #include <linux/sched.h>
X #include <linux/string.h>
-#include <linux/ptrace.h>
+#include <linux/timer.h>
X #include <linux/errno.h>
X #include <linux/in.h>
X #include <linux/ioport.h>
X #include <linux/malloc.h>
X #include <linux/interrupt.h>
X #include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#if LINUX_VERSION_CODE < 0x20155 || defined(CARDBUS)
X #include <linux/bios32.h>
-#include <linux/timer.h>
+#endif
X #include <asm/irq.h> /* For NR_IRQS only. */
X #include <asm/bitops.h>
X #include <asm/io.h>
X
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-
-/* Kernel compatibility defines, common to David Hind's PCMCIA package.
+/* Kernel compatibility defines, some common to David Hinds' PCMCIA package.
X This is only in the support-all-kernels source code. */
-#ifndef LINUX_VERSION_CODE
-#include <linux/version.h> /* Redundant above, here for easy clean-up. */
-#endif
-#if LINUX_VERSION_CODE < 0x10300
-#define RUN_AT(x) (x) /* What to put in timer->expires. */
-#define DEV_ALLOC_SKB(len) alloc_skb(len, GFP_ATOMIC)
-#if defined(__alpha)
-#error "The Alpha architecture is only support with kernel version 2.0."
-#endif
-#define virt_to_bus(addr) ((unsigned long)addr)
-#define bus_to_virt(addr) ((void*)addr)
-#define NR_IRQS 16
-#else /* 1.3.0 and later */
-#define RUN_AT(x) (jiffies + (x))
-#define DEV_ALLOC_SKB(len) dev_alloc_skb(len)
-#endif
-#if LINUX_VERSION_CODE < 0x20159
-#define DEV_FREE_SKB(skb) dev_kfree_skb (skb, FREE_WRITE);
-#else /* Grrr, unneeded incompatible change. */
-#define DEV_FREE_SKB(skb) dev_kfree_skb(skb);
-#endif
X
-#ifdef SA_SHIRQ
-#define FREE_IRQ(irqnum, dev) free_irq(irqnum, dev)
-#define REQUEST_IRQ(i,h,f,n, instance) request_irq(i,h,f,n, instance)
-#define IRQ(irq, dev_id, pt_regs) (irq, dev_id, pt_regs)
-#else
-#define FREE_IRQ(irqnum, dev) free_irq(irqnum)
-#define REQUEST_IRQ(i,h,f,n, instance) request_irq(i,h,f,n)
-#define IRQ(irq, dev_id, pt_regs) (irq, pt_regs)
-#endif
+#define RUN_AT(x) (jiffies + (x))
X
-#if (LINUX_VERSION_CODE >= 0x10344)
-#define NEW_MULTICAST
X #include <linux/delay.h>
+
+#if (LINUX_VERSION_CODE >= 0x20100)
+char kernel_version[] = UTS_RELEASE;
X #else
-#define udelay(microsec) do { int _i = 4*microsec; while (--_i > 0) { __SLOW_DOWN_IO; }} while (0)
+#ifndef __alpha__
+#define ioremap(a,b) \
+ (((a)<0x100000) ? (void *)((u_long)(a)) : vremap(a,b))
+#define iounmap(v) \
+ do { if ((u_long)(v) > 0x100000) vfree(v); } while (0)
+#endif
+#endif
+#if LINUX_VERSION_CODE <= 0x20139
+#define net_device_stats enet_statistics
+#define NETSTATS_VER2
X #endif
-
X #if LINUX_VERSION_CODE < 0x20138
X #define test_and_set_bit(val, addr) set_bit(val, addr)
+#define le32_to_cpu(val) (val)
+#define cpu_to_le32(val) (val)
+#endif
+#if LINUX_VERSION_CODE < 0x20155
+#define PCI_SUPPORT_VER1
+#else
+#define PCI_SUPPORT_VER2
+#endif
+#if LINUX_VERSION_CODE < 0x20159
+#define DEV_FREE_SKB(skb) dev_kfree_skb (skb, FREE_WRITE);
+#else /* Grrr, unneeded incompatible change. */
+#define DEV_FREE_SKB(skb) dev_kfree_skb(skb);
X #endif
-#if defined(MODULE) && (LINUX_VERSION_CODE >= 0x20115)
+
+#if defined(MODULE) && LINUX_VERSION_CODE > 0x20115
X MODULE_AUTHOR("Donald Becker <bec...@cesdis.gsfc.nasa.gov>");
X MODULE_DESCRIPTION("3Com 3c590/3c900 series Vortex/Boomerang driver");
X MODULE_PARM(debug, "i");
@@ -141,7 +126,7 @@
X MODULE_PARM(max_interrupt_work, "i");
X MODULE_PARM(compaq_ioaddr, "i");
X MODULE_PARM(compaq_irq, "i");
-MODULE_PARM(compaq_prod_id, "i");
+MODULE_PARM(compaq_device_id, "i");
X #endif
X
X /* Operational parameter that usually are not changed. */
@@ -153,35 +138,11 @@
X #define VORTEX_TOTAL_SIZE 0x20
X #define BOOMERANG_TOTAL_SIZE 0x40
X
-#ifdef HAVE_DEVLIST
-struct netdev_entry tc59x_drv =
-{"Vortex", vortex_pci_probe, VORTEX_TOTAL_SIZE, NULL};
-#endif
-
X /* Set iff a MII transceiver on any interface requires mdio preamble.
X This only set with the original DP83840 on older 3c905 boards, so the extra
X code size of a per-interface flag is not worthwhile. */
X static char mii_preamble_required = 0;
X
-/* Caution! These entries must be consistent. */
-static const int product_ids[] = {
- 0x5900, 0x5920, 0x5970, 0x5950, 0x5951, 0x5952, 0x9000, 0x9001,
- 0x9050, 0x9051, 0x9055, 0x5057, 0 };
-static const char *product_names[] = {
- "3c590 Vortex 10Mbps",
- "3c592 EISA 10mbps Demon/Vortex",
- "3c597 EISA Fast Demon/Vortex",
- "3c595 Vortex 100baseTX",
- "3c595 Vortex 100baseT4",
- "3c595 Vortex 100base-MII",
- "3c900 Boomerang 10baseT",
- "3c900 Boomerang 10Mbps/Combo",
- "3c905 Boomerang 100baseTx",
- "3c905 Boomerang 100baseT4",
- "3c905B Cyclone 100baseTx",
- "3c575", /* Cardbus Boomerang */
-};
-
X /*
X Theory of Operation
X
@@ -192,17 +153,19 @@
X versions of the FastEtherLink cards. The supported product IDs are
X 3c590, 3c592, 3c595, 3c597, 3c900, 3c905
X
-The ISA 3c515 is supported with a separate driver, 3c515.c, included with
-the kernel source or available from
+The related ISA 3c515 is supported with a separate driver, 3c515.c, included
+with the kernel source or available from
X cesdis.gsfc.nasa.gov:/pub/linux/drivers/3c515.html
X
X II. Board-specific settings
X
X PCI bus devices are configured by the system at boot time, so no jumpers
X need to be set on the board. The system BIOS should be set to assign the
-PCI INTA signal to an otherwise unused system IRQ line. While it's
-physically possible to shared PCI interrupt lines, the 1.2.0 kernel doesn't
-support it.
+PCI INTA signal to an otherwise unused system IRQ line.
+
+The EEPROM settings for media type and forced-full-duplex are observed.
+The EEPROM media type should be left at the default "autoselect" unless using
+10base2 or AUI connections which cannot be reliably detected.
X
X III. Driver operation
X
@@ -213,7 +176,7 @@
X The 3c900 "Boomerang" series uses a full-bus-master interface with separate
X lists of transmit and receive descriptors, similar to the AMD LANCE/PCnet,
X DEC Tulip and Intel Speedo3. The first chip version retains a compatible
-programmed-I/O interface that will be removed in the 'B' and subsequent
+programmed-I/O interface that has been removed in 'B' and subsequent board
X revisions.
X
X One extension that is advertised in a very large font is that the adapters
@@ -231,7 +194,7 @@
X single frame.
X
X With full-bus-master support, this driver uses a "RX_COPYBREAK" scheme.
-Tather than a fixed intermediate receive buffer, this scheme allocates
+Rather than a fixed intermediate receive buffer, this scheme allocates
X full-sized skbuffs as receive buffers. The value RX_COPYBREAK is used as
X the copying breakpoint: it is chosen to trade-off the memory wasted by
X passing the full-sized skbuff to the queue layer for all frames vs. the
@@ -257,7 +220,66 @@
X limit of 4K.
X */
X
-#define TCOM_VENDOR_ID 0x10B7 /* 3Com's manufacturer's ID. */
+/* This table drives the PCI probe routines. It's mostly boilerplate in all
+ of the drivers, and will likely be provided by some future kernel.
+*/
+enum pci_flags_bit {
+ PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
+ PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3,
+};
+struct pci_id_info {
+ const char *name;
+ u16 vendor_id, device_id, device_id_mask, flags;
+ int drv_flags, io_size;
+ struct device *(*probe1)(int pci_bus, int pci_devfn, struct device *dev,
+ long ioaddr, int irq, int chip_idx, int fnd_cnt);
+};
+
+enum { IS_VORTEX=1, IS_BOOMERANG=2, IS_CYCLONE=4,
+ HAS_PWR_CTRL=0x10, HAS_MII=0x20, HAS_NWAY=0x40, HAS_CB_FNS=0x80, };
+static struct device *vortex_probe1(int pci_bus, int pci_devfn,
+ struct device *dev, long ioaddr,
+ int irq, int dev_id, int card_idx);
+static struct pci_id_info pci_tbl[] = {
+ {"3c590 Vortex 10Mbps", 0x10B7, 0x5900, 0xffff,
+ PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, vortex_probe1},
+ {"3c595 Vortex 100baseTx", 0x10B7, 0x5950, 0xffff,
+ PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, vortex_probe1},
+ {"3c595 Vortex 100baseT4", 0x10B7, 0x5951, 0xffff,
+ PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, vortex_probe1},
+ {"3c595 Vortex 100base-MII", 0x10B7, 0x5952, 0xffff,
+ PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, vortex_probe1},
+ {"3Com Vortex", 0x10B7, 0x5900, 0xff00,
+ PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, vortex_probe1},
+ {"3c900 Boomerang 10baseT", 0x10B7, 0x9000, 0xffff,
+ PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, vortex_probe1},
+ {"3c900 Boomerang 10Mbps Combo", 0x10B7, 0x9001, 0xffff,
+ PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, vortex_probe1},
+ {"3c900 Cyclone 10Mbps Combo", 0x10B7, 0x9005, 0xffff,
+ PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1},
+ {"3c900B-FL Cyclone 10base-FL", 0x10B7, 0x900A, 0xffff,
+ PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1},
+ {"3c905 Boomerang 100baseTx", 0x10B7, 0x9050, 0xffff,
+ PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, vortex_probe1},
+ {"3c905 Boomerang 100baseT4", 0x10B7, 0x9051, 0xffff,
+ PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, vortex_probe1},
+ {"3c905B Cyclone 100baseTx", 0x10B7, 0x9055, 0xffff,
+ PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, vortex_probe1},
+ {"3c905B-FX Cyclone 100baseFx", 0x10B7, 0x905A, 0xffff,
+ PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1},
+ {"3c980 Cyclone", 0x10B7, 0x9800, 0xfff0,
+ PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1},
+ {"3c575 Boomerang CardBus", 0x10B7, 0x5057, 0xffff,
+ PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, vortex_probe1},
+ {"3CCFE575 Cyclone CardBus", 0x10B7, 0x5157, 0xffff,
+ PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS,
+ 128, vortex_probe1},
+ {"3c575 series CardBus (unknown version)", 0x10B7, 0x5057, 0xf0ff,
+ PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, vortex_probe1},
+ {"3Com Boomerang (unknown version)", 0x10B7, 0x9000, 0xff00,
+ PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, vortex_probe1},
+ {0,}, /* 0 terminated list. */
+};
X
X /* Operational definitions.
X These are not used by other compilation units and thus are not
@@ -286,7 +308,7 @@
X SetStatusEnb = 15<<11, SetRxFilter = 16<<11, SetRxThreshold = 17<<11,
X SetTxThreshold = 18<<11, SetTxStart = 19<<11,
X StartDMAUp = 20<<11, StartDMADown = (20<<11)+1, StatsEnable = 21<<11,
- StatsDisable = 22<<11, StopCoax = 23<<11,};
+ StatsDisable = 22<<11, StopCoax = 23<<11, SetFilterBit = 25<<11,};
X
X /* The SetRxFilter command accepts the following classes: */
X enum RxFilter {
@@ -326,6 +348,9 @@
X NodeAddr01=10, NodeAddr23=11, NodeAddr45=12,
X DriverTune=13, Checksum=15};
X
+enum Window2 { /* Window 2. */
+ Wn2_ResetOptions=12,
+};
X enum Window3 { /* Window 3: MAC/config bits. */
X Wn3_Config=0, Wn3_MAC_Ctrl=6, Wn3_Options=8,
X };
@@ -393,37 +418,37 @@
X enum ChipCaps { CapBusMaster=0x20 };
X
X struct vortex_private {
- char devname[8]; /* "ethN" string, also for kernel debug. */
- const char *product_name;
- struct device *next_module;
- /* The Rx and Tx rings are here to keep them quad-word-aligned. */
+ /* The Rx and Tx rings should be quad-word-aligned. */
X struct boom_rx_desc rx_ring[RX_RING_SIZE];
X struct boom_tx_desc tx_ring[TX_RING_SIZE];
X /* The addresses of transmit- and receive-in-place skbuffs. */
X struct sk_buff* rx_skbuff[RX_RING_SIZE];
X struct sk_buff* tx_skbuff[TX_RING_SIZE];
+ struct device *next_module;
+ void *priv_addr;
X unsigned int cur_rx, cur_tx; /* The next free ring entry */
X unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */
- struct enet_statistics stats;
+ struct net_device_stats stats;
X struct sk_buff *tx_skb; /* Packet being eaten by bus master ctrl. */
X
X /* PCI configuration space information. */
- u8 pci_bus, pci_dev_fn; /* PCI bus location, for power management. */
- u16 pci_device_id;
+ u8 pci_bus, pci_devfn; /* PCI bus location, for power management. */
+ char *cb_fn_base; /* CardBus function status addr space. */
+ int chip_id;
X
X /* The remainder are related to chip state, mostly media selection. */
- int in_interrupt;
+ unsigned long in_interrupt;
X struct timer_list timer; /* Media selection timer. */
X int options; /* User-settable misc. driver options. */
- unsigned int
- media_override:3, /* Passed-in media type. */
- default_media:3, /* Read from the EEPROM/Wn3_Config. */
- full_duplex:1, autoselect:1,
- bus_master:1, /* Vortex can only do a fragment bus-m. */
- full_bus_master_tx:1, full_bus_master_rx:2, /* Boomerang */
- hw_csums:1, /* Has hardware checksums. */
- tx_full:1;
+ unsigned int media_override:3, /* Passed-in media type. */
+ default_media:4, /* Read from the EEPROM/Wn3_Config. */
+ full_duplex:1, force_fd:1, autoselect:1,
+ bus_master:1, /* Vortex can only do a fragment bus-m. */
+ full_bus_master_tx:1, full_bus_master_rx:2, /* Boomerang */
+ hw_csums:1, /* Has hardware checksums. */
+ tx_full:1;
X u16 status_enable;
+ u16 intr_enable;
X u16 available_media; /* From Wn3_Options. */
X u16 capabilities, info1, info2; /* Various, from EEPROM. */
X u16 advertising; /* NWay media advertisement */
@@ -458,61 +483,39 @@
X { "Default", 0, 0xFF, XCVR_10baseT, 10000},
X };
X
-static int vortex_scan(struct device *dev);
-static struct device *vortex_found_device(struct device *dev, int ioaddr,
- int irq, int device_id,
- int options, int card_idx);
-static int vortex_probe1(struct device *dev);
-static int vortex_open(struct device *dev);
-static void mdio_sync(int ioaddr, int bits);
-static int mdio_read(int ioaddr, int phy_id, int location);
-#ifdef HAVE_PRIVATE_IOCTL
-static void mdio_write(int ioaddr, int phy_id, int location, int value);
+#ifndef CARDBUS
+static int vortex_scan(struct device *dev, struct pci_id_info pci_tbl[]);
X #endif
+static int vortex_open(struct device *dev);
+static void mdio_sync(long ioaddr, int bits);
+static int mdio_read(long ioaddr, int phy_id, int location);
+static void mdio_write(long ioaddr, int phy_id, int location, int value);
X static void vortex_timer(unsigned long arg);
X static int vortex_start_xmit(struct sk_buff *skb, struct device *dev);
X static int boomerang_start_xmit(struct sk_buff *skb, struct device *dev);
X static int vortex_rx(struct device *dev);
X static int boomerang_rx(struct device *dev);
-static void vortex_interrupt IRQ(int irq, void *dev_id, struct pt_regs *regs);
+static void vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs);
X static int vortex_close(struct device *dev);
-static void update_stats(int addr, struct device *dev);
-static struct enet_statistics *vortex_get_stats(struct device *dev);
+static void update_stats(long ioaddr, struct device *dev);
+static struct net_device_stats *vortex_get_stats(struct device *dev);
X static void set_rx_mode(struct device *dev);
-#ifdef HAVE_PRIVATE_IOCTL
X static int vortex_ioctl(struct device *dev, struct ifreq *rq, int cmd);
-#endif
-#ifndef NEW_MULTICAST
-static void set_multicast_list(struct device *dev, int num_addrs, void *addrs);
-#endif
X
X
-/* Unlike the other PCI cards the 59x cards don't need a large contiguous
- memory region, so making the driver a loadable module is feasible.
-
- Unfortunately maximizing the shared code between the integrated and
- module version of the driver results in a complicated set of initialization
- procedures.
- init_module() -- modules / tc59x_init() -- built-in
- The wrappers for vortex_scan()
- vortex_scan() The common routine that scans for PCI and EISA cards
- vortex_found_device() Allocate a device structure when we find a card.
- Different versions exist for modules and built-in.
- vortex_probe1() Fill in the device structure -- this is separated
- so that the modules code can put it in dev->init.
-*/
X /* This driver uses 'options' to pass the media type, full-duplex flag, etc. */
-/* Note: this is the only limit on the number of cards supported!! */
-static int options[8] = { -1, -1, -1, -1, -1, -1, -1, -1,};
-static int full_duplex[8] = {-1, -1, -1, -1, -1, -1, -1, -1};
+/* Option count limit only -- unlimited interfaces are supported. */
+#define MAX_UNITS 8
+static int options[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1,};
+static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
X /* A list of all installed Vortex devices, for removing the driver module. */
X static struct device *root_vortex_dev = NULL;
X
X #ifdef MODULE
+#ifndef CARDBUS
X /* Variables to work-around the Compaq PCI BIOS32 problem. */
X static int compaq_ioaddr = 0, compaq_irq = 0, compaq_device_id = 0x5900;
-
-static int debug = -1;
+#endif
X
X #ifdef CARDBUS
X
@@ -520,19 +523,38 @@
X
X static dev_node_t *vortex_attach(dev_locator_t *loc)
X {
- u16 dev_id;
+ u16 dev_id, vendor_id;
X u32 io;
X u8 bus, devfn, irq;
X struct device *dev;
+ int chip_idx;
X
X if (loc->bus != LOC_PCI) return NULL;
X bus = loc->b.pci.bus; devfn = loc->b.pci.devfn;
- printk(KERN_INFO "vortex_attach(bus %d, function %d)\n", bus, devfn);
X pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, &io);
X pcibios_read_config_byte(bus, devfn, PCI_INTERRUPT_LINE, &irq);
+ pcibios_read_config_word(bus, devfn, PCI_VENDOR_ID, &vendor_id);
X pcibios_read_config_word(bus, devfn, PCI_DEVICE_ID, &dev_id);
+ printk(KERN_INFO "vortex_attach(bus %d, function %d, device %4.4x)\n",
+ bus, devfn, dev_id);
X io &= ~3;
- dev = vortex_found_device(NULL, io, irq, dev_id, 0, -1);
+ if (io == 0 || irq == 0) {
+ printk(KERN_ERR "The 3Com CardBus Ethernet interface was not "
+ "assigned an %s.\n" KERN_ERR " It will not be activated.\n",
+ io == 0 ? "I/O address" : "IRQ");
+ return NULL;
+ }
+ for (chip_idx = 0; pci_tbl[chip_idx].vendor_id; chip_idx++)
+ if (vendor_id == pci_tbl[chip_idx].vendor_id
+ && (dev_id & pci_tbl[chip_idx].device_id_mask) ==
+ pci_tbl[chip_idx].device_id)
+ break;
+ if (pci_tbl[chip_idx].vendor_id == 0) { /* Compiled out! */
+ printk(KERN_INFO "Unable to match chip type %4.4x %4.4x in "
+ "vortex_attach().\n", vendor_id, dev_id);
+ return NULL;
+ }
+ dev = vortex_probe1(bus, devfn, NULL, io, irq, chip_idx, MAX_UNITS+1);
X if (dev) {
X dev_node_t *node = kmalloc(sizeof(dev_node_t), GFP_KERNEL);
X strcpy(node->dev_name, dev->name);
@@ -554,61 +576,49 @@
X }
X if (*devp) {
X struct device *dev = *devp;
+ struct vortex_private *vp = dev->priv;
X if (dev->flags & IFF_UP)
X vortex_close(dev);
X dev->flags &= ~(IFF_UP|IFF_RUNNING);
X unregister_netdev(dev);
+ if (vp->cb_fn_base) iounmap(vp->cb_fn_base);
X kfree(dev);
X *devp = *next;
+ kfree(vp);
X kfree(node);
X MOD_DEC_USE_COUNT;
X }
X }
X
X struct driver_operations vortex_ops = {
- "3c59x_cb", vortex_attach, NULL, NULL, vortex_detach
+ "3c575_cb", vortex_attach, NULL, NULL, vortex_detach
X };
X
X #endif /* Cardbus support */
X
X
-int
-init_module(void)
+int init_module(void)
X {
- if (debug >= 0)
- vortex_debug = debug;
X if (vortex_debug)
- printk(version);
-
- root_vortex_dev = NULL;
+ printk(KERN_INFO "%s", version);
X #ifdef CARDBUS
X register_driver(&vortex_ops);
X return 0;
X #else
- {
- int cards_found = vortex_scan(0);
- if (cards_found == 0)
- printk("No 3Com Vortex/Boomerang cards found.\n");
- return cards_found ? 0 : -ENODEV;
- }
+ return vortex_scan(0, pci_tbl);
X #endif
X }
X
X #else
X int tc59x_probe(struct device *dev)
X {
- int cards_found = 0;
-
- cards_found = vortex_scan(dev);
-
- if (vortex_debug > 0 && cards_found)
- printk(version);
-
- return cards_found ? 0 : -ENODEV;
+ printk(KERN_INFO "%s", version);
+ return vortex_scan(dev, pci_tbl);
X }
X #endif /* not MODULE */
X
-static int vortex_scan(struct device *dev)
+#ifndef CARDBUS
+static int vortex_scan(struct device *dev, struct pci_id_info pci_tbl[])
X {
X int cards_found = 0;
X
@@ -623,25 +633,30 @@
X unsigned char pci_bus, pci_device_fn;
X
X for (;pci_index < 0xff; pci_index++) {
- u8 pci_latency;
- u16 pci_command, new_command, vendor, device;
- int irq;
+ u16 vendor, device, pci_command, new_command, pwr_cmd;
+ int chip_idx, irq;
X long ioaddr;
X
- if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8,
- pci_index, &pci_bus, &pci_device_fn)
+ if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8, pci_index,
+ &pci_bus, &pci_device_fn)
X != PCIBIOS_SUCCESSFUL)
X break;
X pcibios_read_config_word(pci_bus, pci_device_fn,
X PCI_VENDOR_ID, &vendor);
X pcibios_read_config_word(pci_bus, pci_device_fn,
X PCI_DEVICE_ID, &device);
- pcibios_read_config_word(pci_bus, pci_device_fn,
- PCI_COMMAND, &pci_command);
+ for (chip_idx = 0; pci_tbl[chip_idx].vendor_id; chip_idx++)
+ if (vendor == pci_tbl[chip_idx].vendor_id
+ && (device & pci_tbl[chip_idx].device_id_mask) ==
+ pci_tbl[chip_idx].device_id)
+ break;
+ if (pci_tbl[chip_idx].vendor_id == 0) /* Compiled out! */
+ continue;
+
X {
X #if LINUX_VERSION_CODE >= 0x20155
X struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn);
- ioaddr = pdev->base_address[0];
+ ioaddr = pdev->base_address[0] & ~3;
X irq = pdev->irq;
X #else
X u32 pci_ioaddr;
@@ -650,15 +665,28 @@
X PCI_INTERRUPT_LINE, &pci_irq_line);
X pcibios_read_config_dword(pci_bus, pci_device_fn,
X PCI_BASE_ADDRESS_0, &pci_ioaddr);
- ioaddr = pci_ioaddr;
+ ioaddr = pci_ioaddr & ~3;;
X irq = pci_irq_line;
X #endif
X }
- /* Remove I/O space marker in bit 0. */
- ioaddr &= ~3;
X
- if (vendor != TCOM_VENDOR_ID)
- continue;
+ /* Power-up the card. */
+ pcibios_read_config_word(pci_bus, pci_device_fn,
+ 0xe0, &pwr_cmd);
+ if (pwr_cmd & 0x3) {
+ /* Save the ioaddr and IRQ info! */
+ printk(KERN_INFO " A 3Com network adapter is powered down!"
+ " Setting the power state %4.4x->%4.4x.\n",
+ pwr_cmd, pwr_cmd & ~3);
+ pcibios_write_config_word(pci_bus, pci_device_fn,
+ 0xe0, pwr_cmd & ~3);
+ printk(KERN_INFO " Setting the IRQ to %d, IOADDR to %#lx.\n",
+ irq, ioaddr);
+ pcibios_write_config_byte(pci_bus, pci_device_fn,
+ PCI_INTERRUPT_LINE, irq);
+ pcibios_write_config_dword(pci_bus, pci_device_fn,
+ PCI_BASE_ADDRESS_0, ioaddr);
+ }
X
X if (ioaddr == 0) {
X printk(KERN_WARNING " A 3Com network adapter has been found, "
@@ -668,34 +696,31 @@
X continue;
X }
X
- if (check_region(ioaddr, VORTEX_TOTAL_SIZE))
+ if (check_region(ioaddr, pci_tbl[chip_idx].io_size))
X continue;
X
X /* Activate the card. */
+ pcibios_read_config_word(pci_bus, pci_device_fn,
+ PCI_COMMAND, &pci_command);
X new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO;
X if (pci_command != new_command) {
- printk(KERN_INFO " The PCI BIOS has not enabled this"
- " device! Updating PCI command %4.4x->%4.4x.\n",
- pci_command, new_command);
+ printk(KERN_INFO " The PCI BIOS has not enabled the device "
+ "at %d/%d. Updating PCI command %4.4x->%4.4x.\n",
+ pci_bus, pci_device_fn, pci_command, new_command);
X pcibios_write_config_word(pci_bus, pci_device_fn,
X PCI_COMMAND, new_command);
X }
X
- dev = vortex_found_device(dev, ioaddr, irq,
- device, dev && dev->mem_start
- ? dev->mem_start : options[cards_found],
- cards_found);
+ dev = vortex_probe1(pci_bus, pci_device_fn, dev, ioaddr, irq,
+ chip_idx, cards_found);
X
X if (dev) {
- struct vortex_private *vp = (struct vortex_private *)dev->priv;
X /* Get and check the latency values. On the 3c590 series
X the latency timer must be set to the maximum value to avoid
X data corruption that occurs when the timer expires during
X a transfer -- a bug in the Vortex chip only. */
- u8 new_latency = (device&0xff00) == 0x5900 ? 248 : 32;
- vp->pci_bus = pci_bus;
- vp->pci_dev_fn = pci_device_fn;
- vp->pci_device_id = device;
+ u8 pci_latency;
+ u8 new_latency = (device & 0xff00) == 0x5900 ? 248 : 32;
X
X pcibios_read_config_byte(pci_bus, pci_device_fn,
X PCI_LATENCY_TIMER, &pci_latency);
@@ -715,7 +740,7 @@
X
X /* Now check all slots of the EISA bus. */
X if (EISA_bus) {
- static int ioaddr = 0x1000;
+ static long ioaddr = 0x1000;
X for ( ; ioaddr < 0x9000; ioaddr += 0x1000) {
X int device_id;
X if (check_region(ioaddr, VORTEX_TOTAL_SIZE))
@@ -727,10 +752,8 @@
X device_id = (inb(ioaddr + 0xC82)<<8) + inb(ioaddr + 0xC83);
X if ((device_id & 0xFF00) != 0x5900)
X continue;
- vortex_found_device(dev, ioaddr, inw(ioaddr + 0xC88) >> 12,
- device_id, dev && dev->mem_start
- ? dev->mem_start : options[cards_found],
- cards_found);
+ vortex_probe1(0, 0, dev, ioaddr, inw(ioaddr + 0xC88) >> 12,
+ 4, cards_found);
X dev = 0;
X cards_found++;
X }
@@ -739,97 +762,58 @@
X #ifdef MODULE
X /* Special code to work-around the Compaq PCI BIOS32 problem. */
X if (compaq_ioaddr) {
- vortex_found_device(dev, compaq_ioaddr, compaq_irq, compaq_device_id,
- dev && dev->mem_start ? dev->mem_start
- : options[cards_found], cards_found);
- cards_found++;
+ vortex_probe1(0, 0, dev, compaq_ioaddr, compaq_irq,
+ compaq_device_id, cards_found++);
X dev = 0;
X }
X #endif
X
- /* 3c515 cards are now supported by the 3c515.c driver. */
-
- return cards_found;
+ return cards_found ? 0 : -ENODEV;
X }
+#endif /* ! Cardbus */
X
-static struct device *
-vortex_found_device(struct device *dev, int ioaddr, int irq,
- int device_id, int option, int card_idx)
+static struct device *vortex_probe1(int pci_bus, int pci_devfn,
+ struct device *dev, long ioaddr,
+ int irq, int chip_idx, int card_idx)
X {
X struct vortex_private *vp;
- const char *product_name;
- int board_index = 0;
+ int option;
+ unsigned int eeprom[0x40], checksum = 0; /* EEPROM contents */
+ int i;
X
- for (board_index = 0; product_ids[board_index]; board_index++) {
- if (device_id == product_ids[board_index])
- break;
- }
- /* Handle products we don't recognize, but might still work with. */
- if (product_ids[board_index])
- product_name = product_names[board_index];
- else if ((device_id & 0xff00) == 0x5900)
- product_name = "3c590 Vortex";
- else if ((device_id & 0xfff0) == 0x9000)
- product_name = "3c900";
- else if ((device_id & 0xfff0) == 0x9050)
- product_name = "3c905";
- else {
- printk(KERN_WARNING "Unknown 3Com PCI ethernet adapter type %4.4x detected:"
- " not configured.\n", device_id);
- return 0;
- }
+ dev = init_etherdev(dev, 0);
X
-#ifdef MODULE
- /* Allocate and fill new device structure. */
- {
- int dev_size = sizeof(struct device) +
- sizeof(struct vortex_private) + 15; /* Pad for alignment */
+ printk(KERN_INFO "%s: 3Com %s at 0x%lx, ",
+ dev->name, pci_tbl[chip_idx].name, ioaddr);
X
- dev = (struct device *) kmalloc(dev_size, GFP_KERNEL);
- memset(dev, 0, dev_size);
- }
- /* Align the Rx and Tx ring entries. */
- dev->priv = (void *)(((long)dev + sizeof(struct device) + 15) & ~15);
- vp = (struct vortex_private *)dev->priv;
- dev->name = vp->devname; /* An empty string. */
X dev->base_addr = ioaddr;
X dev->irq = irq;
- dev->init = vortex_probe1;
- vp->product_name = product_name;
- vp->options = option;
- if (card_idx >= 0) {
- if (full_duplex[card_idx] >= 0)
- vp->full_duplex = full_duplex[card_idx];
- } else
- vp->full_duplex = (option > 0 && (option & 0x10) ? 1 : 0);
+ dev->mtu = mtu;
X
- if (option > 0) {
- vp->media_override = ((option & 7) == XCVR_10baseTOnly) ?
- XCVR_10baseT : option & 7;
- vp->bus_master = (option & 16) ? 1 : 0;
- } else {
- vp->media_override = 7;
- vp->bus_master = 0;
+ /* Make certain the descriptor lists are aligned. */
+ {
+ void *mem = kmalloc(sizeof(*vp) + 15, GFP_KERNEL);
+ vp = (void *)(((long)mem + 15) & ~15);
+ vp->priv_addr = mem;
X }
- ether_setup(dev);
+ memset(vp, 0, sizeof(*vp));
+ dev->priv = vp;
+
X vp->next_module = root_vortex_dev;
X root_vortex_dev = dev;
- if (register_netdev(dev) != 0)
- return 0;
-#else /* not a MODULE */
- if (dev) {
- /* Caution: quad-word alignment required for rings! */
- dev->priv = kmalloc(sizeof (struct vortex_private), GFP_KERNEL);
- memset(dev->priv, 0, sizeof (struct vortex_private));
- }
- dev = init_etherdev(dev, sizeof(struct vortex_private));
- dev->base_addr = ioaddr;
- dev->irq = irq;
- dev->mtu = mtu;
X
- vp = (struct vortex_private *)dev->priv;
- vp->product_name = product_name;
- vp->options = option;
+ vp->chip_id = chip_idx;
+ vp->pci_bus = pci_bus;
+ vp->pci_devfn = pci_devfn;
+
+ /* The lower four bits are the media type. */
+ if (dev->mem_start)
+ option = dev->mem_start;
+ else if (card_idx < MAX_UNITS)
+ option = options[card_idx];
+ else
+ option = -1;
+
X if (option >= 0) {
X vp->media_override = ((option & 7) == 2) ? 0 : option & 7;
X vp->full_duplex = (option & 8) ? 1 : 0;
@@ -839,22 +823,11 @@
X vp->full_duplex = 0;
X vp->bus_master = 0;
X }
+ if (card_idx < MAX_UNITS && full_duplex[card_idx] > 0)
+ vp->full_duplex = 1;
X
- vortex_probe1(dev);
-#endif /* MODULE */
- return dev;
-}
-
-static int vortex_probe1(struct device *dev)
-{
- int ioaddr = dev->base_addr;
- struct vortex_private *vp = (struct vortex_private *)dev->priv;
- u16 *ether_addr = (u16 *)dev->dev_addr;
- unsigned int eeprom[0x40], checksum = 0; /* EEPROM contents */
- int i;
-
- printk(KERN_INFO "%s: 3Com %s at %#3x,",
- dev->name, vp->product_name, ioaddr);
+ vp->force_fd = vp->full_duplex;
+ vp->options = option;
X
X /* Read the station address from the EEPROM. */
X EL3WINDOW(0);
@@ -885,14 +858,30 @@
X printk(" ***INVALID CHECKSUM %4.4x*** ", checksum);
X
X for (i = 0; i < 3; i++)
- ether_addr[i] = htons(eeprom[i + 10]);
+ ((u16 *)dev->dev_addr)[i] = htons(eeprom[i + 10]);
X for (i = 0; i < 6; i++)
X printk("%c%2.2x", i ? ':' : ' ', dev->dev_addr[i]);
+#ifdef __sparc__
+ printk(", IRQ %s\n", __irq_itoa(dev->irq));
+#else
X printk(", IRQ %d\n", dev->irq);
X /* Tell them about an invalid IRQ. */
X if (vortex_debug && (dev->irq <= 0 || dev->irq >= NR_IRQS))
X printk(KERN_WARNING " *** Warning: IRQ %d is unlikely to work! ***\n",


SHAR_EOF
true || echo 'restore of patch-2.0.37 failed'
fi

echo 'End of part 09'
echo 'File patch-2.0.37 is continued in part 10'
echo 10 > _shar_seq_.tmp
exit 0

Thomas...@ciw.uni-karlsruhe.de

unread,
Jun 16, 1999, 3:00:00 AM6/16/99
to
Archive-name: v2.0/patch-2.0.37/part10

#!/bin/sh
# this is part 10 of a 45 - part archive


# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.0.37 continued
if test ! -r _shar_seq_.tmp; then
echo 'Please unpack part 1 first!'
exit 1
fi
(read Scheck

if test "$Scheck" != 10; then


echo Please unpack part "$Scheck" next!
exit 1
else
exit 0
fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.0.37'
else
echo 'x - continuing with patch-2.0.37'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.0.37' &&

X dev->irq);
+#endif
+
+ if (pci_tbl[vp->chip_id].drv_flags & HAS_CB_FNS) {
+ u32 fn_st_addr; /* Cardbus function status space */
+ pcibios_read_config_dword(pci_bus, pci_devfn, PCI_BASE_ADDRESS_2,
+ &fn_st_addr);
+ if (fn_st_addr)
+ vp->cb_fn_base = ioremap(fn_st_addr & ~3, 128);
+ printk("%s: CardBus functions mapped %8.8x->%p (PCMCIA committee"
+ " brain-damage).\n", dev->name, fn_st_addr, vp->cb_fn_base);
+ EL3WINDOW(2);
+ outw(0x10 | inw(ioaddr + Wn2_ResetOptions), ioaddr + Wn2_ResetOptions);
+ }
X
X /* Extract our information from the EEPROM data. */
X vp->info1 = eeprom[13];
@@ -918,7 +907,7 @@
X config.u.ram_width ? "word" : "byte",
X ram_split[config.u.ram_split],
X config.u.autoselect ? "autoselect/" : "",
- config.u.xcvr ? "NWay Autonegotiation" :
+ config.u.xcvr > XCVR_ExtMII ? "<invalid transceiver>" :
X media_tbl[config.u.xcvr].name);
X vp->default_media = config.u.xcvr;
X vp->autoselect = config.u.autoselect;
@@ -931,22 +920,24 @@
X } else
X dev->if_port = vp->default_media;
X
- if (dev->if_port == XCVR_MII) {
+ if (dev->if_port == XCVR_MII || dev->if_port == XCVR_NWAY) {
X int phy, phy_idx = 0;
X EL3WINDOW(4);
- for (phy = 0; phy < 32 && phy_idx < sizeof(vp->phys); phy++) {
- int mii_status;
- mdio_sync(ioaddr, 32);
- mii_status = mdio_read(ioaddr, phy, 1);
+ mii_preamble_required++;
+ mii_preamble_required++;
+ mdio_read(ioaddr, 24, 1);
+ for (phy = 1; phy <= 32 && phy_idx < sizeof(vp->phys); phy++) {
+ int mii_status, phyx = phy & 0x1f;
+ mii_status = mdio_read(ioaddr, phyx, 1);
X if (mii_status && mii_status != 0xffff) {
- vp->phys[phy_idx++] = phy;
- printk(KERN_INFO " MII transceiver found at address %d, status %4x.\n",
- phy, mii_status);
- mdio_sync(ioaddr, 32);
- if ((mdio_read(ioaddr, phy, 1) & 0x0040) == 0)
- mii_preamble_required = 1;
+ vp->phys[phy_idx++] = phyx;
+ printk(KERN_INFO " MII transceiver found at address %d,"
+ " status %4x.\n", phyx, mii_status);
+ if ((mii_status & 0x0040) == 0)
+ mii_preamble_required++;
X }
X }
+ mii_preamble_required--;
X if (phy_idx == 0) {
X printk(KERN_WARNING" ***WARNING*** No MII transceivers found!\n");
X vp->phys[0] = 24;
@@ -954,7 +945,7 @@
X vp->advertising = mdio_read(ioaddr, vp->phys[0], 4);
X if (vp->full_duplex) {
X /* Only advertise the FD media types. */
- vp->advertising &= 0x015F;
+ vp->advertising &= ~0x02A0;
X mdio_write(ioaddr, vp->phys[0], 4, vp->advertising);
X }
X }
@@ -968,30 +959,24 @@
X }
X
X /* We do a request_region() to register /proc/ioports info. */
- request_region(ioaddr, VORTEX_TOTAL_SIZE, vp->product_name);
+ request_region(ioaddr, pci_tbl[chip_idx].io_size, dev->name);
X
X /* The 3c59x-specific entries in the device structure. */
X dev->open = &vortex_open;
X dev->hard_start_xmit = &vortex_start_xmit;
X dev->stop = &vortex_close;
X dev->get_stats = &vortex_get_stats;
-#ifdef HAVE_PRIVATE_IOCTL
X dev->do_ioctl = &vortex_ioctl;
-#endif
-#ifdef NEW_MULTICAST
X dev->set_multicast_list = &set_rx_mode;
-#else
- dev->set_multicast_list = &set_multicast_list;
-#endif
X
- return 0;
+ return dev;
X }


X
X
X static int

X vortex_open(struct device *dev)
X {
- int ioaddr = dev->base_addr;
+ long ioaddr = dev->base_addr;
X struct vortex_private *vp = (struct vortex_private *)dev->priv;
X union wn3_config config;
X int i;
@@ -1006,28 +991,31 @@
X dev->name, vp->media_override,
X media_tbl[vp->media_override].name);
X dev->if_port = vp->media_override;
+ } else if (vp->autoselect && pci_tbl[vp->chip_id].drv_flags & HAS_NWAY) {
+ dev->if_port = XCVR_NWAY;
X } else if (vp->autoselect) {
X /* Find first available media type, starting with 100baseTx. */
X dev->if_port = XCVR_100baseTx;
X while (! (vp->available_media & media_tbl[dev->if_port].mask))
X dev->if_port = media_tbl[dev->if_port].next;
-
- if (vortex_debug > 1)
- printk(KERN_DEBUG "%s: Initial media type %s.\n",
- dev->name, media_tbl[dev->if_port].name);
-
- init_timer(&vp->timer);
- vp->timer.expires = RUN_AT(media_tbl[dev->if_port].wait);
- vp->timer.data = (unsigned long)dev;
- vp->timer.function = &vortex_timer; /* timer handler */
- add_timer(&vp->timer);
X } else
X dev->if_port = vp->default_media;
X
+ init_timer(&vp->timer);
+ vp->timer.expires = RUN_AT(media_tbl[dev->if_port].wait);
+ vp->timer.data = (unsigned long)dev;
+ vp->timer.function = &vortex_timer; /* timer handler */
+ add_timer(&vp->timer);
+
+ if (vortex_debug > 1)
+ printk(KERN_DEBUG "%s: Initial media type %s.\n",
+ dev->name, media_tbl[dev->if_port].name);
+
+ vp->full_duplex = vp->force_fd;
X config.u.xcvr = dev->if_port;
X outl(config.i, ioaddr + Wn3_Config);
X
- if (dev->if_port == XCVR_MII) {
+ if (dev->if_port == XCVR_MII || dev->if_port == XCVR_NWAY) {
X int mii_reg1, mii_reg5;
X EL3WINDOW(4);
X /* Read BMSR (reg1) only to clear old status. */
@@ -1067,20 +1055,10 @@
X
X outw(SetStatusEnb | 0x00, ioaddr + EL3_CMD);
X
-#ifdef SA_SHIRQ
X /* Use the now-standard shared IRQ implementation. */
X if (request_irq(dev->irq, &vortex_interrupt, SA_SHIRQ, dev->name, dev)) {
X return -EAGAIN;
X }
-#else
- if (dev->irq == 0 || irq2dev_map[dev->irq] != NULL)
- return -EAGAIN;
- irq2dev_map[dev->irq] = dev;
- if (request_irq(dev->irq, &vortex_interrupt, 0, vp->product_name)) {
- irq2dev_map[dev->irq] = NULL;
- return -EAGAIN;
- }
-#endif
X
X if (vortex_debug > 1) {
X EL3WINDOW(4);
@@ -1098,9 +1076,11 @@
X if (dev->if_port == XCVR_10base2)
X /* Start the thinnet transceiver. We should really wait 50ms...*/
X outw(StartCoax, ioaddr + EL3_CMD);
- EL3WINDOW(4);
- outw((inw(ioaddr + Wn4_Media) & ~(Media_10TP|Media_SQE)) |
- media_tbl[dev->if_port].media_bits, ioaddr + Wn4_Media);
+ if (dev->if_port != XCVR_NWAY) {
+ EL3WINDOW(4);
+ outw((inw(ioaddr + Wn4_Media) & ~(Media_10TP|Media_SQE)) |
+ media_tbl[dev->if_port].media_bits, ioaddr + Wn4_Media);
+ }
X
X /* Switch to the stats window, and clear all stats by reading. */
X outw(StatsDisable, ioaddr + EL3_CMD);
@@ -1127,22 +1107,23 @@
X printk(KERN_DEBUG "%s: Filling in the Rx ring.\n", dev->name);
X for (i = 0; i < RX_RING_SIZE; i++) {
X struct sk_buff *skb;
- vp->rx_ring[i].next = virt_to_bus(&vp->rx_ring[i+1]);
+ vp->rx_ring[i].next = cpu_to_le32(virt_to_bus(&vp->rx_ring[i+1]));
X vp->rx_ring[i].status = 0; /* Clear complete bit. */
- vp->rx_ring[i].length = PKT_BUF_SZ | LAST_FRAG;
- skb = DEV_ALLOC_SKB(PKT_BUF_SZ);
+ vp->rx_ring[i].length = cpu_to_le32(PKT_BUF_SZ | LAST_FRAG);
+ skb = dev_alloc_skb(PKT_BUF_SZ);
X vp->rx_skbuff[i] = skb;
X if (skb == NULL)
X break; /* Bad news! */
X skb->dev = dev; /* Mark as being used by this device. */
X #if LINUX_VERSION_CODE >= 0x10300
X skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
- vp->rx_ring[i].addr = virt_to_bus(skb->tail);
+ vp->rx_ring[i].addr = cpu_to_le32(virt_to_bus(skb->tail));
X #else
X vp->rx_ring[i].addr = virt_to_bus(skb->data);
X #endif
X }
- vp->rx_ring[i-1].next = virt_to_bus(&vp->rx_ring[0]); /* Wrap the ring. */
+ /* Wrap the ring. */
+ vp->rx_ring[i-1].next = cpu_to_le32(virt_to_bus(&vp->rx_ring[0]));
X outl(virt_to_bus(&vp->rx_ring[0]), ioaddr + UpListPtr);
X }
X if (vp->full_bus_master_tx) { /* Boomerang bus master Tx. */
@@ -1170,14 +1151,16 @@
X (vp->full_bus_master_tx ? DownComplete : TxAvailable) |
X (vp->full_bus_master_rx ? UpComplete : RxComplete) |
X (vp->bus_master ? DMADone : 0);
+ vp->intr_enable = SetIntrEnb | IntLatch | TxAvailable | RxComplete |
+ StatsFull | HostError | TxComplete | IntReq
+ | (vp->bus_master ? DMADone : 0) | UpComplete | DownComplete;
X outw(vp->status_enable, ioaddr + EL3_CMD);
X /* Ack all pending events, and set active indicator mask. */
X outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq,
X ioaddr + EL3_CMD);
- outw(SetIntrEnb | IntLatch | TxAvailable | RxComplete | StatsFull
- | HostError | TxComplete
- | (vp->bus_master ? DMADone : 0) | UpComplete | DownComplete,
- ioaddr + EL3_CMD);
+ outw(vp->intr_enable, ioaddr + EL3_CMD);
+ if (vp->cb_fn_base) /* The PCMCIA people are idiots. */
+ writel(0x8000, vp->cb_fn_base + 4);
X
X MOD_INC_USE_COUNT;
X
@@ -1186,24 +1169,23 @@
X
X static void vortex_timer(unsigned long data)
X {
-#ifdef AUTOMEDIA
X struct device *dev = (struct device *)data;
X struct vortex_private *vp = (struct vortex_private *)dev->priv;


- int ioaddr = dev->base_addr;

- unsigned long flags;
+ long ioaddr = dev->base_addr;
+ int next_tick = 0;
X int ok = 0;
+ int media_status, mii_status, old_window;
X
X if (vortex_debug > 1)
X printk(KERN_DEBUG "%s: Media selection timer tick happened, %s.\n",
X dev->name, media_tbl[dev->if_port].name);
X
- save_flags(flags); cli(); {
- int old_window = inw(ioaddr + EL3_CMD) >> 13;
- int media_status;
- EL3WINDOW(4);
- media_status = inw(ioaddr + Wn4_Media);
- switch (dev->if_port) {
- case XCVR_10baseT: case XCVR_100baseTx: case XCVR_100baseFx:
+ disable_irq(dev->irq);
+ old_window = inw(ioaddr + EL3_CMD) >> 13;
+ EL3WINDOW(4);
+ media_status = inw(ioaddr + Wn4_Media);
+ switch (dev->if_port) {
+ case XCVR_10baseT: case XCVR_100baseTx: case XCVR_100baseFx:
X if (media_status & Media_LnkBeat) {
X ok = 1;
X if (vortex_debug > 1)
@@ -1212,27 +1194,40 @@
X } else if (vortex_debug > 1)
X printk(KERN_DEBUG "%s: Media %s is has no link beat, %x.\n",
X dev->name, media_tbl[dev->if_port].name, media_status);
-
X break;
- case XCVR_MII:
- {
- int mii_reg1 = mdio_read(ioaddr, vp->phys[0], 1);
+ case XCVR_MII: case XCVR_NWAY:
+ mii_status = mdio_read(ioaddr, vp->phys[0], 1);
+ ok = 1;
+ if (debug > 1)
+ printk(KERN_DEBUG "%s: MII transceiver has status %4.4x.\n",
+ dev->name, mii_status);
+ if (mii_status & 0x0004) {
X int mii_reg5 = mdio_read(ioaddr, vp->phys[0], 5);
- if (vortex_debug > 1)
- printk(KERN_DEBUG "%s: MII #%d status register is %4.4x, "
- "link partner capability %4.4x.\n",
- dev->name, vp->phys[0], mii_reg1, mii_reg5);
- if (mii_reg1 & 0x0004)
- ok = 1;
- break;
+ if (! vp->force_fd && mii_reg5 != 0xffff) {
+ int duplex = (mii_reg5&0x0100) ||
+ (mii_reg5 & 0x01C0) == 0x0040;
+ if (vp->full_duplex != duplex) {
+ vp->full_duplex = duplex;
+ printk(KERN_INFO "%s: Setting %s-duplex based on MII "
+ "#%d link partner capability of %4.4x.\n",
+ dev->name, vp->full_duplex ? "full" : "half",
+ vp->phys[0], mii_reg5);
+ /* Set the full-duplex bit. */
+ outb((vp->full_duplex ? 0x20 : 0) |
+ (dev->mtu > 1500 ? 0x40 : 0),
+ ioaddr + Wn3_MAC_Ctrl);
+ }
+ next_tick = 60*HZ;
+ }
X }
+ break;
X default: /* Other media types handled by Tx timeouts. */
X if (vortex_debug > 1)
X printk(KERN_DEBUG "%s: Media %s is has no indication, %x.\n",
X dev->name, media_tbl[dev->if_port].name, media_status);
X ok = 1;
- }
- if ( ! ok) {
+ }
+ if ( ! ok) {
X union wn3_config config;
X
X do {
@@ -1249,8 +1244,7 @@
X printk(KERN_DEBUG "%s: Media selection failed, now trying "
X "%s port.\n",
X dev->name, media_tbl[dev->if_port].name);
- vp->timer.expires = RUN_AT(media_tbl[dev->if_port].wait);
- add_timer(&vp->timer);
+ next_tick = RUN_AT(media_tbl[dev->if_port].wait);
X }
X outw((media_status & ~(Media_10TP|Media_SQE)) |
X media_tbl[dev->if_port].media_bits, ioaddr + Wn4_Media);
@@ -1262,21 +1256,25 @@
X
X outw(dev->if_port == XCVR_10base2 ? StartCoax : StopCoax,
X ioaddr + EL3_CMD);
- }
- EL3WINDOW(old_window);
- } restore_flags(flags);
- if (vortex_debug > 1)
+ }
+ EL3WINDOW(old_window);
+ enable_irq(dev->irq);
+
+ if (vortex_debug > 2)
X printk(KERN_DEBUG "%s: Media selection timer finished, %s.\n",
X dev->name, media_tbl[dev->if_port].name);
X
-#endif /* AUTOMEDIA*/
+ if (next_tick) {
+ vp->timer.expires = RUN_AT(next_tick);
+ add_timer(&vp->timer);
+ }
X return;
X }
X
X static void vortex_tx_timeout(struct device *dev)
X {
X struct vortex_private *vp = (struct vortex_private *)dev->priv;


- int ioaddr = dev->base_addr;

+ long ioaddr = dev->base_addr;
X int j;
X
X printk(KERN_ERR "%s: transmit timed out, tx_status %2.2x status %4.4x.\n",
@@ -1290,7 +1288,7 @@
X printk(KERN_ERR "%s: Interrupt posted but not delivered --"
X " IRQ blocked by another device?\n", dev->name);
X /* Bad idea here.. but we might as well handle a few events. */
- vortex_interrupt IRQ(dev->irq, dev, 0);
+ vortex_interrupt(dev->irq, dev, 0);
X }
X outw(TxReset, ioaddr + EL3_CMD);
X for (j = 200; j >= 0 ; j--)
@@ -1309,8 +1307,8 @@
X for (i = 0; i < TX_RING_SIZE; i++) {
X printk(KERN_DEBUG " %d: @%p length %8.8x status %8.8x\n", i,
X &vp->tx_ring[i],
- vp->tx_ring[i].length,
- vp->tx_ring[i].status);
+ le32_to_cpu(vp->tx_ring[i].length),
+ le32_to_cpu(vp->tx_ring[i].status));
X }
X }
X #endif
@@ -1347,7 +1345,7 @@
X vortex_error(struct device *dev, int status)
X {
X struct vortex_private *vp = (struct vortex_private *)dev->priv;


- int ioaddr = dev->base_addr;

+ long ioaddr = dev->base_addr;
X int do_tx_reset = 0;
X int i;
X
@@ -1387,8 +1385,10 @@
X DoneDidThat++;
X }
X }
- if (status & IntReq) /* Restore all interrupt sources. */
- outw(ioaddr + EL3_CMD, vp->status_enable);
+ if (status & IntReq) { /* Restore all interrupt sources. */
+ outw(vp->status_enable, ioaddr + EL3_CMD);
+ outw(vp->intr_enable, ioaddr + EL3_CMD);
+ }
X if (status & HostError) {
X u16 fifo_diag;
X EL3WINDOW(4);
@@ -1434,7 +1434,7 @@
X vortex_start_xmit(struct sk_buff *skb, struct device *dev)
X {
X struct vortex_private *vp = (struct vortex_private *)dev->priv;


- int ioaddr = dev->base_addr;

+ long ioaddr = dev->base_addr;
X
X if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
X if (jiffies - dev->trans_start >= TX_TIMEOUT)
@@ -1444,7 +1444,6 @@
X
X /* Put out the doubleword header... */
X outl(skb->len, ioaddr + TX_FIFO);
-#ifdef VORTEX_BUS_MASTER
X if (vp->bus_master) {
X /* Set the bus-master controller to transfer the packet. */
X outl(virt_to_bus(skb->data), ioaddr + Wn7_MasterAddr);
@@ -1462,16 +1461,6 @@
X /* Interrupt us when the FIFO has room for max-sized packet. */
X outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD);
X }
-#else
- /* ... and the packet rounded to a doubleword. */
- outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
- DEV_FREE_SKB(skb);
- if (inw(ioaddr + TxFree) > 1536) {
- clear_bit(0, (void*)&dev->tbusy);
- } else
- /* Interrupt us when the FIFO has room for max-sized packet. */
- outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD);
-#endif /* bus master */
X
X dev->trans_start = jiffies;
X
@@ -1506,7 +1495,7 @@
X boomerang_start_xmit(struct sk_buff *skb, struct device *dev)
X {
X struct vortex_private *vp = (struct vortex_private *)dev->priv;


- int ioaddr = dev->base_addr;

+ long ioaddr = dev->base_addr;
X
X if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
X if (jiffies - dev->trans_start >= TX_TIMEOUT)
@@ -1528,13 +1517,12 @@
X printk(KERN_WARNING "%s: Tx Ring full, refusing to send buffer.\n",
X dev->name);
X return 1;
- }
- /* end change 06/25/97 M. Sievers */
+ }
X vp->tx_skbuff[entry] = skb;
X vp->tx_ring[entry].next = 0;
- vp->tx_ring[entry].addr = virt_to_bus(skb->data);
- vp->tx_ring[entry].length = skb->len | LAST_FRAG;
- vp->tx_ring[entry].status = skb->len | TxIntrUploaded;
+ vp->tx_ring[entry].addr = cpu_to_le32(virt_to_bus(skb->data));
+ vp->tx_ring[entry].length = cpu_to_le32(skb->len | LAST_FRAG);
+ vp->tx_ring[entry].status = cpu_to_le32(skb->len | TxIntrUploaded);
X
X save_flags(flags);
X cli();
@@ -1543,7 +1531,7 @@
X for (i = 600; i >= 0 ; i--)
X if ( (inw(ioaddr + EL3_STATUS) & CmdInProgress) == 0)
X break;
- prev_entry->next = virt_to_bus(&vp->tx_ring[entry]);
+ prev_entry->next = cpu_to_le32(virt_to_bus(&vp->tx_ring[entry]));
X if (inl(ioaddr + DownListPtr) == 0) {
X outl(virt_to_bus(&vp->tx_ring[entry]), ioaddr + DownListPtr);
X queued_packet++;
@@ -1555,7 +1543,7 @@
X if (vp->cur_tx - vp->dirty_tx > TX_RING_SIZE - 1)
X vp->tx_full = 1;
X else { /* Clear previous interrupt enable. */
- prev_entry->status &= ~TxIntrUploaded;
+ prev_entry->status &= cpu_to_le32(~TxIntrUploaded);
X clear_bit(0, (void*)&dev->tbusy);
X }
X dev->trans_start = jiffies;
@@ -1565,28 +1553,33 @@
X
X /* The interrupt handler does all of the Rx thread work and cleans up
X after the Tx thread. */


-static void vortex_interrupt IRQ(int irq, void *dev_id, struct pt_regs *regs)
+static void vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs)

X {
-#ifdef SA_SHIRQ /* Use the now-standard shared IRQ implementation. */
X struct device *dev = dev_id;
-#else
- struct device *dev = (struct device *)(irq2dev_map[irq]);
-#endif
- struct vortex_private *vp;
- int ioaddr, status;
- int latency;
+ struct vortex_private *vp = (struct vortex_private *)dev->priv;
+ long ioaddr;
+ int latency, status;
X int work_done = max_interrupt_work;


X
- vp = (struct vortex_private *)dev->priv;

- if (test_and_set_bit(0, (void*)&vp->in_interrupt)) {
+#if defined(__i386__)
+ /* A lock to prevent simultaneous entry bug on Intel SMP machines. */
+ if (test_and_set_bit(0, (void*)&dev->interrupt)) {
+ printk(KERN_ERR"%s: SMP simultaneous entry of an interrupt handler.\n",
+ dev->name);
+ dev->interrupt = 0; /* Avoid halting machine. */
+ return;
+ }
+#else
+ if (dev->interrupt) {
X printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name);
X return;
X }
+ dev->interrupt = 1;
+#endif
X
X dev->interrupt = 1;
X ioaddr = dev->base_addr;
X latency = inb(ioaddr + Timer);
-
X status = inw(ioaddr + EL3_STATUS);
X
X if (vortex_debug > 4)
@@ -1635,17 +1628,23 @@
X mark_bh(NET_BH);
X }
X }
-#ifdef VORTEX_BUS_MASTER
X if (status & DMADone) {
- outw(0x1000, ioaddr + Wn7_MasterStatus); /* Ack the event. */
- clear_bit(0, (void*)&dev->tbusy);
- DEV_FREE_SKB(vp->tx_skb); /* Release the transfered buffer */
- mark_bh(NET_BH);
+ if (inw(ioaddr + Wn7_MasterStatus) & 0x1000) {
+ outw(0x1000, ioaddr + Wn7_MasterStatus); /* Ack the event. */
+ DEV_FREE_SKB(vp->tx_skb); /* Release the transfered buffer */
+ if (inw(ioaddr + TxFree) > 1536) {
+ clear_bit(0, (void*)&dev->tbusy);
+ mark_bh(NET_BH);
+ } else /* Interrupt when FIFO has room for max-sized packet. */
+ outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD);
+ }
X }
-#endif
X /* Check for all uncommon interrupts at once. */
- if (status & (HostError | RxEarly | StatsFull | TxComplete | IntReq))
+ if (status & (HostError | RxEarly | StatsFull | TxComplete | IntReq)) {
+ if (status == 0xffff)
+ break;
X vortex_error(dev, status);
+ }
X
X if (--work_done < 0) {
X if ((status & (0x7fe - (UpComplete | DownComplete))) == 0) {
@@ -1658,13 +1657,14 @@
X /* Disable all pending interrupts. */
X outw(SetStatusEnb | ((~status) & 0x7FE), ioaddr + EL3_CMD);
X outw(AckIntr | 0x7FF, ioaddr + EL3_CMD);
- /* Set a timer to reenable interrupts. */
-
+ /* The timer will reenable interrupts. */
X break;
X }
X }
X /* Acknowledge the IRQ. */
X outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD);
+ if (vp->cb_fn_base) /* The PCMCIA people are idiots. */
+ writel(0x8000, vp->cb_fn_base + 4);
X
X } while ((status = inw(ioaddr + EL3_STATUS)) & (IntLatch | RxComplete));
X
@@ -1672,16 +1672,18 @@
X printk(KERN_DEBUG "%s: exiting interrupt, status %4.4x.\n",
X dev->name, status);
X
+#if defined(__i386__)
+ clear_bit(0, (void*)&dev->interrupt);
+#else
X dev->interrupt = 0;
- clear_bit(0, (void*)&vp->in_interrupt);
+#endif
X return;
X }
X
-static int
-vortex_rx(struct device *dev)
+static int vortex_rx(struct device *dev)
X {
X struct vortex_private *vp = (struct vortex_private *)dev->priv;


- int ioaddr = dev->base_addr;

+ long ioaddr = dev->base_addr;
X int i;
X short rx_status;
X
@@ -1704,25 +1706,28 @@
X int pkt_len = rx_status & 0x1fff;
X struct sk_buff *skb;
X
- skb = DEV_ALLOC_SKB(pkt_len + 5);
+ skb = dev_alloc_skb(pkt_len + 5);
X if (vortex_debug > 4)
X printk(KERN_DEBUG "Receiving packet size %d status %4.4x.\n",
X pkt_len, rx_status);
X if (skb != NULL) {
X skb->dev = dev;
-#if LINUX_VERSION_CODE >= 0x10300
X skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
X /* 'skb_put()' points to the start of sk_buff data area. */
- insl(ioaddr + RX_FIFO, skb_put(skb, pkt_len),
- (pkt_len + 3) >> 2);
+ if (vp->bus_master &&
+ ! (inw(ioaddr + Wn7_MasterStatus) & 0x8000)) {
+ outl(virt_to_bus(skb_put(skb, pkt_len)),
+ ioaddr + Wn7_MasterAddr);
+ outw((skb->len + 3) & ~3, ioaddr + Wn7_MasterLen);
+ outw(StartDMAUp, ioaddr + EL3_CMD);
+ while (inw(ioaddr + Wn7_MasterStatus) & 0x8000)
+ ;
+ } else {
+ insl(ioaddr + RX_FIFO, skb_put(skb, pkt_len),
+ (pkt_len + 3) >> 2);
+ }
X outw(RxDiscard, ioaddr + EL3_CMD); /* Pop top Rx packet. */
X skb->protocol = eth_type_trans(skb, dev);
-#else
- skb->len = pkt_len;
- /* 'skb->data' points to the start of sk_buff data area. */
- insl(ioaddr + RX_FIFO, skb->data, (pkt_len + 3) >> 2);
- outw(RxDiscard, ioaddr + EL3_CMD); /* Pop top Rx packet. */
-#endif /* KERNEL_1_3_0 */
X netif_rx(skb);
X dev->last_rx = jiffies;
X vp->stats.rx_packets++;
@@ -1751,7 +1756,7 @@
X {
X struct vortex_private *vp = (struct vortex_private *)dev->priv;
X int entry = vp->cur_rx % RX_RING_SIZE;


- int ioaddr = dev->base_addr;

+ long ioaddr = dev->base_addr;
X int rx_status;
X int rx_work_limit = vp->dirty_rx + RX_RING_SIZE - vp->cur_rx;
X
@@ -1759,8 +1764,9 @@
X printk(KERN_DEBUG " In boomerang_rx(), status %4.4x, rx_status "
X "%4.4x.\n",
X inw(ioaddr+EL3_STATUS), inw(ioaddr+RxStatus));
- while ((--rx_work_limit >= 0) &&
- ((rx_status = vp->rx_ring[entry].status) & RxDComplete)) {
+ while ((rx_status = le32_to_cpu(vp->rx_ring[entry].status)) & RxDComplete){
+ if (--rx_work_limit < 0)
+ break;
X if (rx_status & RxDError) { /* Error, update stats. */
X unsigned char rx_error = rx_status >> 16;
X if (vortex_debug > 2)
@@ -1783,41 +1789,28 @@
X /* Check if the packet is long enough to just accept without
X copying to a properly sized skbuff. */
X if (pkt_len < rx_copybreak
- && (skb = DEV_ALLOC_SKB(pkt_len + 2)) != 0) {
+ && (skb = dev_alloc_skb(pkt_len + 2)) != 0) {
X skb->dev = dev;
-#if LINUX_VERSION_CODE >= 0x10300
X skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
X /* 'skb_put()' points to the start of sk_buff data area. */
X memcpy(skb_put(skb, pkt_len),
- bus_to_virt(vp->rx_ring[entry].addr),
+ bus_to_virt(le32_to_cpu(vp->rx_ring[entry].addr)),
X pkt_len);
-#else
- memcpy(skb->data, bus_to_virt(vp->rx_ring[entry].addr), pkt_len);
- skb->len = pkt_len;
-#endif
X rx_copy++;
- } else{
+ } else {
X void *temp;
X /* Pass up the skbuff already on the Rx ring. */
X skb = vp->rx_skbuff[entry];
- if (skb == NULL) {
- printk(KERN_WARNING "%s: in boomerang_rx -- attempt to use NULL skb caught\n", dev->name);
- break;
- }
X vp->rx_skbuff[entry] = NULL;
-#if LINUX_VERSION_CODE >= 0x10300
X temp = skb_put(skb, pkt_len);
-#else
- temp = skb->data;
-#endif
X /* Remove this checking code for final release. */
- if (bus_to_virt(vp->rx_ring[entry].addr) != temp)
+ if (bus_to_virt(le32_to_cpu(vp->rx_ring[entry].addr)) != temp)
X printk(KERN_ERR "%s: Warning -- the skbuff addresses do not match"
X " in boomerang_rx: %p vs. %p.\n", dev->name,
- bus_to_virt(vp->rx_ring[entry].addr), temp);
+ bus_to_virt(le32_to_cpu(vp->rx_ring[entry].addr)),
+ temp);
X rx_nocopy++;
X }
-#if LINUX_VERSION_CODE > 0x10300
X skb->protocol = eth_type_trans(skb, dev);
X { /* Use hardware checksum info. */
X int csum_bits = rx_status & 0xee000000;
@@ -1828,9 +1821,6 @@
X rx_csumhits++;
X }
X }
-#else
- skb->len = pkt_len;
-#endif
X netif_rx(skb);
X dev->last_rx = jiffies;
X vp->stats.rx_packets++;
@@ -1842,29 +1832,17 @@
X struct sk_buff *skb;
X entry = vp->dirty_rx % RX_RING_SIZE;
X if (vp->rx_skbuff[entry] == NULL) {
- skb = DEV_ALLOC_SKB(PKT_BUF_SZ);
- if (skb == NULL) {
- printk(KERN_DEBUG "%s: in boomerang_rx -- could not allocate skbuff\n", dev->name);
+ skb = dev_alloc_skb(PKT_BUF_SZ);
+ if (skb == NULL)
X break; /* Bad news! */
- }
X skb->dev = dev; /* Mark as being used by this device. */
-#if LINUX_VERSION_CODE > 0x10300
X skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
- vp->rx_ring[entry].addr = virt_to_bus(skb->tail);
-#else
- vp->rx_ring[entry].addr = virt_to_bus(skb->data);
-#endif
+ vp->rx_ring[entry].addr = cpu_to_le32(virt_to_bus(skb->tail));
X vp->rx_skbuff[entry] = skb;
X }
X vp->rx_ring[entry].status = 0; /* Clear complete bit. */
X outw(UpUnstall, ioaddr + EL3_CMD);
X }
-
- if (vp->dirty_rx >= RX_RING_SIZE ) {
- vp->cur_rx -= RX_RING_SIZE;
- vp->dirty_rx -= RX_RING_SIZE;
- }
-


X return 0;
X }
X

@@ -1872,7 +1850,7 @@
X vortex_close(struct device *dev)
X {
X struct vortex_private *vp = (struct vortex_private *)dev->priv;


- int ioaddr = dev->base_addr;

+ long ioaddr = dev->base_addr;
X int i;
X
X dev->start = 0;
@@ -1899,12 +1877,7 @@
X /* Turn off thinnet power. Green! */
X outw(StopCoax, ioaddr + EL3_CMD);
X
-#ifdef SA_SHIRQ
X free_irq(dev->irq, dev);
-#else
- free_irq(dev->irq);
- irq2dev_map[dev->irq] = 0;
-#endif
X
X outw(SetIntrEnb | 0x0000, ioaddr + EL3_CMD);
X
@@ -1934,8 +1907,7 @@


X return 0;
X }
X

-static struct enet_statistics *
-vortex_get_stats(struct device *dev)


+static struct net_device_stats *vortex_get_stats(struct device *dev)

X {
X struct vortex_private *vp = (struct vortex_private *)dev->priv;
X unsigned long flags;
@@ -1956,7 +1928,7 @@
X table. This is done by checking that the ASM (!) code generated uses
X atomic updates with '+='.
X */
-static void update_stats(int ioaddr, struct device *dev)


+static void update_stats(long ioaddr, struct device *dev)

X {
X struct vortex_private *vp = (struct vortex_private *)dev->priv;
X
@@ -1987,20 +1959,14 @@
X return;
X }
X

-#ifdef HAVE_PRIVATE_IOCTL
X static int vortex_ioctl(struct device *dev, struct ifreq *rq, int cmd)

X {
X struct vortex_private *vp = (struct vortex_private *)dev->priv;


- int ioaddr = dev->base_addr;

+ long ioaddr = dev->base_addr;
X u16 *data = (u16 *)&rq->ifr_data;
X int phy = vp->phys[0] & 0x1f;
X
- if (vortex_debug > 2)
- printk(KERN_DEBUG "%s: In ioct(%-.6s, %#4.4x) %4.4x %4.4x %4.4x %4.4x.\n",
- dev->name, rq->ifr_ifrn.ifrn_name, cmd,
- data[0], data[1], data[2], data[3]);
-
- switch(cmd) {
+ switch(cmd) {
X case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */
X data[0] = phy;
X case SIOCDEVPRIVATE+1: /* Read the specified MII register. */
@@ -2010,22 +1976,20 @@
X case SIOCDEVPRIVATE+2: /* Write the specified MII register */
X if (!suser())
X return -EPERM;
+ EL3WINDOW(4);
X mdio_write(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2]);
X return 0;
X default:
X return -EOPNOTSUPP;
X }
X }
-#endif /* HAVE_PRIVATE_IOCTL */
X
-/* This new version of set_rx_mode() supports v1.4 kernels.
- The Vortex chip has no documented multicast filter, so the only
+/* Pre-Cyclone chips have no documented multicast filter, so the only
X multicast setting is to receive all multicast frames. At least
X the chip has a very clean way to set the mode, unlike many others. */
-static void
-set_rx_mode(struct device *dev)
+static void set_rx_mode(struct device *dev)
X {
- int ioaddr = dev->base_addr;
+ long ioaddr = dev->base_addr;
X int new_mode;
X
X if (dev->flags & IFF_PROMISC) {
@@ -2039,14 +2003,6 @@
X
X outw(new_mode, ioaddr + EL3_CMD);
X }
-#ifndef NEW_MULTICAST
-/* The old interface to set the Rx mode. */
-static void
-set_multicast_list(struct device *dev, int num_addrs, void *addrs)
-{
- set_rx_mode(dev);
-}
-#endif
X
X
X /* MII transceiver control section.
@@ -2057,7 +2013,7 @@
X /* The maximum data clock rate is 2.5 Mhz. The minimum timing is usually
X met by back-to-back PCI I/O cycles, but we insert a delay to avoid
X "overclocking" issues. */
-#define mdio_delay() udelay(1)
+#define mdio_delay() inl(mdio_addr)
X
X #define MDIO_SHIFT_CLK 0x01
X #define MDIO_DIR_WRITE 0x04
@@ -2068,11 +2024,11 @@
X
X /* Generate the preamble required for initial synchronization and
X a few older transceivers. */


-static void mdio_sync(int ioaddr, int bits)

+static void mdio_sync(long ioaddr, int bits)

X {
- int mdio_addr = ioaddr + Wn4_PhysicalMgmt;
+ long mdio_addr = ioaddr + Wn4_PhysicalMgmt;
X
- /* Establish sync by sending at least 32 logic ones. */
+ /* Establish sync by sending at least 32 logic ones. */
X while (-- bits >= 0) {
X outw(MDIO_DATA_WRITE1, mdio_addr);
X mdio_delay();
@@ -2081,12 +2037,12 @@
X }
X }
X

-static int mdio_read(int ioaddr, int phy_id, int location)

+static int mdio_read(long ioaddr, int phy_id, int location)

X {
X int i;
X int read_cmd = (0xf6 << 10) | (phy_id << 5) | location;
X unsigned int retval = 0;
- int mdio_addr = ioaddr + Wn4_PhysicalMgmt;
+ long mdio_addr = ioaddr + Wn4_PhysicalMgmt;
X
X if (mii_preamble_required)
X mdio_sync(ioaddr, 32);
@@ -2107,13 +2063,17 @@
X outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
X mdio_delay();
X }
- return retval>>1 & 0xffff;
+#if 0
+ return (retval>>1) & 0x1ffff;
+#else
+ return retval & 0x20000 ? 0xffff : retval>>1 & 0xffff;
+#endif
X }
X

-static void mdio_write(int ioaddr, int phy_id, int location, int value)

+static void mdio_write(long ioaddr, int phy_id, int location, int value)

X {
X int write_cmd = 0x50020000 | (phy_id << 23) | (location << 18) | value;
- int mdio_addr = ioaddr + Wn4_PhysicalMgmt;
+ long mdio_addr = ioaddr + Wn4_PhysicalMgmt;
X int i;
X
X if (mii_preamble_required)
@@ -2140,8 +2100,7 @@
X
X
X #ifdef MODULE
-void
-cleanup_module(void)
+void cleanup_module(void)
X {
X struct device *next_dev;
X
@@ -2151,11 +2110,14 @@
X
X /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
X while (root_vortex_dev) {
- next_dev = ((struct vortex_private *)root_vortex_dev->priv)->next_module;
+ struct vortex_private *vp=(void *)(root_vortex_dev->priv);
+ next_dev = vp->next_module;
X unregister_netdev(root_vortex_dev);
X outw(TotalReset, root_vortex_dev->base_addr + EL3_CMD);
- release_region(root_vortex_dev->base_addr, VORTEX_TOTAL_SIZE);
+ release_region(root_vortex_dev->base_addr,
+ pci_tbl[vp->chip_id].io_size);
X kfree(root_vortex_dev);
+ kfree(vp->priv_addr);
X root_vortex_dev = next_dev;
X }
X }
@@ -2166,7 +2128,7 @@
X * Local variables:
X * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
X * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c"
- * compile-command-alt1: "gcc -DCARDBUS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c -o 3c59x_cb.o"
+ * cardbus-compile-command: "gcc -DCARDBUS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c -o 3c575_cb.o -I/usr/src/pcmcia-cs-3.0.5/include/"
X * c-indent-level: 4
X * c-basic-offset: 4
X * tab-width: 4
diff -u --recursive --new-file v2.0.36/linux/drivers/net/Makefile linux/drivers/net/Makefile
--- v2.0.36/linux/drivers/net/Makefile Sun Nov 15 21:51:46 1998
+++ linux/drivers/net/Makefile Sun Jun 13 10:21:01 1999
@@ -682,8 +682,8 @@
X clean:
X rm -f core *.o *.a *.s
X
-rcpci.o: rcpci45.o rcmtl.o
- $(LD) -r -o rcpci.o rcpci45.o rcmtl.o
+rcpci.o: rcpci45.o rclanmtl.o
+ $(LD) -r -o rcpci.o rcpci45.o rclanmtl.o
X
X wd.o: wd.c CONFIG
X $(CC) $(CPPFLAGS) $(CFLAGS) $(WD_OPTS) -c $<
diff -u --recursive --new-file v2.0.36/linux/drivers/net/README.rcpci linux/drivers/net/README.rcpci
--- v2.0.36/linux/drivers/net/README.rcpci Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/README.rcpci Sun Jun 13 10:21:01 1999
@@ -0,0 +1,79 @@
+
+Application Information
+
+
+The included application, called "rcc" (for RedCreek Control), is an
+example of a user-space application (i.e., not running within kernel
+space). It issues ioctl commands to communicate with the PCI driver.
+It can currently report any of the following information:
+
+ - PCI driver information ("getinfo")
+ - card statistics ("getstats")
+ - card's ip address & netmask ("getipnmask")
+ - card's mac address ("getmac")
+ - current speed ("getspeed")
+ - firmware version string ("getfirmware")
+ - status of the link (up or down) ("getstatus")
+
+Also, it can "set" the following parameters:
+
+ - IP and mask
+ - mac address
+ - link speed
+ - promiscuous mode
+
+Example: rcc eth1 setipnmask="192.168.254.254 255.255.255.0"
+
+Note: rcc's command line parser is very basic. If you type the
+command incorrectly, it might result in a core dump.
+
+This program needs to run as root, to avoid encountering permission
+problems. An alternative is to change the permission and ownership
+so that it runs as a setuid root process (for example, "chown
+root.root rcc; chmod u+s rcc").
+
+
+
+Quick PCI driver background
+
+
+The adapter has its own IP and mac addresses which you have to
+assign using the RedCreek manager (assuming the adapter is
+running 3.X firmware). Your linux box will not know anything
+about the adapter's IP address -- ie, the adapter will show up
+as a regular nic. You will assign the linux box IP address using
+the "ifconfig" command, as mentioned below.
+
+
+To compile the driver, simply type "make".
+This, of course, assumes that you have GNU compiler environment
+already setup on a linux box. The .c and .h files were copied
+to a dos filesystem (the floppy), so you may have to use "dos2unix" to
+convert it back to a unix text file. Keep in mind that the driver
+currently works with kernels 2.0.X only. Furthermore, it was only
+tested with kernel 2.0.34.
+
+To load the driver:
+
+"insmod rcpci"
+
+The adapter will show up as a regular nic. Thus, if you have only
+one nic (the pci card) in your box, you would at this point configure
+it with the following commands:
+
+mandatory:
+"ifconfig eth0 <your linux box IP address (NOT the IP address of the
+ adapter!>"
+"route add -net <your network address> eth0"
+
+optional (if you want to be able to access other networks):
+"route add default gw <your default gateway IP address> eth0"
+
+Done. Type "ifconfig" to see "eth0" and the packet count, as well
+as the IP address, net mask, etc.
+
+To unload the driver, you first have to shutdown the interface:
+
+"ifconfig eth0 down"
+
+Then you unload the driver with "rmmod rcpci".
diff -u --recursive --new-file v2.0.36/linux/drivers/net/Space.c linux/drivers/net/Space.c
--- v2.0.36/linux/drivers/net/Space.c Sun Nov 15 21:51:46 1998
+++ linux/drivers/net/Space.c Sun Jun 13 10:21:01 1999
@@ -52,6 +52,7 @@
X extern int express_probe(struct device *);
X extern int eepro_probe(struct device *);
X extern int el3_probe(struct device *);
+extern int tc515_probe(struct device *);
X extern int at1500_probe(struct device *);
X extern int at1700_probe(struct device *);
X extern int fmv18x_probe(struct device *);
diff -u --recursive --new-file v2.0.36/linux/drivers/net/at1700.c linux/drivers/net/at1700.c
--- v2.0.36/linux/drivers/net/at1700.c Mon Jul 13 13:46:29 1998
+++ linux/drivers/net/at1700.c Sun Jun 13 10:21:01 1999
@@ -595,7 +595,6 @@
X /* The inverse routine to net_open(). */
X static int net_close(struct device *dev)
X {
- struct net_local *lp = (struct net_local *)dev->priv;
X int ioaddr = dev->base_addr;
X
X dev->tbusy = 1;
@@ -605,14 +604,6 @@
X outb(0xda, ioaddr + CONFIG_0);
X
X /* No statistic counters on the chip to update. */
-
-#if 0
- /* Disable the IRQ on boards where it is feasible. */
- if (lp->jumpered) {
- outb(0x00, ioaddr + IOCONFIG1);
- free_irq(dev->irq, dev);
- }
-#endif
X
X /* Power-down the chip. Green, green, green! */
X outb(0x00, ioaddr + CONFIG_1);
diff -u --recursive --new-file v2.0.36/linux/drivers/net/de4x5.c linux/drivers/net/de4x5.c
--- v2.0.36/linux/drivers/net/de4x5.c Sun Nov 15 21:51:46 1998
+++ linux/drivers/net/de4x5.c Sun Jun 13 10:21:01 1999
@@ -404,11 +404,12 @@
X alignment for Alpha's and avoid their unaligned
X access traps. This flag is merely for log messages:
X should do something more definitive though...
+ 0.5352 30-Dec-98 Fix driver recognition of the newer DECchips.
X
X =========================================================================
X */
X
-static const char *version = "de4x5.c:V0.5351 1998/10/4 dav...@maniac.ultranet.com\n";
+static const char *version = "de4x5.c:V0.5352 1998/12/30 dav...@maniac.ultranet.com\n";


X
X #include <linux/module.h>
X

@@ -769,7 +770,7 @@
X int tx_new, tx_old; /* TX descriptor ring pointers */
X char setup_frame[SETUP_FRAME_LEN]; /* Holds MCA and PA info. */
X char frame[64]; /* Min sized packet for loopback*/
- struct net_device_stats stats; /* Public stats */
+ struct net_device_stats stats; /* Public stats */
X struct {
X u_int bins[DE4X5_PKT_STAT_SZ]; /* Private stats counters */
X u_int unicast;
@@ -1356,7 +1357,6 @@
X ** Re-initialize the DE4X5...
X */
X status = de4x5_init(dev);
-
X lp->state = OPEN;
X de4x5_dbg_open(dev);
X
@@ -1599,7 +1599,7 @@
X DISABLE_IRQs; /* Ensure non re-entrancy */
X
X if (test_and_set_bit(MASK_INTERRUPTS, (void*) &lp->interrupt))
- printk("%s: Re-entering the interrupt handler.\n", dev->name);
+ printk("%s: Re-entering the interrupt handler.\n", dev->name);
X
X #if LINUX_VERSION_CODE >= ((2 << 16) | (1 << 8))
X synchronize_irq();
@@ -2075,7 +2075,9 @@
X irq = inb(EISA_REG0);
X irq = de4x5_irq[(irq >> 1) & 0x03];
X
- if (is_DC2114x) device |= (cfrv & CFRV_RN);
+ if (is_DC2114x) {
+ device = ((cfrv & CFRV_RN) < DC2114x_BRK ? DC21142 : DC21143);
+ }
X lp->chipset = device;
X
X /* Write the PCI Configuration Registers */
@@ -2180,7 +2182,9 @@
X lp->bus_num = pb;
X
X /* Set the chipset information */
- if (is_DC2114x) device |= (cfrv & CFRV_RN);
+ if (is_DC2114x) {
+ device = ((cfrv & CFRV_RN) < DC2114x_BRK ? DC21142 : DC21143);
+ }
X lp->chipset = device;
X
X /* Get the board I/O address (64 bits on sparc64) */
@@ -2291,7 +2295,9 @@
X lp->bus_num = pb;
X
X /* Set the chipset information */
- if (is_DC2114x) device |= (cfrv & CFRV_RN);
+ if (is_DC2114x) {
+ device = ((cfrv & CFRV_RN) < DC2114x_BRK ? DC21142 : DC21143);
+ }
X lp->chipset = device;
X
X /* Get the board I/O address (64 bits on sparc64) */
@@ -5657,7 +5663,7 @@
X cli();
X copy_to_user(ioc->data, &lp->pktStats, ioc->len);
X sti();
-
+
X break;
X case DE4X5_CLR_STATS: /* Zero out the driver statistics */
X if (suser()) {
@@ -5830,6 +5836,12 @@
X if (!mdev) mdev = p;
X
X if (register_netdev(p) != 0) {
+ struct de4x5_private *lp = (struct de4x5_private *)p->priv;
+ if (lp) {
+ release_region(p->base_addr, (lp->bus == PCI ?
+ DE4X5_PCI_TOTAL_SIZE :
+ DE4X5_EISA_TOTAL_SIZE));
+ }
X kfree(p);
X } else {
X status = 0; /* At least one adapter will work */
diff -u --recursive --new-file v2.0.36/linux/drivers/net/de4x5.h linux/drivers/net/de4x5.h
--- v2.0.36/linux/drivers/net/de4x5.h Mon Jul 13 13:46:29 1998
+++ linux/drivers/net/de4x5.h Sun Jun 13 10:21:01 1999
@@ -121,6 +121,7 @@
X #define DC2114x DC2114x_DID
X #define DC21142 (DC2114x_DID | 0x0010)
X #define DC21143 (DC2114x_DID | 0x0030)
+#define DC2114x_BRK 0x0020 /* CFRV break between DC21142 & DC21143 */
X
X #define is_DC21040 ((vendor == DC21040_VID) && (device == DC21040_DID))
X #define is_DC21041 ((vendor == DC21041_VID) && (device == DC21041_DID))
diff -u --recursive --new-file v2.0.36/linux/drivers/net/depca.c linux/drivers/net/depca.c
--- v2.0.36/linux/drivers/net/depca.c Tue Apr 8 08:47:45 1997
+++ linux/drivers/net/depca.c Sun Jun 13 10:21:01 1999
@@ -154,7 +154,20 @@
X the 'memory autoprobe' picking the wrong shared memory (for the case of
X 2 depca's in a PC).
X
+ ************************************************************************
+ Support for MCA EtherWORKS cards added 11-3-98.
+ Verified to work with up to 2 DE212 cards in a system (although not
+ fully stress-tested).
+
+ Currently known bugs/limitations:
+
+ Note: with the MCA stuff as a module, it trusts the MCA configuration,
+ not the command line for IRQ and memory address. You can
+ specify them if you want, but it will throw your values out.
+ You still have to pass the IO address it was configured as
+ though.
X
+ ************************************************************************
X TO DO:
X ------
X
@@ -202,11 +215,16 @@
X 0.422 29-Apr-96 Fix depca_hw_init() bug <ja...@markkus2.fimr.fi>
X 0.423 7-Jun-96 Fix module load bug <k...@barco.be>
X 0.43 16-Aug-96 Update alloc_device() to conform to de4x5.c
+ 0.44 1-Sep-97 Fix *_probe() to test check_region() first - bug
+ reported by <mmog...@elbert.uccs.edu>
+ 0.45 3-Nov-98 Added support for MCA EtherWORKS (DE210/DE212) cards
+ by <ty...@computer.org>
+ 0.451 5-Nov-98 Fixed mca stuff cuz I'm a dummy. <ty...@computer.org>
X
X =========================================================================
X */
X
-static const char *version = "depca.c:v0.43 96/8/16 dav...@maniac.ultranet.com\n";
+static const char *version = "depca.c:v0.451 1998/11/14 dav...@maniac.ultranet.com\n";


X
X #include <linux/module.h>
X

@@ -233,6 +251,10 @@
X #include <linux/unistd.h>
X #include <linux/ctype.h>
X
+#ifdef CONFIG_MCA
+#include <linux/mca.h>
+#endif
+
X #include "depca.h"
X
X #ifdef DEPCA_DEBUG
@@ -280,15 +302,20 @@
X static short mem_chkd = 0;
X
X /*
+** Adapter ID for the MCA EtherWORKS DE210/212 adapter
+*/
+#define DE212_ID 0x6def
+
+/*
X ** Name <-> Adapter mapping
X */
X #define DEPCA_SIGNATURE {"DEPCA",\
X "DE100","DE101",\
X "DE200","DE201","DE202",\
- "DE210",\
+ "DE210","DE212",\
X "DE422",\
X ""}
-static enum {DEPCA, de100, de101, de200, de201, de202, de210, de422, unknown} adapter;
+static enum {DEPCA, de100, de101, de200, de201, de202, de210, de212, de422, unknown} adapter;
X
X /*
X ** Miscellaneous info...
@@ -342,7 +369,7 @@
X char devname[DEPCA_STRLEN]; /* Device Product String */
X char adapter_name[DEPCA_STRLEN];/* /proc/ioports string */
X char adapter; /* Adapter type */
- struct depca_rx_desc *rx_ring; /* Pointer to start of RX descriptor ring */
+ char mca_slot; /* MCA slot, if MCA else -1 */ struct depca_rx_desc *rx_ring; /* Pointer to start of RX descriptor ring */
X struct depca_tx_desc *tx_ring; /* Pointer to start of TX descriptor ring */
X struct depca_init init_block;/* Shadow Initialization block */
X char *rx_memcpy[NUM_RX_DESC]; /* CPU virt address of sh'd memory buffs */
@@ -393,7 +420,7 @@
X /*
X ** Private functions
X */
-static int depca_hw_init(struct device *dev, u_long ioaddr);
+static int depca_hw_init(struct device *dev, u_long ioaddr, int mca_slot);
X static void depca_init_ring(struct device *dev);
X static int depca_rx(struct device *dev);
X static int depca_tx(struct device *dev);
@@ -407,6 +434,9 @@
X static void SetMulticastFilter(struct device *dev);
X static void isa_probe(struct device *dev, u_long iobase);
X static void eisa_probe(struct device *dev, u_long iobase);
+#ifdef CONFIG_MCA
+static void mca_probe(struct device *dev, u_long iobase);
+#endif
X static struct device *alloc_device(struct device *dev, u_long iobase);
X static int depca_dev_index(char *s);
X static struct device *insert_device(struct device *dev, u_long iobase, int (*init)(struct device *));
@@ -441,7 +471,8 @@
X
X
X
-int depca_probe(struct device *dev)
+int
+depca_probe(struct device *dev)
X {
X int tmp = num_depcas, status = -ENODEV;
X u_long iobase = dev->base_addr;
@@ -450,6 +481,9 @@
X printk("Autoprobing is not supported when loading a module based driver.\n");
X status = -EIO;
X } else {
+#ifdef CONFIG_MCA
+ mca_probe(dev, iobase);
+#endif
X isa_probe(dev, iobase);
X eisa_probe(dev, iobase);
X
@@ -472,7 +506,7 @@


X }
X
X static int

-depca_hw_init(struct device *dev, u_long ioaddr)
+depca_hw_init(struct device *dev, u_long ioaddr, int mca_slot)
X {
X struct depca_private *lp;
X int i, j, offset, netRAM, mem_len, status=0;
@@ -495,7 +529,10 @@
X if ((adapter != unknown) && mem_start) { /* found a DEPCA device */


X dev->base_addr = ioaddr;
X

- if ((ioaddr&0x0fff)==DEPCA_EISA_IO_PORTS) {/* EISA slot address */
+ if (mca_slot != -1) {
+ printk("%s: %s at 0x%04lx (MCA slot %d)", dev->name, name,
+ ioaddr, mca_slot);
+ } else if ((ioaddr & 0x0fff) == DEPCA_EISA_IO_PORTS) { /* EISA slot address */
X printk("%s: %s at 0x%04lx (EISA slot %d)",
X dev->name, name, ioaddr, (int)((ioaddr>>12)&0x0f));
X } else { /* ISA port address */
@@ -541,7 +578,8 @@
X lp = (struct depca_private *)dev->priv;
X memset((char *)dev->priv, 0, sizeof(struct depca_private));
X lp->adapter = adapter;
- sprintf(lp->adapter_name,"%s (%s)", name, dev->name);
+ lp->mca_slot = mca_slot;
+ sprintf(lp->adapter_name,"%s (%s)", name, dev->name);
X request_region(ioaddr, DEPCA_TOTAL_SIZE, lp->adapter_name);
X
X /* Initialisation Block */
@@ -603,6 +641,7 @@
X case de201:
X case de202:
X case de210:
+ case de212:
X depca_irq = de2xx_irq;
X break;
X case de422:
@@ -1205,10 +1244,161 @@
X return;
X }
X
+#ifdef CONFIG_MCA
+/*
+** Microchannel bus I/O device probe
+*/
+static void
+mca_probe(struct device *dev, u_long ioaddr)
+{
+ unsigned char pos[2];
+ unsigned char where;
+ unsigned long iobase;
+ int irq;
+ int slot = 0;
+
+ /*
+ ** See if we've been here before.
+ */
+ if ((!ioaddr && autoprobed) || (ioaddr && !loading_module)) return;
+
+ if (MCA_bus) {
+ /*
+ ** Search for the adapter. If an address has been given, search
+ ** specifically for the card at that address. Otherwise find the
+ ** first card in the system.
+ */
+ while ((dev!=NULL) &&
+ ((slot=mca_find_adapter(DE212_ID, slot)) != MCA_NOTFOUND)) {
+ pos[0] = mca_read_stored_pos(slot, 2);
+ pos[1] = mca_read_stored_pos(slot, 3);
+
+ /*
+ ** IO of card is handled by bits 1 and 2 of pos0.
+ **
+ ** bit2 bit1 IO
+ ** 0 0 0x2c00
+ ** 0 1 0x2c10
+ ** 1 0 0x2c20
+ ** 1 1 0x2c30
+ */
+ where = (pos[0] & 6) >> 1;
+ iobase = 0x2c00 + (0x10 * where);
+
+ if ((ioaddr) && (ioaddr != iobase)) {
+ /*
+ ** Card was found, but not at the right IO location. Continue
+ ** scanning from the next MCA slot up for another card.
+ */
+ slot++;
+ continue;
+ }
+
+ /*
+ ** Found the adapter we were looking for. Now start setting it up.
+ **
+ ** First work on decoding the IRQ. It's stored in the lower 4 bits
+ ** of pos1. Bits are as follows (from the ADF file):
+ **
+ ** Bits
+ ** 3 2 1 0 IRQ
+ ** --------------------
+ ** 0 0 1 0 5
+ ** 0 0 0 1 9
+ ** 0 1 0 0 10
+ ** 1 0 0 0 11
+ **/
+ where = pos[1] & 0x0f;
+ switch(where) {
+ case 1:
+ irq = 9;
+ break;
+ case 2:
+ irq = 5;
+ break;
+ case 4:
+ irq = 10;
+ break;
+ case 8:
+ irq = 11;
+ break;
+ default:
+ printk("%s: mca_probe IRQ error. You should never get here (%d).\n", dev->name, where);
+ return;
+ }
+
+ /*
+ ** Shared memory address of adapter is stored in bits 3-5 of pos0.
+ ** They are mapped as follows:
+ **
+ ** Bit
+ ** 5 4 3 Memory Addresses
+ ** 0 0 0 C0000-CFFFF (64K)
+ ** 1 0 0 C8000-CFFFF (32K)
+ ** 0 0 1 D0000-DFFFF (64K)
+ ** 1 0 1 D8000-DFFFF (32K)
+ ** 0 1 0 E0000-EFFFF (64K)
+ ** 1 1 0 E8000-EFFFF (32K)
+ */
+ where = (pos[0] & 0x18) >> 3;
+ mem = 0xc0000 + (where * 0x10000);
+ if (pos[0] & 0x20) {
+ mem += 0x8000;
+ }
+
+ /*
+ ** Get everything allocated and initialized... (almost just
+ ** like the ISA and EISA probes)
+ */
+ if (DevicePresent(iobase) != 0) {
+ /*
+ ** If the MCA configuration says the card should be here,
+ ** it really should be here.
+ */
+ printk(KERN_ERR "%s: MCA reports card at 0x%lx but it is not
+responding.\n", dev->name, iobase);
+ }
+
+ if (check_region(iobase, DEPCA_TOTAL_SIZE) == 0) {
+ if ((dev = alloc_device(dev, iobase)) != NULL) {
+ dev->irq = irq;
+ if (depca_hw_init(dev, iobase, slot) == 0) {
+ /*
+ ** Adapter initialized correctly: Name it in
+ ** /proc/mca.
+ */
+ mca_set_adapter_name(slot, "DE210/212 Ethernet Adapter");
+ mca_mark_as_used(slot);
+ num_depcas++;
+ }
+ num_eth++;
+ }
+ } else if (autoprobed) {
+ printk(KERN_WARNING "%s: region already allocated at 0x%04lx.\n", dev->name, iobase);
+ }
+
+ /*
+ ** If this is a probe by a module, return after setting up the
+ ** given card.
+ */
+ if (ioaddr) return;
+
+ /*
+ ** Set up to check the next slot and loop.
+ */
+ slot++;
+ }
+ }
+
+ return;


+}
+#endif
+
X /*

X ** ISA bus I/O device probe
X */
-static void isa_probe(struct device *dev, u_long ioaddr)
+static void
+isa_probe(struct device *dev, u_long ioaddr)
X {
X int i = num_depcas, maxSlots;
X s32 ports[] = DEPCA_IO_PORTS;
@@ -1225,17 +1415,17 @@
X }
X
X for (; (i<maxSlots) && (dev!=NULL) && ports[i]; i++) {
- if (DevicePresent(ports[i]) == 0) {
- if (check_region(ports[i], DEPCA_TOTAL_SIZE) == 0) {
+ if (check_region(ports[i], DEPCA_TOTAL_SIZE) == 0) {
+ if (DevicePresent(ports[i]) == 0) {
X if ((dev = alloc_device(dev, ports[i])) != NULL) {
- if (depca_hw_init(dev, ports[i]) == 0) {
+ if (depca_hw_init(dev, ports[i], -1) == 0) {
X num_depcas++;
X }
X num_eth++;
X }
- } else if (autoprobed) {
- printk("%s: region already allocated at 0x%04x.\n", dev->name,ports[i]);
X }
+ } else if (autoprobed) {
+ printk("%s: region already allocated at 0x%04x.\n", dev->name,ports[i]);
X }
X }
X
@@ -1246,7 +1436,8 @@
X ** EISA bus I/O device probe. Probe from slot 1 since slot 0 is usually
X ** the motherboard. Upto 15 EISA devices are supported.
X */
-static void eisa_probe(struct device *dev, u_long ioaddr)
+static void
+eisa_probe(struct device *dev, u_long ioaddr)
X {
X int i, maxSlots;
X u_long iobase;
@@ -1267,19 +1458,19 @@
X if ((iobase & 0x0fff) == 0) iobase += DEPCA_EISA_IO_PORTS;
X
X for (; (i<maxSlots) && (dev!=NULL); i++, iobase+=EISA_SLOT_INC) {
- if (EISA_signature(name, EISA_ID)) {
- if (DevicePresent(iobase) == 0) {
- if (check_region(iobase, DEPCA_TOTAL_SIZE) == 0) {
+ if (check_region(iobase, DEPCA_TOTAL_SIZE) == 0) {
+ if (EISA_signature(name, EISA_ID)) {
+ if (DevicePresent(iobase) == 0) {
X if ((dev = alloc_device(dev, iobase)) != NULL) {
- if (depca_hw_init(dev, iobase) == 0) {
+ if (depca_hw_init(dev, iobase, -1) == 0) {
X num_depcas++;
X }
X num_eth++;
X }
- } else if (autoprobed) {
- printk("%s: region already allocated at 0x%04lx.\n",dev->name,iobase);
X }
X }
+ } else if (autoprobed) {
+ printk("%s: region already allocated at 0x%04lx.\n",dev->name,iobase);
X }
X }
X
@@ -1683,7 +1874,7 @@
X /*
X ** Perform IOCTL call functions here. Some are privileged operations and the
X ** effective uid is checked in those cases.
-** All MCA IOCTLs will not work here and are for testing purposes only.
+** All multicast IOCTLs will not work here and are for testing purposes only.
X */
X static int depca_ioctl(struct device *dev, struct ifreq *rq, int cmd)
X {
@@ -1703,126 +1894,103 @@
X tmp.addr[i] = dev->dev_addr[i];
X }
X ioc->len = ETH_ALEN;
- if (!(status = verify_area(VERIFY_WRITE, (void *)ioc->data, ioc->len))) {
- memcpy_tofs(ioc->data, tmp.addr, ioc->len);
- }
-
+ if (verify_area(VERIFY_WRITE, (void *)ioc->data, ioc->len)) return -EFAULT;
+ memcpy_tofs(ioc->data, tmp.addr, ioc->len);
X break;
+
X case DEPCA_SET_HWADDR: /* Set the hardware address */
- if (suser()) {
- if (!(status = verify_area(VERIFY_READ, (void *)ioc->data, ETH_ALEN))) {
- memcpy_fromfs(tmp.addr,ioc->data,ETH_ALEN);
- for (i=0; i<ETH_ALEN; i++) {
- dev->dev_addr[i] = tmp.addr[i];
- }
- while(dev->tbusy); /* Stop ring access */
- set_bit(0, (void*)&dev->tbusy);
- while(lp->tx_old != lp->tx_new);/* Wait for the ring to empty */
-
- STOP_DEPCA; /* Temporarily stop the depca. */
- depca_init_ring(dev); /* Initialize the descriptor rings */
- LoadCSRs(dev); /* Reload CSR3 */
- InitRestartDepca(dev); /* Resume normal operation. */
- dev->tbusy = 0; /* Unlock the TX ring */
- }
- } else {
- status = -EPERM;
+ if (!suser()) return -EPERM;
+ if (verify_area(VERIFY_READ, (void *)ioc->data, ETH_ALEN)) return -EFAULT;
+ memcpy_fromfs(tmp.addr,ioc->data,ETH_ALEN);
+ for (i=0; i<ETH_ALEN; i++) {
+ dev->dev_addr[i] = tmp.addr[i];
X }
+ while(dev->tbusy) barrier(); /* Stop ring access */
+ set_bit(0, (void*)&dev->tbusy);
+ while(lp->tx_old != lp->tx_new); /* Wait for the ring to empty */
X
+ STOP_DEPCA; /* Temporarily stop the depca. */
+ depca_init_ring(dev); /* Initialize the descriptor rings */
+ LoadCSRs(dev); /* Reload CSR3 */
+ InitRestartDepca(dev); /* Resume normal operation. */
+ dev->tbusy = 0; /* Unlock the TX ring */
X break;
+
X case DEPCA_SET_PROM: /* Set Promiscuous Mode */
- if (suser()) {
- while(dev->tbusy); /* Stop ring access */
- set_bit(0, (void*)&dev->tbusy);
- while(lp->tx_old != lp->tx_new); /* Wait for the ring to empty */
-
- STOP_DEPCA; /* Temporarily stop the depca. */
- depca_init_ring(dev); /* Initialize the descriptor rings */
- lp->init_block.mode |= PROM; /* Set promiscuous mode */
-
- LoadCSRs(dev); /* Reload CSR3 */
- InitRestartDepca(dev); /* Resume normal operation. */
- dev->tbusy = 0; /* Unlock the TX ring */
- } else {
- status = -EPERM;
- }
+ if (!suser()) return -EPERM;
+ while(dev->tbusy) barrier(); /* Stop ring access */
+ set_bit(0, (void*)&dev->tbusy);
+ while(lp->tx_old != lp->tx_new); /* Wait for the ring to empty */
X
+ STOP_DEPCA; /* Temporarily stop the depca. */
+ depca_init_ring(dev); /* Initialize the descriptor rings */
+ lp->init_block.mode |= PROM; /* Set promiscuous mode */
+
+ LoadCSRs(dev); /* Reload CSR3 */
+ InitRestartDepca(dev); /* Resume normal operation. */
+ dev->tbusy = 0; /* Unlock the TX ring */
X break;
+
X case DEPCA_CLR_PROM: /* Clear Promiscuous Mode */
- if (suser()) {
- while(dev->tbusy); /* Stop ring access */
- set_bit(0, (void*)&dev->tbusy);
- while(lp->tx_old != lp->tx_new); /* Wait for the ring to empty */
-
- STOP_DEPCA; /* Temporarily stop the depca. */
- depca_init_ring(dev); /* Initialize the descriptor rings */
- lp->init_block.mode &= ~PROM; /* Clear promiscuous mode */
-
- LoadCSRs(dev); /* Reload CSR3 */
- InitRestartDepca(dev); /* Resume normal operation. */
- dev->tbusy = 0; /* Unlock the TX ring */
- } else {
- status = -EPERM;
- }
+ if (!suser()) return -EPERM;
+ while(dev->tbusy) barrier(); /* Stop ring access */
+ set_bit(0, (void*)&dev->tbusy);
+ while(lp->tx_old != lp->tx_new); /* Wait for the ring to empty */
X
+ STOP_DEPCA; /* Temporarily stop the depca. */
+ depca_init_ring(dev); /* Initialize the descriptor rings */
+ lp->init_block.mode &= ~PROM; /* Clear promiscuous mode */
+
+ LoadCSRs(dev); /* Reload CSR3 */
+ InitRestartDepca(dev); /* Resume normal operation. */
+ dev->tbusy = 0; /* Unlock the TX ring */


SHAR_EOF
true || echo 'restore of patch-2.0.37 failed'
fi

echo 'End of part 10'
echo 'File patch-2.0.37 is continued in part 11'
echo 11 > _shar_seq_.tmp

Thomas...@ciw.uni-karlsruhe.de

unread,
Jun 16, 1999, 3:00:00 AM6/16/99
to
Archive-name: v2.0/patch-2.0.37/part11

#!/bin/sh
# this is part 11 of a 45 - part archive


# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.0.37 continued
if test ! -r _shar_seq_.tmp; then
echo 'Please unpack part 1 first!'
exit 1
fi
(read Scheck

if test "$Scheck" != 11; then


echo Please unpack part "$Scheck" next!
exit 1
else
exit 0
fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.0.37'
else
echo 'x - continuing with patch-2.0.37'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.0.37' &&

X break;
+
X case DEPCA_SAY_BOO: /* Say "Boo!" to the kernel log file */
X printk("%s: Boo!\n", dev->name);
-
X break;
+
X case DEPCA_GET_MCA: /* Get the multicast address table */
X ioc->len = (HASH_TABLE_LEN >> 3);
- if (!(status = verify_area(VERIFY_WRITE, ioc->data, ioc->len))) {
- memcpy_tofs(ioc->data, lp->init_block.mcast_table, ioc->len);
- }
-
+ if (verify_area(VERIFY_WRITE, ioc->data, ioc->len)) return -EFAULT;
+ memcpy_tofs(ioc->data, lp->init_block.mcast_table, ioc->len);
X break;
- case DEPCA_SET_MCA: /* Set a multicast address */
- if (suser()) {
- if (!(status=verify_area(VERIFY_READ, ioc->data, ETH_ALEN*ioc->len))) {
- memcpy_fromfs(tmp.addr, ioc->data, ETH_ALEN * ioc->len);
- set_multicast_list(dev);


- }
- } else {
- status = -EPERM;

- }
X
+ case DEPCA_SET_MCA: /* Set a multicast address */


+ if (!suser()) return -EPERM;

+ if (verify_area(VERIFY_READ, ioc->data, ETH_ALEN*ioc->len)) return -EFAULT;
+ memcpy_fromfs(tmp.addr, ioc->data, ETH_ALEN * ioc->len);
+ set_multicast_list(dev);
X break;
- case DEPCA_CLR_MCA: /* Clear all multicast addresses */
- if (suser()) {
- set_multicast_list(dev);


- } else {
- status = -EPERM;
- }

X
+ case DEPCA_CLR_MCA: /* Clear all multicast addresses */


+ if (!suser()) return -EPERM;

+ set_multicast_list(dev);
X break;
+
X case DEPCA_MCA_EN: /* Enable pass all multicast addressing */
- if (suser()) {


+ if (!suser()) return -EPERM;

X set_multicast_list(dev);


- } else {
- status = -EPERM;
- }

-
X break;
+
X case DEPCA_GET_STATS: /* Get the driver statistics */
X cli();
X ioc->len = sizeof(lp->pktStats);
- if (!(status=verify_area(VERIFY_WRITE, ioc->data, ioc->len))) {
- memcpy_tofs(ioc->data, &lp->pktStats, ioc->len);
+ if (verify_area(VERIFY_WRITE, ioc->data, ioc->len)) {
+ status = -EFAULT;
+ } else {
+ memcpy_tofs(ioc->data, &lp->pktStats, ioc->len);
X }
X sti();
-
X break;
- case DEPCA_CLR_STATS: /* Zero out the driver statistics */
- if (suser()) {
- cli();
- memset(&lp->pktStats, 0, sizeof(lp->pktStats));
- sti();


- } else {
- status = -EPERM;
- }

X
+ case DEPCA_CLR_STATS: /* Zero out the driver statistics */


+ if (!suser()) return -EPERM;

+ cli();
+ memset(&lp->pktStats, 0, sizeof(lp->pktStats));
+ sti();
X break;
+
X case DEPCA_GET_REG: /* Get the DEPCA Registers */
X i=0;
X tmp.sval[i++] = inw(DEPCA_NICSR);
@@ -1830,25 +1998,25 @@
X tmp.sval[i++] = inw(DEPCA_DATA);
X memcpy(&tmp.sval[i], &lp->init_block, sizeof(struct depca_init));
X ioc->len = i+sizeof(struct depca_init);
- if (!(status=verify_area(VERIFY_WRITE, ioc->data, ioc->len))) {


- memcpy_tofs(ioc->data, tmp.addr, ioc->len);
- }
-

+ if (verify_area(VERIFY_WRITE, ioc->data, ioc->len)) return -EFAULT;


+ memcpy_tofs(ioc->data, tmp.addr, ioc->len);
X break;
+

X default:
- status = -EOPNOTSUPP;
+ return -EOPNOTSUPP;
X }
X
X return status;


X }
X
X #ifdef MODULE

-static char devicename[9] = { 0, };
+static char devicename[9] = {0,};
X static struct device thisDepca = {
X devicename, /* device name is inserted by /linux/drivers/net/net_init.c */
X 0, 0, 0, 0,
X 0x200, 7, /* I/O address, IRQ */
- 0, 0, 0, NULL, depca_probe };
+ 0, 0, 0, NULL, depca_probe
+};
X
X static int irq=7; /* EDIT THESE LINE FOR YOUR CONFIGURATION */
X static int io=0x200; /* Or use the irq= io= options to insmod */
@@ -1869,8 +2037,13 @@
X void
X cleanup_module(void)
X {
- if (thisDepca.priv) {
- kfree(thisDepca.priv);
+ struct depca_private *lp = thisDepca.priv;
+ if (lp) {
+#ifdef CONFIG_MCA
+ if(lp->mca_slot != -1)
+ mca_mark_as_unused(lp->mca_slot);
+#endif
+ kfree(lp);
X thisDepca.priv = NULL;
X }
X thisDepca.irq=0;
diff -u --recursive --new-file v2.0.36/linux/drivers/net/dgrs.c linux/drivers/net/dgrs.c
--- v2.0.36/linux/drivers/net/dgrs.c Sun Nov 15 10:49:38 1998
+++ linux/drivers/net/dgrs.c Sun Jun 13 10:21:01 1999
@@ -1254,10 +1254,11 @@
X )
X {
X DGRS_PRIV *priv;
- int i;
X
X #ifdef MODULE
X {
+ int i;
+
X /* Allocate and fill new device structure. */
X int dev_size = sizeof(struct device) + sizeof(DGRS_PRIV);
X
diff -u --recursive --new-file v2.0.36/linux/drivers/net/dummy.c linux/drivers/net/dummy.c
--- v2.0.36/linux/drivers/net/dummy.c Sun May 19 22:08:36 1996
+++ linux/drivers/net/dummy.c Sun Jun 13 10:21:01 1999
@@ -70,6 +70,10 @@


X return 0;
X }
X

+static int dummy_rebuild(void *eth, struct device *dev, unsigned long raddr, struct sk_buff *skb)


+{
+ return 0;
+}

X
X int dummy_init(struct device *dev)
X {
@@ -94,6 +98,7 @@
X /* Fill in the fields of the device structure with ethernet-generic values. */
X ether_setup(dev);
X dev->flags |= IFF_NOARP;
+ dev->rebuild_header = dummy_rebuild;
X
X return 0;
X }
diff -u --recursive --new-file v2.0.36/linux/drivers/net/eepro100.c linux/drivers/net/eepro100.c
--- v2.0.36/linux/drivers/net/eepro100.c Sun Nov 15 21:51:46 1998
+++ linux/drivers/net/eepro100.c Sun Jun 13 10:21:01 1999
@@ -7,7 +7,7 @@
X of the GNU Public License, incorporated herein by reference.
X
X This driver is for the Intel EtherExpress Pro 100B boards.
- It should work with other i82557 boards (if any others exist).
+ It should work with other i82557 and i82558 boards.
X To use a built-in driver, install as drivers/net/eepro100.c.
X To use as a module, use the compile-command at the end of the file.
X
@@ -15,11 +15,13 @@
X Center of Excellence in Space Data and Information Sciences
X Code 930.5, NASA Goddard Space Flight Center, Greenbelt MD 20771
X For updates see
- <base href="http://cesdis.gsfc.nasa.gov/linux/drivers/eepro100.html">
+ http://cesdis.gsfc.nasa.gov/linux/drivers/eepro100.html
+ There is also a mailing list based at
+ linux-e...@cesdis.gsfc.nasa.gov
X */
X
X static const char *version =
-"eepro100.c:v0.99B 4/7/98 Donald Becker linux-e...@cesdis.gsfc.nasa.gov\n";
+"eepro100.c:v1.05 10/16/98 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/eepro100.html\n";
X
X /* A few user-configurable values that apply to all boards.
X First set are undocumented and spelled per Intel recommendations. */
@@ -41,6 +43,7 @@
X /* Maximum number of multicast addresses to filter (vs. rx-all-multicast) */
X static int multicast_filter_limit = 64;
X
+#include <linux/config.h>


X #ifdef MODULE
X #ifdef MODVERSIONS
X #include <linux/modversions.h>

@@ -53,20 +56,18 @@
X
X #include <linux/version.h>
X #include <linux/kernel.h>
-#include <linux/sched.h>
X #include <linux/string.h>
X #include <linux/timer.h>
-#include <linux/ptrace.h>
X #include <linux/errno.h>


X #include <linux/ioport.h>
X #include <linux/malloc.h>
X #include <linux/interrupt.h>
X #include <linux/pci.h>

-#include <linux/bios32.h>
-#include <asm/processor.h> /* Processor type for cache alignment. */
+#if LINUX_VERSION_CODE < 0x20155
+#include <linux/bios32.h> /* Ignore the bogus warning in 2.1.100+ */
+#endif


X #include <asm/bitops.h>
X #include <asm/io.h>

-#include <asm/dma.h>
X
X #include <linux/netdevice.h>
X #include <linux/etherdevice.h>
@@ -74,9 +75,9 @@
X #include <linux/delay.h>
X
X /* Unused in the 2.0.* version, but retained for documentation. */
-#if LINUX_VERSION_CODE > 0x20118
+#if LINUX_VERSION_CODE > 0x20118 && defined(MODULE)


X MODULE_AUTHOR("Donald Becker <bec...@cesdis.gsfc.nasa.gov>");

-MODULE_DESCRIPTION("Intel i82557/i82558 EtherExpressPro driver");
+MODULE_DESCRIPTION("Intel i82557/i82558 PCI EtherExpressPro driver");
X MODULE_PARM(debug, "i");
X MODULE_PARM(options, "1-" __MODULE_STRING(8) "i");
X MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i");
@@ -95,6 +96,11 @@
X #if (LINUX_VERSION_CODE < 0x20123)


X #define test_and_set_bit(val, addr) set_bit(val, addr)

X #endif
+#if LINUX_VERSION_CODE < 0x20159
+#define dev_free_skb(skb) dev_kfree_skb(skb, FREE_WRITE);
+#else
+#define dev_free_skb(skb) dev_kfree_skb(skb);
+#endif
X
X /* The total I/O port extent of the board.
X The registers beyond 0x18 only exist on the i82558. */
@@ -132,7 +138,7 @@
X Despite the extra space overhead in each receive skbuff, the driver must use
X the simplified Rx buffer mode to assure that only a single data buffer is
X associated with each RxFD. The driver implements this by reserving space
-for the Rx descriptor at the head of each Rx skbuff
+for the Rx descriptor at the head of each Rx skbuff.
X
X The Speedo-3 has receive and command unit base addresses that are added to
X almost all descriptor pointers. The driver sets these to zero, so that all
@@ -147,10 +153,13 @@
X
X The driver must use the complex Tx command+descriptor mode in order to
X have a indirect pointer to the skbuff data section. Each Tx command block
-(TxCB) is associated with a single, immediately appended Tx buffer descriptor
+(TxCB) is associated with two immediately appended Tx Buffer Descriptor
X (TxBD). A fixed ring of these TxCB+TxBD pairs are kept as part of the
X speedo_private data structure for each adapter instance.
X
+The newer i82558 explicitly supports this structure, and can read the two
+TxBDs in the same PCI burst as the TxCB.
+
X This ring structure is used for all normal transmit packets, but the
X transmit packet descriptors aren't long enough for most non-Tx commands such
X as CmdConfigure. This is complicated by the possibility that the chip has
@@ -181,10 +190,10 @@
X doing the CU_RESUME
X the chip processes the next-yet-valid post-final-command.
X So blindly sending a CU_RESUME is only safe if we do it immediately after
-erasing the previous CmdSuspend, without the possibility of an intervening
-delay. Thus the resume command is always within the interrupts-disabled
-region. This is a timing dependence, but handling this condition in a
-timing-independent way would considerably complicate the code.
+after erasing the previous CmdSuspend, without the possibility of an
+intervening delay. Thus the resume command is always within the
+interrupts-disabled region. This is a timing dependence, but handling this
+condition in a timing-independent way would considerably complicate the code.
X
X Note: In previous generation Intel chips, restarting the command unit was a
X notoriously slow process. This is presumably no longer true.
@@ -243,11 +252,11 @@
X
X /* How to wait for the command unit to accept a command.
X Typically this takes 0 ticks. */
-static inline void wait_for_cmd_done(int cmd_ioaddr)
+static inline void wait_for_cmd_done(long cmd_ioaddr)
X {
- short wait = 100;
- do ;
- while(inb(cmd_ioaddr) && --wait >= 0);
+ int wait = 100;
+ do ;
+ while(inb(cmd_ioaddr) && --wait >= 0);
X }


X
X /* Operational parameter that usually are not changed. */

@@ -306,17 +315,24 @@
X u16 size;
X };
X
-/* Elements of the RxFD.status word. */
-#define RX_COMPLETE 0x8000
+/* Selected elements of the Tx/RxFD.status word. */
+enum RxFD_bits {
+ RxComplete=0x8000, RxOK=0x2000,
+ RxErrCRC=0x0800, RxErrAlign=0x0400, RxErrTooBig=0x0200, RxErrSymbol=0x0010,
+ RxEth2Type=0x0020, RxNoMatch=0x0004, RxNoIAMatch=0x0002,
+ StatusComplete=0x8000,
+};
X
X struct TxFD { /* Transmit frame descriptor set. */
X s32 status;
X u32 link; /* void * */
X u32 tx_desc_addr; /* Always points to the tx_buf_addr element. */
X s32 count; /* # of TBD (=1), Tx start thresh., etc. */
- /* This constitutes a single "TBD" entry -- we only use one. */
- u32 tx_buf_addr; /* void *, frame to be transmitted. */
- s32 tx_buf_size; /* Length of Tx frame. */
+ /* This constitutes two "TBD" entries -- we only use one. */
+ u32 tx_buf_addr0; /* void *, frame to be transmitted. */
+ s32 tx_buf_size0; /* Length of Tx frame. */
+ u32 tx_buf_addr1; /* void *, frame to be transmitted. */
+ s32 tx_buf_size1; /* Length of Tx frame. */
X };
X
X /* Elements of the dump_statistics block. This block must be lword aligned. */
@@ -358,10 +374,9 @@
X long last_rx_time; /* Last Rx, in jiffies, to handle Rx hang. */


X unsigned int cur_rx, cur_tx; /* The next free ring entry */
X unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */

- struct descriptor config_cmd; /* A configure command, with header... */
- u8 config_cmd_data[22]; /* .. and setup parameters. */
X int mc_setup_frm_len; /* The length of an allocated.. */
X struct descriptor *mc_setup_frm; /* ..multicast setup frame. */
+ int mc_setup_busy; /* Avoid double-use of setup frame. */
X int in_interrupt; /* Word-aligned dev->interrupt */
X char rx_mode; /* Current PROMISC/ALLMULTI setting. */
X unsigned int tx_full:1; /* The Tx queue is full. */
@@ -376,11 +391,16 @@
X /* The parameters for a CmdConfigure operation.
X There are so many options that it would be difficult to document each bit.
X We mostly use the default or recommended settings. */
-const char basic_config_cmd[22] = {
+const char i82557_config_cmd[22] = {
X 22, 0x08, 0, 0, 0, 0x80, 0x32, 0x03, 1, /* 1=Use MII 0=Use AUI */
X 0, 0x2E, 0, 0x60, 0,
X 0xf2, 0x48, 0, 0x40, 0xf2, 0x80, /* 0x40=Force full-duplex */
X 0x3f, 0x05, };
+const char i82558_config_cmd[22] = {
+ 22, 0x08, 0, 1, 0, 0x80, 0x22, 0x03, 1, /* 1=Use MII 0=Use AUI */
+ 0, 0x2E, 0, 0x60, 0x08, 0x88,
+ 0x68, 0, 0x40, 0xf2, 0xBD, /* 0xBD->0xFD=Force full-duplex */
+ 0x31, 0x05, };
X
X /* PHY media interface chips. */
X static const char *phys[] = {
@@ -392,12 +412,12 @@
X S80C24, I82555, DP83840A=10, };
X static const char is_mii[] = { 0, 1, 1, 0, 1, 1, 0, 1 };
X
-static void speedo_found1(struct device *dev, int ioaddr, int irq,
+static void speedo_found1(struct device *dev, long ioaddr, int irq,
X int card_idx);
X
-static int read_eeprom(int ioaddr, int location);
-static int mdio_read(int ioaddr, int phy_id, int location);
-static int mdio_write(int ioaddr, int phy_id, int location, int value);
+static int read_eeprom(long ioaddr, int location, int addr_len);
+static int mdio_read(long ioaddr, int phy_id, int location);
+static int mdio_write(long ioaddr, int phy_id, int location, int value);
X static int speedo_open(struct device *dev);
X static void speedo_timer(unsigned long data);
X static void speedo_init_rx_ring(struct device *dev);
@@ -420,68 +440,91 @@
X static int debug = -1; /* The debug level */
X #endif
X
+#ifdef honor_default_port
+/* Optional driver feature to allow forcing the transceiver setting.
+ Not recommended. */
+static int mii_ctrl[8] = { 0x3300, 0x3100, 0x0000, 0x0100,
+ 0x2000, 0x2100, 0x0400, 0x3100};
+#endif
+
X /* A list of all installed Speedo devices, for removing the driver module. */
X static struct device *root_speedo_dev = NULL;
X
X int eepro100_init(struct device *dev)
X {
X int cards_found = 0;


+ static int pci_index = 0;

X
- if (pcibios_present()) {
- static int pci_index = 0;
- for (; pci_index < 8; pci_index++) {
- unsigned char pci_bus, pci_device_fn, pci_irq_line, pci_latency;
- int pci_ioaddr;
-
- unsigned short pci_command, new_command;
-
- if (pcibios_find_device(PCI_VENDOR_ID_INTEL,
- PCI_DEVICE_ID_INTEL_82557,
- pci_index, &pci_bus,
- &pci_device_fn))
- break;
+ if (! pcibios_present())
+ return cards_found;
+
+ for (; pci_index < 8; pci_index++) {
+ unsigned char pci_bus, pci_device_fn, pci_latency;
+ long ioaddr;
+ int irq;
+
+ u16 pci_command, new_command;
+
+ if (pcibios_find_device(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_82557,
+ pci_index, &pci_bus,
+ &pci_device_fn))
+ break;
+#if LINUX_VERSION_CODE >= 0x20155 || PCI_SUPPORT_1
+ {
+ struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn);
+ ioaddr = pdev->base_address[1]; /* Use [0] to mem-map */
+ irq = pdev->irq;
+ }
+#else
+ {
+ u32 pci_ioaddr;
+ u8 pci_irq_line;
X pcibios_read_config_byte(pci_bus, pci_device_fn,
X PCI_INTERRUPT_LINE, &pci_irq_line);
X /* Note: BASE_ADDRESS_0 is for memory-mapping the registers. */
X pcibios_read_config_dword(pci_bus, pci_device_fn,
X PCI_BASE_ADDRESS_1, &pci_ioaddr);


- /* Remove I/O space marker in bit 0. */

- pci_ioaddr &= ~3;
- if (speedo_debug > 2)
- printk("Found Intel i82557 PCI Speedo at I/O %#x, IRQ %d.\n",
- (int)pci_ioaddr, pci_irq_line);
-
- /* Get and check the bus-master and latency values. */


- pcibios_read_config_word(pci_bus, pci_device_fn,
- PCI_COMMAND, &pci_command);

- new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO;
- if (pci_command != new_command) {


- printk(KERN_INFO " The PCI BIOS has not enabled this"
- " device! Updating PCI command %4.4x->%4.4x.\n",
- pci_command, new_command);

- pcibios_write_config_word(pci_bus, pci_device_fn,
- PCI_COMMAND, new_command);
- }
- pcibios_read_config_byte(pci_bus, pci_device_fn,
- PCI_LATENCY_TIMER, &pci_latency);
- if (pci_latency < 32) {
- printk(" PCI latency timer (CFLT) is unreasonably low at %d."
- " Setting to 32 clocks.\n", pci_latency);
- pcibios_write_config_byte(pci_bus, pci_device_fn,
- PCI_LATENCY_TIMER, 32);
- } else if (speedo_debug > 1)
- printk(" PCI latency timer (CFLT) is %#x.\n", pci_latency);
-
- speedo_found1(dev, pci_ioaddr, pci_irq_line, cards_found);
- dev = NULL;
- cards_found++;
+ ioaddr = pci_ioaddr;
+ irq = pci_irq_line;
+ }
+#endif
+ /* Remove I/O space marker in bit 0. */
+ ioaddr &= ~3;
+ if (speedo_debug > 2)
+ printk("Found Intel i82557 PCI Speedo at I/O %#lx, IRQ %d.\n",
+ ioaddr, irq);
+
+ /* Get and check the bus-master and latency values. */


+ pcibios_read_config_word(pci_bus, pci_device_fn,
+ PCI_COMMAND, &pci_command);

+ new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO;
+ if (pci_command != new_command) {
+ printk(KERN_INFO " The PCI BIOS has not enabled this"
+ " device! Updating PCI command %4.4x->%4.4x.\n",
+ pci_command, new_command);
+ pcibios_write_config_word(pci_bus, pci_device_fn,
+ PCI_COMMAND, new_command);
X }
+ pcibios_read_config_byte(pci_bus, pci_device_fn,
+ PCI_LATENCY_TIMER, &pci_latency);
+ if (pci_latency < 32) {
+ printk(" PCI latency timer (CFLT) is unreasonably low at %d."
+ " Setting to 32 clocks.\n", pci_latency);
+ pcibios_write_config_byte(pci_bus, pci_device_fn,
+ PCI_LATENCY_TIMER, 32);
+ } else if (speedo_debug > 1)
+ printk(" PCI latency timer (CFLT) is %#x.\n", pci_latency);
+
+ speedo_found1(dev, ioaddr, irq, cards_found);
+ dev = NULL;
+ cards_found++;
X }
X
X return cards_found;
X }
X
-static void speedo_found1(struct device *dev, int ioaddr, int irq,
+static void speedo_found1(struct device *dev, long ioaddr, int irq,
X int card_idx)
X {
X static int did_version = 0; /* Already printed version info. */


@@ -495,7 +538,7 @@
X

X dev = init_etherdev(dev, sizeof(struct speedo_private));
X
- if (dev->mem_start > 0)
+ if (dev->mem_start > 0)
X option = dev->mem_start;
X else if (card_idx >= 0 && options[card_idx] >= 0)
X option = options[card_idx];
@@ -508,8 +551,10 @@
X {
X u16 sum = 0;
X int j;
+ int addr_len = read_eeprom(ioaddr, 0, 6) == 0xffff ? 8 : 6;
+
X for (j = 0, i = 0; i < 0x40; i++) {
- u16 value = read_eeprom(ioaddr, i);
+ u16 value = read_eeprom(ioaddr, i, addr_len);
X eeprom[i] = value;
X sum += value;
X if (i < 3) {
@@ -535,7 +580,7 @@
X else
X product = "Intel EtherExpress Pro 10/100";
X
- printk(KERN_INFO "%s: %s at %#3x, ", dev->name, product, ioaddr);
+ printk(KERN_INFO "%s: %s at %#3lx, ", dev->name, product, ioaddr);
X
X for (i = 0; i < 5; i++)
X printk("%2.2X:", dev->dev_addr[i]);
@@ -666,22 +711,22 @@
X #define eeprom_delay(nanosec) udelay(1);
X
X /* The EEPROM commands include the alway-set leading bit. */
-#define EE_WRITE_CMD (5 << 6)
-#define EE_READ_CMD (6 << 6)
-#define EE_ERASE_CMD (7 << 6)
+#define EE_WRITE_CMD (5 << addr_len)
+#define EE_READ_CMD (6 << addr_len)
+#define EE_ERASE_CMD (7 << addr_len)
X
-static int read_eeprom(int ioaddr, int location)
+static int read_eeprom(long ioaddr, int location, int addr_len)
X {
- int i;
X unsigned short retval = 0;
X int ee_addr = ioaddr + SCBeeprom;
X int read_cmd = location | EE_READ_CMD;
+ int i;
X
X outw(EE_ENB & ~EE_CS, ee_addr);
X outw(EE_ENB, ee_addr);
X
X /* Shift the read command bits out. */
- for (i = 10; i >= 0; i--) {
+ for (i = 12; i >= 0; i--) {
X short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
X outw(EE_ENB | dataval, ee_addr);
X eeprom_delay(100);
@@ -703,7 +748,7 @@
X return retval;


X }
X
-static int mdio_read(int ioaddr, int phy_id, int location)
+static int mdio_read(long ioaddr, int phy_id, int location)
X {

X int val, boguscnt = 64*10; /* <64 usec. to complete, typ 27 ticks */
X outl(0x08000000 | (location<<16) | (phy_id<<21), ioaddr + SCBCtrlMDI);
@@ -716,7 +761,7 @@
X return val & 0xffff;
X }
X
-static int mdio_write(int ioaddr, int phy_id, int location, int value)
+static int mdio_write(long ioaddr, int phy_id, int location, int value)
X {
X int val, boguscnt = 64*10; /* <64 usec. to complete, typ 27 ticks */
X outl(0x04000000 | (location<<16) | (phy_id<<21) | value,
@@ -735,7 +780,7 @@
X speedo_open(struct device *dev)
X {
X struct speedo_private *sp = (struct speedo_private *)dev->priv;


- int ioaddr = dev->base_addr;
+ long ioaddr = dev->base_addr;
X

X #ifdef notdef
X /* We could reset the chip, but should not need to. */
@@ -752,6 +797,22 @@
X
X MOD_INC_USE_COUNT;
X
+ /* Retrigger negotiation to reset previous errors. */
+ if ((sp->phy[0] & 0x8000) == 0) {
+ int phy_addr = sp->phy[0] & 0x1f ;
+ /* Use 0x3300 for restarting NWay, other values to force xcvr:
+ 0x0000 10-HD
+ 0x0100 10-FD
+ 0x2000 100-HD
+ 0x2100 100-FD
+ */
+#ifdef honor_default_port
+ mdio_write(ioaddr, phy_addr, 0, mii_ctrl[dev->default_port & 7]);
+#else
+ mdio_write(ioaddr, phy_addr, 0, 0x3300);
+#endif
+ }
+
X /* Load the statistics block address. */
X wait_for_cmd_done(ioaddr + SCBCmd);
X outl(virt_to_bus(&sp->lstats), ioaddr + SCBPointer);
@@ -805,6 +866,7 @@
X /* Setup the chip and configure the multicast list. */
X sp->mc_setup_frm = NULL;
X sp->mc_setup_frm_len = 0;
+ sp->mc_setup_busy = 0;
X sp->rx_mode = -1; /* Invalid -> always reset the mode. */
X set_rx_mode(dev);
X
@@ -825,6 +887,9 @@
X
X wait_for_cmd_done(ioaddr + SCBCmd);
X outw(CU_DUMPSTATS, ioaddr + SCBCmd);
+ /* No need to wait for the command unit to accept here. */
+ if ((sp->phy[0] & 0x8000) == 0)
+ mdio_read(ioaddr, sp->phy[0] & 0x1f, 0);


X return 0;
X }
X

@@ -833,24 +898,22 @@
X {


X struct device *dev = (struct device *)data;

X struct speedo_private *sp = (struct speedo_private *)dev->priv;
- int tickssofar = jiffies - sp->last_rx_time;
X
X if (speedo_debug > 3) {


- int ioaddr = dev->base_addr;

- printk(KERN_DEBUG "%s: Media selection tick, status %4.4x.\n",


+ long ioaddr = dev->base_addr;

+ printk(KERN_DEBUG "%s: Media control tick, status %4.4x.\n",
X dev->name, inw(ioaddr + SCBStatus));
X }
- if (sp->rx_bug) {
- if (tickssofar > 2*HZ || sp->rx_mode < 0) {
- /* We haven't received a packet in a Long Time. We might have been
- bitten by the receiver hang bug. This can be cleared by sending
- a set multicast list command. */
- set_rx_mode(dev);
- }
- /* We must continue to monitor the media. */
- sp->timer.expires = RUN_AT(2*HZ); /* 2.0 sec. */
- add_timer(&sp->timer);
+ if (sp->rx_mode < 0 ||
+ (sp->rx_bug && jiffies - sp->last_rx_time > 2*HZ)) {
+ /* We haven't received a packet in a Long Time. We might have been
+ bitten by the receiver hang bug. This can be cleared by sending
+ a set multicast list command. */
+ set_rx_mode(dev);
X }
+ /* We must continue to monitor the media. */
+ sp->timer.expires = RUN_AT(2*HZ); /* 2.0 sec. */
+ add_timer(&sp->timer);
X }
X
X /* Initialize the Rx and Tx rings, along with various 'dev' bits. */
@@ -862,30 +925,32 @@
X int i;
X
X sp->cur_rx = 0;
- sp->dirty_rx = RX_RING_SIZE - 1;
X

X for (i = 0; i < RX_RING_SIZE; i++) {
X struct sk_buff *skb;

- skb = alloc_skb(PKT_BUF_SZ, GFP_ATOMIC);
+ skb = dev_alloc_skb(PKT_BUF_SZ + sizeof(struct RxFD));
X sp->rx_skbuff[i] = skb;


X if (skb == NULL)

- break; /* Bad news! */
+ break; /* OK. Just initially short of Rx bufs. */


X skb->dev = dev; /* Mark as being used by this device. */

-
X rxf = (struct RxFD *)skb->tail;
- skb_reserve(skb, sizeof(struct RxFD));
X sp->rx_ringp[i] = rxf;
+ skb_reserve(skb, sizeof(struct RxFD));
X if (last_rxf)
X last_rxf->link = virt_to_bus(rxf);
X last_rxf = rxf;
X rxf->status = 0x00000001; /* '1' is flag value only. */
X rxf->link = 0; /* None yet. */
X /* This field unused by i82557, we use it as a consistency check. */
+#ifdef final_version
+ rxf->rx_buf_addr = 0xffffffff;
+#else
X rxf->rx_buf_addr = virt_to_bus(skb->tail);
-
+#endif
X rxf->count = 0;
X rxf->size = PKT_BUF_SZ;
X }
+ sp->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
X /* Mark the last entry as end-of-list. */
X last_rxf->status = 0xC0000002; /* '2' is flag value only. */
X sp->last_rxf = last_rxf;
@@ -894,20 +959,21 @@
X static void speedo_tx_timeout(struct device *dev)
X {
X struct speedo_private *sp = (struct speedo_private *)dev->priv;


- int ioaddr = dev->base_addr;
+ long ioaddr = dev->base_addr;
X

X printk(KERN_WARNING "%s: Transmit timed out: status %4.4x "
- "command %4.4x.\n",
- dev->name, inw(ioaddr + SCBStatus), inw(ioaddr + SCBCmd));
-
+ " %4.4x at %d/%d command %8.8x.\n",
+ dev->name, inw(ioaddr + SCBStatus), inw(ioaddr + SCBCmd),
+ sp->dirty_tx, sp->cur_tx,
+ sp->tx_ring[sp->dirty_tx % TX_RING_SIZE].status);
X if ((inw(ioaddr + SCBStatus) & 0x00C0) != 0x0080) {
- printk(KERN_WARNING "%s: Trying to restart the transmitter...\n",
- dev->name);
- outl(virt_to_bus(&sp->tx_ring[sp->dirty_tx % TX_RING_SIZE]),
- ioaddr + SCBPointer);
- outw(CU_START, ioaddr + SCBCmd);
+ printk(KERN_WARNING "%s: Trying to restart the transmitter...\n",
+ dev->name);
+ outl(virt_to_bus(&sp->tx_ring[sp->dirty_tx % TX_RING_SIZE]),
+ ioaddr + SCBPointer);
+ outw(CU_START, ioaddr + SCBCmd);
X } else {
- outw(DRVR_INT, ioaddr + SCBCmd);
+ outw(DRVR_INT, ioaddr + SCBCmd);
X }
X /* Reset the MII transceiver, suggested by Fred Young @ scalable.com. */
X if ((sp->phy[0] & 0x8000) == 0) {
@@ -916,6 +982,9 @@
X mdio_write(ioaddr, phy_addr, 1, 0x0000);
X mdio_write(ioaddr, phy_addr, 4, 0x0000);
X mdio_write(ioaddr, phy_addr, 0, 0x8000);
+#ifdef honor_default_port
+ mdio_write(ioaddr, phy_addr, 0, mii_ctrl[dev->default_port & 7]);
+#endif
X }
X sp->stats.tx_errors++;


X dev->trans_start = jiffies;

@@ -926,7 +995,7 @@
X speedo_start_xmit(struct sk_buff *skb, struct device *dev)
X {
X struct speedo_private *sp = (struct speedo_private *)dev->priv;


- int ioaddr = dev->base_addr;
+ long ioaddr = dev->base_addr;

X int entry;
X
X /* Block a timer-based transmit from overlapping. This could better be
@@ -963,22 +1032,22 @@
X sp->tx_ring[entry].link =
X virt_to_bus(&sp->tx_ring[sp->cur_tx % TX_RING_SIZE]);
X sp->tx_ring[entry].tx_desc_addr =
- virt_to_bus(&sp->tx_ring[entry].tx_buf_addr);
+ virt_to_bus(&sp->tx_ring[entry].tx_buf_addr0);
X /* The data region is always in one buffer descriptor, Tx FIFO
X threshold of 256. */
X sp->tx_ring[entry].count = 0x01208000;
- sp->tx_ring[entry].tx_buf_addr = virt_to_bus(skb->data);
- sp->tx_ring[entry].tx_buf_size = skb->len;
+ sp->tx_ring[entry].tx_buf_addr0 = virt_to_bus(skb->data);
+ sp->tx_ring[entry].tx_buf_size0 = skb->len;
X /* Todo: perhaps leave the interrupt bit set if the Tx queue is more
X than half full. Argument against: we should be receiving packets
X and scavenging the queue. Argument for: if so, it shouldn't
X matter. */
X sp->last_cmd->command &= ~(CmdSuspend | CmdIntr);
X sp->last_cmd = (struct descriptor *)&sp->tx_ring[entry];
+ restore_flags(flags);
X /* Trigger the command unit resume. */
X wait_for_cmd_done(ioaddr + SCBCmd);
X outw(CU_RESUME, ioaddr + SCBCmd);
- restore_flags(flags);
X }
X
X /* Leave room for set_rx_mode() to fill two entries. */
@@ -998,7 +1067,7 @@
X {
X struct device *dev = (struct device *)dev_instance;
X struct speedo_private *sp;
- int ioaddr, boguscnt = max_interrupt_work;
+ long ioaddr, boguscnt = max_interrupt_work;
X unsigned short status;
X
X #ifndef final_version
@@ -1015,6 +1084,7 @@
X if (test_and_set_bit(0, (void*)&sp->in_interrupt)) {
X printk(KERN_ERR"%s: SMP simultaneous entry of an interrupt handler.\n",
X dev->name);
+ sp->in_interrupt = 0; /* Avoid halting machine. */
X return;


X }
X dev->interrupt = 1;

@@ -1058,14 +1128,15 @@
X if (speedo_debug > 5)
X printk(KERN_DEBUG " scavenge candidate %d status %4.4x.\n",
X entry, status);
- if ((status & 0x8000) == 0)
+ if ((status & StatusComplete) == 0)
X break; /* It still hasn't been processed. */
X /* Free the original skb. */
X if (sp->tx_skbuff[entry]) {
X sp->stats.tx_packets++; /* Count only user packets. */
- dev_kfree_skb(sp->tx_skbuff[entry], FREE_WRITE);
+ dev_free_skb(sp->tx_skbuff[entry]);
X sp->tx_skbuff[entry] = 0;
- }
+ } else if ((sp->tx_ring[entry].status&0x70000) == CmdNOp << 16)
+ sp->mc_setup_busy = 0;
X dirty_tx++;
X }
X
@@ -1113,108 +1184,104 @@
X struct speedo_private *sp = (struct speedo_private *)dev->priv;
X int entry = sp->cur_rx % RX_RING_SIZE;
X int status;
+ int rx_work_limit = sp->dirty_rx + RX_RING_SIZE - sp->cur_rx;
X
X if (speedo_debug > 4)
X printk(KERN_DEBUG " In speedo_rx().\n");
X /* If we own the next entry, it's a new packet. Send it up. */
- while ((status = sp->rx_ringp[entry]->status) & RX_COMPLETE) {
+ while (sp->rx_ringp[entry] != NULL &&
+ (status = sp->rx_ringp[entry]->status) & RxComplete) {
X

+ if (--rx_work_limit < 0)
+ break;

X if (speedo_debug > 4)
X printk(KERN_DEBUG " speedo_rx() status %8.8x len %d.\n", status,
X sp->rx_ringp[entry]->count & 0x3fff);
- if (status & 0x0200) {
- printk(KERN_ERR "%s: Ethernet frame overran the Rx buffer, "
- "status %8.8x!\n", dev->name, status);
- } else if ( ! (status & 0x2000)) {
- /* There was a fatal error. This *should* be impossible. */
- sp->stats.rx_errors++;
- printk(KERN_ERR "%s: Anomalous event in speedo_rx(), status %8.8x.\n",
- dev->name, status);
+ if ((status & (RxErrTooBig|RxOK)) != RxOK) {
+ if (status & RxErrTooBig)
+ printk(KERN_ERR "%s: Ethernet frame overran the Rx buffer, "
+ "status %8.8x!\n", dev->name, status);
+ else if ( ! (status & 0x2000)) {
+ /* There was a fatal error. This *should* be impossible. */
+ sp->stats.rx_errors++;
+ printk(KERN_ERR "%s: Anomalous event in speedo_rx(), "
+ "status %8.8x.\n",
+ dev->name, status);
+ }
X } else {
- /* Malloc up new buffer, compatible with net-2e. */
X int pkt_len = sp->rx_ringp[entry]->count & 0x3fff;
X struct sk_buff *skb;
- int rx_in_place = 0;
X

X /* Check if the packet is long enough to just accept without
X copying to a properly sized skbuff. */

- if (pkt_len > rx_copybreak) {
- struct sk_buff *newskb;
- char *temp;
-
- /* Pass up the skb already on the Rx ring. */
- skb = sp->rx_skbuff[entry];
- temp = skb_put(skb, pkt_len);
- if (bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr) != temp)
- printk(KERN_ERR "%s: Warning -- the skbuff addresses do not match"
- " in speedo_rx: %8.8x vs. %p / %p.\n", dev->name,
- sp->rx_ringp[entry]->rx_buf_addr, skb->head, temp);
- /* Get a fresh skbuff to replace the filled one. */
- newskb = dev_alloc_skb(PKT_BUF_SZ + sizeof(struct RxFD));
-
- if (newskb) {
- struct RxFD *rxf;
- rx_in_place = 1;
- sp->rx_skbuff[entry] = newskb;
- newskb->dev = dev;
- rxf = sp->rx_ringp[entry] = (struct RxFD *)newskb->tail;
- skb_reserve(newskb, sizeof(struct RxFD));
- /* Unused by i82557, consistency check only. */
- rxf->rx_buf_addr = virt_to_bus(newskb->tail);
- rxf->status = 0x00000001;
- } else /* No memory, drop the packet. */
- skb = 0;
- } else
- skb = dev_alloc_skb(pkt_len + 2);


- if (skb == NULL) {

- int i;
- printk(KERN_ERR "%s: Memory squeeze, deferring packet.\n", dev->name);
- /* Check that at least two ring entries are free.
- If not, free one and mark stats->rx_dropped++. */
- /* ToDo: This is not correct!!!! We should count the number
- of linked-in Rx buffer to very that we have at least two
- remaining. */
- for (i = 0; i < RX_RING_SIZE; i++)
- if (! ((sp->rx_ringp[(entry+i) % RX_RING_SIZE]->status)
- & RX_COMPLETE))
- break;
-
- if (i > RX_RING_SIZE -2) {
- sp->stats.rx_dropped++;
- sp->rx_ringp[entry]->status = 0;
- sp->cur_rx++;
- }
- break;
- }
- skb->dev = dev;
- if (! rx_in_place) {
- skb_reserve(skb, 2); /* 16 byte align the data fields */
-#if defined(__i386) && notyet
+ if (pkt_len < rx_copybreak


+ && (skb = dev_alloc_skb(pkt_len + 2)) != 0) {

+ skb->dev = dev;
+ skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
+ /* 'skb_put()' points to the start of sk_buff data area. */
+#if 1 || USE_IP_CSUM
X /* Packet is in one chunk -- we can copy + cksum. */
- eth_io_copy_and_sum(skb, bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr),
- pkt_len, 0);
+ eth_copy_and_sum(skb,
+ bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr),
+ pkt_len, 0);
+ skb_put(skb, pkt_len);
X #else
X memcpy(skb_put(skb, pkt_len),
X bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr), pkt_len);
X #endif
+ } else {
+ void *temp;
+ /* Pass up the already-filled skbuff. */
+ skb = sp->rx_skbuff[entry];
+ if (skb == NULL) {
+ printk(KERN_ERR "%s: Inconsistent Rx descriptor chain.\n",
+ dev->name);
+ break;
+ }
+ sp->rx_skbuff[entry] = NULL;
+ temp = skb_put(skb, pkt_len);
+ if (bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr) != temp)
+ printk(KERN_ERR "%s: Rx consistency error -- the skbuff "
+ "addresses do not match in speedo_rx: %p vs. %p "
+ "/ %p.\n", dev->name,
+ bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr),
+ skb->head, temp);
+ sp->rx_ringp[entry] = NULL;
X }


X skb->protocol = eth_type_trans(skb, dev);

X netif_rx(skb);
X sp->stats.rx_packets++;
X }
+ entry = (++sp->cur_rx) % RX_RING_SIZE;
+ }
X
- /* ToDo: This is better than before, but should be checked. */
- {
- struct RxFD *rxf = sp->rx_ringp[entry];
- rxf->status = 0xC0000003; /* '3' for verification only */
- rxf->link = 0; /* None yet. */
- rxf->count = 0;
- rxf->size = PKT_BUF_SZ;
- sp->last_rxf->link = virt_to_bus(rxf);
- sp->last_rxf->status &= ~0xC0000000;
- sp->last_rxf = rxf;
- entry = (++sp->cur_rx) % RX_RING_SIZE;
+ /* Refill the Rx ring buffers. */
+ for (; sp->dirty_rx < sp->cur_rx; sp->dirty_rx++) {
+ struct RxFD *rxf;
+ entry = sp->dirty_rx % RX_RING_SIZE;
+ if (sp->rx_skbuff[entry] == NULL) {
+ struct sk_buff *skb;
+ /* Get a fresh skbuff to replace the consumed one. */
+ skb = dev_alloc_skb(PKT_BUF_SZ + sizeof(struct RxFD));
+ sp->rx_skbuff[entry] = skb;
+ if (skb == NULL) {
+ sp->rx_ringp[entry] = NULL;
+ break; /* Better luck next time! */
+ }
+ rxf = sp->rx_ringp[entry] = (struct RxFD *)skb->tail;
+ skb->dev = dev;
+ skb_reserve(skb, sizeof(struct RxFD));
+ rxf->rx_buf_addr = virt_to_bus(skb->tail);
+ } else {
+ rxf = sp->rx_ringp[entry];
X }
+ rxf->status = 0xC0000001; /* '1' for driver use only. */
+ rxf->link = 0; /* None yet. */
+ rxf->count = 0;
+ rxf->size = PKT_BUF_SZ;
+ sp->last_rxf->link = virt_to_bus(rxf);
+ sp->last_rxf->status &= ~0xC0000000;
+ sp->last_rxf = rxf;
X }
X
X sp->last_rx_time = jiffies;
@@ -1224,7 +1291,7 @@
X static int
X speedo_close(struct device *dev)


X {
- int ioaddr = dev->base_addr;
+ long ioaddr = dev->base_addr;

X struct speedo_private *sp = (struct speedo_private *)dev->priv;
X int i;
X
@@ -1250,7 +1317,7 @@
X sp->rx_skbuff[i] = 0;
X /* Clear the Rx descriptors. */
X if (skb)
- dev_kfree_skb(skb, FREE_WRITE);
+ dev_free_skb(skb);
X }
X

X for (i = 0; i < TX_RING_SIZE; i++) {

@@ -1258,7 +1325,7 @@
X sp->tx_skbuff[i] = 0;
X /* Clear the Tx descriptors. */
X if (skb)
- dev_kfree_skb(skb, FREE_WRITE);
+ dev_free_skb(skb);
X }
X if (sp->mc_setup_frm) {
X kfree(sp->mc_setup_frm);
@@ -1303,7 +1370,7 @@
X speedo_get_stats(struct device *dev)
X {
X struct speedo_private *sp = (struct speedo_private *)dev->priv;


- int ioaddr = dev->base_addr;
+ long ioaddr = dev->base_addr;
X

X if (sp->lstats.done_marker == 0xA007) { /* Previous dump finished */
X sp->stats.tx_aborted_errors += sp->lstats.tx_coll16_errs;
@@ -1329,7 +1396,7 @@
X static int speedo_ioctl(struct device *dev, struct ifreq *rq, int cmd)
X {
X struct speedo_private *sp = (struct speedo_private *)dev->priv;


- int ioaddr = dev->base_addr;
+ long ioaddr = dev->base_addr;
X u16 *data = (u16 *)&rq->ifr_data;

X int phy = sp->phy[0] & 0x1f;
X
@@ -1362,7 +1429,8 @@
X set_rx_mode(struct device *dev)
X {
X struct speedo_private *sp = (struct speedo_private *)dev->priv;


- int ioaddr = dev->base_addr;
+ long ioaddr = dev->base_addr;

+ struct descriptor *last_cmd;
X char new_rx_mode;
X unsigned long flags;
X int entry, i;
@@ -1383,57 +1451,55 @@
X }
X
X if (new_rx_mode != sp->rx_mode) {
- /* We must change the configuration. Construct a CmdConfig frame. */
- memcpy(sp->config_cmd_data, basic_config_cmd,sizeof(basic_config_cmd));
- sp->config_cmd_data[1] = (txfifo << 4) | rxfifo;
- sp->config_cmd_data[4] = rxdmacount;
- sp->config_cmd_data[5] = txdmacount + 0x80;
- sp->config_cmd_data[15] = (new_rx_mode & 2) ? 0x49 : 0x48;
- sp->config_cmd_data[19] = sp->full_duplex ? 0xC0 : 0x80;
- sp->config_cmd_data[21] = (new_rx_mode & 1) ? 0x0D : 0x05;
- if (sp->phy[0] & 0x8000) { /* Use the AUI port instead. */
- sp->config_cmd_data[15] |= 0x80;
- sp->config_cmd_data[8] = 0;
- }
- save_flags(flags);
+ u8 *config_cmd_data;
+
+ save_flags(flags); /* Lock to protect sp->cur_tx. */
X cli();
- /* Fill the "real" tx_ring frame with a no-op and point it to us. */
X entry = sp->cur_tx++ % TX_RING_SIZE;
- sp->tx_skbuff[entry] = 0; /* Nothing to free. */
- sp->tx_ring[entry].status = CmdNOp << 16;
- sp->tx_ring[entry].link = virt_to_bus(&sp->config_cmd);
- sp->config_cmd.status = 0;
- sp->config_cmd.command = CmdSuspend | CmdConfigure;
- sp->config_cmd.link =
- virt_to_bus(&(sp->tx_ring[sp->cur_tx % TX_RING_SIZE]));
- sp->last_cmd->command &= ~CmdSuspend;
- /* Immediately trigger the command unit resume. */
- wait_for_cmd_done(ioaddr + SCBCmd);
- outw(CU_RESUME, ioaddr + SCBCmd);
- sp->last_cmd = &sp->config_cmd;
+ last_cmd = sp->last_cmd;
+ sp->last_cmd = (struct descriptor *)&sp->tx_ring[entry];
X restore_flags(flags);
- if (speedo_debug > 5) {
- int i;
- printk(KERN_DEBUG " CmdConfig frame in entry %d.\n", entry);
- for(i = 0; i < 32; i++)
- printk(" %2.2x", ((unsigned char *)&sp->config_cmd)[i]);
- printk(".\n");
+
+ sp->tx_skbuff[entry] = 0; /* Redundant. */
+ sp->tx_ring[entry].status = (CmdSuspend | CmdConfigure) << 16;
+ sp->tx_ring[entry].link =
+ virt_to_bus(&sp->tx_ring[(entry + 1) % TX_RING_SIZE]);
+ config_cmd_data = (void *)&sp->tx_ring[entry].tx_desc_addr;
+ /* Construct a full CmdConfig frame. */
+ memcpy(config_cmd_data, i82558_config_cmd, sizeof(i82558_config_cmd));
+ config_cmd_data[1] = (txfifo << 4) | rxfifo;
+ config_cmd_data[4] = rxdmacount;
+ config_cmd_data[5] = txdmacount + 0x80;
+ config_cmd_data[15] |= (new_rx_mode & 2) ? 1 : 0;
+ config_cmd_data[19] |= sp->full_duplex ? 0x40 : 0;
+ config_cmd_data[21] = (new_rx_mode & 1) ? 0x0D : 0x05;
+ if (sp->phy[0] & 0x8000) { /* Use the AUI port instead. */
+ config_cmd_data[15] |= 0x80;
+ config_cmd_data[8] = 0;
X }
+ /* Trigger the command unit resume. */
+ last_cmd->command &= ~CmdSuspend;
+ wait_for_cmd_done(ioaddr + SCBCmd);
+ outw(CU_RESUME, ioaddr + SCBCmd);
X }
X
- if (new_rx_mode == 0 && dev->mc_count < 3) {
- /* The simple case of 0-2 multicast list entries occurs often, and
+ if (new_rx_mode == 0 && dev->mc_count < 4) {
+ /* The simple case of 0-3 multicast list entries occurs often, and
X fits within one tx_ring[] entry. */
- u16 *setup_params, *eaddrs;
X struct dev_mc_list *mclist;
+ u16 *setup_params, *eaddrs;
X
- save_flags(flags);
+ save_flags(flags); /* Lock to protect sp->cur_tx. */
X cli();
X entry = sp->cur_tx++ % TX_RING_SIZE;
+ last_cmd = sp->last_cmd;
+ sp->last_cmd = (struct descriptor *)&sp->tx_ring[entry];
+ restore_flags(flags);
+
X sp->tx_skbuff[entry] = 0;
X sp->tx_ring[entry].status = (CmdSuspend | CmdMulticastList) << 16;
X sp->tx_ring[entry].link =
- virt_to_bus(&sp->tx_ring[sp->cur_tx % TX_RING_SIZE]);
+ virt_to_bus(&sp->tx_ring[(entry + 1) % TX_RING_SIZE]);
X sp->tx_ring[entry].tx_desc_addr = 0; /* Really MC list count. */
X setup_params = (u16 *)&sp->tx_ring[entry].tx_desc_addr;
X *setup_params++ = dev->mc_count*6;
@@ -1446,36 +1512,39 @@
X *setup_params++ = *eaddrs++;
X }
X
- sp->last_cmd->command &= ~CmdSuspend;
+ last_cmd->command &= ~CmdSuspend;
X /* Immediately trigger the command unit resume. */
X wait_for_cmd_done(ioaddr + SCBCmd);
X outw(CU_RESUME, ioaddr + SCBCmd);
- sp->last_cmd = (struct descriptor *)&sp->tx_ring[entry];
- restore_flags(flags);
X } else if (new_rx_mode == 0) {
- /* This does not work correctly, but why not? */
X struct dev_mc_list *mclist;
- u16 *eaddrs;
+ u16 *setup_params, *eaddrs;
X struct descriptor *mc_setup_frm = sp->mc_setup_frm;
- u16 *setup_params;
X int i;
X
X if (sp->mc_setup_frm_len < 10 + dev->mc_count*6
X || sp->mc_setup_frm == NULL) {
- /* Allocate a new frame, 10bytes + addrs, with a few
- extra entries for growth. */
+ /* Allocate a full setup frame, 10bytes + <max addrs>. */
X if (sp->mc_setup_frm)
X kfree(sp->mc_setup_frm);
- sp->mc_setup_frm_len = 10 + dev->mc_count*6 + 24;
+ sp->mc_setup_busy = 0;
+ sp->mc_setup_frm_len = 10 + multicast_filter_limit*6;
X sp->mc_setup_frm = kmalloc(sp->mc_setup_frm_len, GFP_ATOMIC);
X if (sp->mc_setup_frm == NULL) {
- printk(KERN_ERR "%s: Failed to allocate a setup frame.\n", dev->name);
+ printk(KERN_ERR "%s: Failed to allocate a setup frame.\n",
+ dev->name);
X sp->rx_mode = -1; /* We failed, try again. */
X return;
X }
X }
+ /* If we are busy, someone might be quickly adding to the MC list.
+ Try again later when the list changes stop. */
+ if (sp->mc_setup_busy) {
+ sp->rx_mode = -1;
+ return;
+ }
X mc_setup_frm = sp->mc_setup_frm;
- /* Construct the new setup frame. */
+ /* Fill the setup frame. */
X if (speedo_debug > 1)
X printk(KERN_DEBUG "%s: Constructing a setup frame at %p, "
X "%d bytes.\n",
@@ -1483,7 +1552,7 @@
X mc_setup_frm->status = 0;
X mc_setup_frm->command = CmdSuspend | CmdIntr | CmdMulticastList;
X /* Link set below. */
- setup_params = (u16 *)mc_setup_frm->params;
+ setup_params = (u16 *)&mc_setup_frm->params;
X *setup_params++ = dev->mc_count*6;
X /* Fill in the multicast addresses. */
X for (i = 0, mclist = dev->mc_list; i < dev->mc_count;
@@ -1498,10 +1567,10 @@
X save_flags(flags);
X cli();
X entry = sp->cur_tx++ % TX_RING_SIZE;
-
- if (speedo_debug > 5)
- printk(" CmdMCSetup frame length %d in entry %d.\n",
- dev->mc_count, entry);
+ last_cmd = sp->last_cmd;
+ sp->last_cmd = mc_setup_frm;
+ sp->mc_setup_busy++;
+ restore_flags(flags);
X
X /* Change the command to a NoOp, pointing to the CmdMulti command. */
X sp->tx_skbuff[entry] = 0;
@@ -1510,17 +1579,15 @@
X
X /* Set the link in the setup frame. */
X mc_setup_frm->link =
- virt_to_bus(&(sp->tx_ring[sp->cur_tx % TX_RING_SIZE]));
+ virt_to_bus(&(sp->tx_ring[(entry+1) % TX_RING_SIZE]));
X
- sp->last_cmd->command &= ~CmdSuspend;
+ last_cmd->command &= ~CmdSuspend;
X /* Immediately trigger the command unit resume. */
X wait_for_cmd_done(ioaddr + SCBCmd);
X outw(CU_RESUME, ioaddr + SCBCmd);
- sp->last_cmd = mc_setup_frm;
- restore_flags(flags);
- if (speedo_debug > 1)
- printk(KERN_DEBUG "%s: Last command at %p is %4.4x.\n",
- dev->name, sp->last_cmd, sp->last_cmd->command);
+ if (speedo_debug > 5)
+ printk(" CmdMCSetup frame length %d in entry %d.\n",
+ dev->mc_count, entry);
X }
X
X sp->rx_mode = new_rx_mode;
diff -u --recursive --new-file v2.0.36/linux/drivers/net/epic100.c linux/drivers/net/epic100.c
--- v2.0.36/linux/drivers/net/epic100.c Sun Nov 15 21:51:46 1998
+++ linux/drivers/net/epic100.c Sun Jun 13 10:21:01 1999
@@ -1,6 +1,6 @@
X /* epic100.c: A SMC 83c170 EPIC/100 Fast Ethernet driver for Linux. */
X /*
- Written 1997-1998 by Donald Becker.
+ Written/copyright 1997-1998 by Donald Becker.
X
X This software may be used and distributed according to the terms
X of the GNU Public License, incorporated herein by reference.
@@ -10,15 +10,15 @@
X SMC EtherPower II 9432 PCI adapter, and several CardBus cards.
X
X The author may be reached as bec...@CESDIS.gsfc.nasa.gov, or C/O
- Center of Excellence in Space Data and Information Sciences
+ USRA Center of Excellence in Space Data and Information Sciences
X Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
X
- Support and updates available at
+ Information and updates available at
X http://cesdis.gsfc.nasa.gov/linux/drivers/epic100.html
X */
X
X static const char *version =
-"epic100.c:v1.03 8/7/98 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/epic100.html\n";
+"epic100.c:v1.04 8/23/98 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/epic100.html\n";
X
X /* A few user-configurable values. */
X
@@ -118,6 +118,7 @@
X /* The I/O extent. */
X #define EPIC_TOTAL_SIZE 0x100
X
+#define epic_debug debug
X static int epic_debug = 1;
X
X /*
@@ -155,7 +156,8 @@
X /* The rest of these values should never change. */
X
X static struct device *epic_probe1(int pci_bus, int pci_devfn,
- struct device *dev, int card_idx);
+ struct device *dev, long ioaddr, int irq,
+ int chip_id, int card_idx);
X
X enum pci_flags_bit {
X PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
@@ -166,9 +168,11 @@
X u16 vendor_id, device_id, device_id_mask, pci_flags;
X int io_size, min_latency;
X struct device *(*probe1)(int pci_bus, int pci_devfn, struct device *dev,
- int chip_idx);


+ long ioaddr, int irq, int chip_idx, int fnd_cnt);

X } chip_tbl[] = {
- {"SMSC EPIC/100", 0x10B8, 0x0005, 0x7fff,
+ {"SMSC EPIC/100 83c170", 0x10B8, 0x0005, 0x7fff,
+ PCI_USES_IO|PCI_USES_MASTER|PCI_ADDR0, EPIC_TOTAL_SIZE, 32, epic_probe1},
+ {"SMSC EPIC/C 83c175", 0x10B8, 0x0006, 0x7fff,
X PCI_USES_IO|PCI_USES_MASTER|PCI_ADDR0, EPIC_TOTAL_SIZE, 32, epic_probe1},
X {0,},
X };
@@ -276,7 +280,7 @@
X int epic100_probe(struct device *dev)
X {
X int cards_found = 0;
- int chip_idx;
+ int chip_idx, irq;
X u16 pci_command, new_command;


X unsigned char pci_bus, pci_device_fn;
X

@@ -298,6 +302,7 @@
X continue;
X pci_bus = pcidev->bus->number;
X pci_device_fn = pcidev->devfn;
+ irq = pcidev->irq;
X #else
X int pci_index;
X
@@ -305,6 +310,7 @@
X return -ENODEV;
X
X for (pci_index = 0; pci_index < 0xff; pci_index++) {
+ u8 pci_irq_line;
X u16 vendor, device;
X u32 pci_ioaddr;
X
@@ -327,8 +333,11 @@
X

X pcibios_read_config_dword(pci_bus, pci_device_fn,
X PCI_BASE_ADDRESS_0, &pci_ioaddr);

+ pcibios_read_config_byte(pci_bus, pci_device_fn,
+ PCI_INTERRUPT_LINE, &pci_irq_line);
X /* Remove I/O space marker in bit 0. */
X pci_ioaddr &= ~3;
+ irq = pci_irq_line;
X
X if (check_region(pci_ioaddr, chip_tbl[chip_idx].io_size))
X continue;
@@ -350,8 +359,8 @@


X PCI_COMMAND, new_command);
X }
X

- dev = chip_tbl[chip_idx].probe1(pci_bus, pci_device_fn,
- dev, cards_found);
+ dev = chip_tbl[chip_idx].probe1(pci_bus, pci_device_fn, dev, pci_ioaddr,
+ irq, chip_idx, cards_found);
X
X /* Check the latency timer. */
X if (dev) {
@@ -375,17 +384,12 @@
X }
X #endif /* not CARDBUS */
X
-static struct device *epic_probe1(int bus, int devfn, struct device *dev,
- int card_idx)
+static struct device *epic_probe1(int pci_bus, int pci_devfn,
+ struct device *dev, long ioaddr, int irq,
+ int chip_idx, int card_idx)
X {
- static int did_version = 0; /* Already printed version info. */
X struct epic_private *ep;
X int i, option = 0, duplex = 0;
- u16 chip_id;
- u32 ioaddr;
-
- if (epic_debug > 0 && did_version++ == 0)
- printk(KERN_INFO "%s", version);
X
X if (dev && dev->mem_start) {
X option = dev->mem_start;
@@ -399,26 +403,10 @@
X
X dev = init_etherdev(dev, 0);
X
- { /* Grrrr, badly consider interface change. */
-#if defined(PCI_SUPPORT_VER2)
- struct pci_dev *pdev = pci_find_slot(bus, devfn);
- ioaddr = pdev->base_address[0] & ~3;
- dev->irq = pdev->irq;
- chip_id = pdev->device;
-#else
- u8 irq;
- u32 ioaddr0;
- pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, &ioaddr0);
- pcibios_read_config_byte(bus, devfn, PCI_INTERRUPT_LINE, &irq);
- pcibios_read_config_word(bus, devfn, PCI_DEVICE_ID, &chip_id);
- ioaddr = ioaddr0 & ~3;


- dev->irq = irq;

-#endif
- }
-


X dev->base_addr = ioaddr;

- printk(KERN_INFO "%s: SMC EPIC/100 (chip ID %4.4x) at %#3x, IRQ %d, ",
- dev->name, chip_id, ioaddr, dev->irq);


+ dev->irq = irq;

+ printk(KERN_INFO "%s: SMC EPIC/100 at %#lx, IRQ %d, ",
+ dev->name, ioaddr, dev->irq);
X
X /* Bring the chip out of low-power mode. */
X outl(0x4200, ioaddr + GENCTL);
@@ -427,7 +415,7 @@
X
X /* Turn on the MII transceiver. */
X outl(0x12, ioaddr + MIICfg);
- if (chip_id == 6)
+ if (chip_idx == 1)
X outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL);
X outl(0x0200, ioaddr + GENCTL);
X
@@ -447,7 +435,7 @@


X }
X
X /* We do a request_region() to register /proc/ioports info. */

- request_region(ioaddr, EPIC_TOTAL_SIZE, "SMC EPIC/100");
+ request_region(ioaddr, EPIC_TOTAL_SIZE, dev->name);
X
X /* The data structures must be quadword aligned. */
X ep = kmalloc(sizeof(*ep), GFP_KERNEL | GFP_DMA);
@@ -457,9 +445,13 @@
X ep->next_module = root_epic_dev;
X root_epic_dev = dev;
X
- ep->pci_bus = bus;
- ep->pci_dev_fn = devfn;
- ep->chip_id = chip_id;
+ ep->pci_bus = pci_bus;
+ ep->pci_dev_fn = pci_devfn;
+#if defined(PCI_SUPPORT_VER2)
+ ep->chip_id = pci_find_slot(pci_bus, pci_devfn)->device;
+#else
+ ep->chip_id = chip_tbl[chip_idx].device_id;
+#endif
X
X /* Find the connected MII xcvrs.
X Doing this in open() would allow detecting external xcvrs later, but
@@ -545,7 +537,6 @@
X int read_cmd = location |
X (inl(ee_addr) & 0x40) ? EE_READ64_CMD : EE_READ256_CMD;
X
- printk("EEctrl is %x.\n", inl(ee_addr));
X outl(EE_ENB & ~EE_CS, ee_addr);
X outl(EE_ENB, ee_addr);
X
@@ -930,11 +921,9 @@
X static void epic_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
X {
X struct device *dev = (struct device *)dev_instance;
- struct epic_private *ep;
- int status, ioaddr, boguscnt = max_interrupt_work;
-
- ioaddr = dev->base_addr;
- ep = (struct epic_private *)dev->priv;
+ struct epic_private *ep = (struct epic_private *)dev->priv;


+ long ioaddr = dev->base_addr;

+ int status, boguscnt = max_interrupt_work;
X
X #if defined(__i386__)
X /* A lock to prevent simultaneous entry bug on Intel SMP machines. */
@@ -1340,12 +1329,18 @@


X
X if (loc->bus != LOC_PCI) return NULL;
X bus = loc->b.pci.bus; devfn = loc->b.pci.devfn;

- printk(KERN_INFO "epic_attach(bus %d, function %d)\n", bus, devfn);
+ printk(KERN_DEBUG "epic_attach(bus %d, function %d)\n", bus, devfn);


X pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, &io);
X pcibios_read_config_byte(bus, devfn, PCI_INTERRUPT_LINE, &irq);

X pcibios_read_config_word(bus, devfn, PCI_DEVICE_ID, &dev_id);

X io &= ~3;
- dev = epic_probe1(bus, devfn, NULL, -1);


+ if (io == 0 || irq == 0) {

+ printk(KERN_ERR "The EPIC/C CardBus Ethernet interface was not "


+ "assigned an %s.\n" KERN_ERR " It will not be activated.\n",
+ io == 0 ? "I/O address" : "IRQ");
+ return NULL;
+ }

+ dev = epic_probe1(bus, devfn, NULL, io, irq, 2, -1);


X if (dev) {
X dev_node_t *node = kmalloc(sizeof(dev_node_t), GFP_KERNEL);
X strcpy(node->dev_name, dev->name);

@@ -1410,14 +1405,10 @@
X
X #ifdef MODULE
X
-/* An additional parameter that may be passed in... */


-static int debug = -1;

-


-int
-init_module(void)
+int init_module(void)
X {
- if (debug >= 0)

- epic_debug = debug;
+ if (epic_debug)


+ printk(KERN_INFO "%s", version);
X

X #ifdef CARDBUS
X register_driver(&epic_ops);
@@ -1427,8 +1418,7 @@
X #endif
X }
X

-void
-cleanup_module(void)
+void cleanup_module(void)
X {
X struct device *next_dev;
X

@@ -1438,11 +1428,13 @@


X
X /* No need to check MOD_IN_USE, as sys_delete_module() checks. */

X while (root_epic_dev) {
- next_dev = ((struct epic_private *)root_epic_dev->priv)->next_module;
+ struct epic_private *ep = (struct epic_private *)root_epic_dev->priv;
+ next_dev = ep->next_module;
X unregister_netdev(root_epic_dev);
X release_region(root_epic_dev->base_addr, EPIC_TOTAL_SIZE);
X kfree(root_epic_dev);
X root_epic_dev = next_dev;
+ kfree(ep);
X }
X }
X
diff -u --recursive --new-file v2.0.36/linux/drivers/net/eql.c linux/drivers/net/eql.c
--- v2.0.36/linux/drivers/net/eql.c Mon Jul 13 13:46:29 1998
+++ linux/drivers/net/eql.c Sun Jun 13 10:21:01 1999
@@ -389,8 +389,8 @@
X
X eql_schedule_slaves (eql->queue);
X
- slave_dev = eql_best_slave_dev (eql->queue);
X slave = eql_best_slave (eql->queue);
+ slave_dev = slave ? slave->dev : 0;
X
X if ( slave_dev != 0 )
X {
@@ -426,9 +426,9 @@
X if (slave_dev->hard_header == NULL
X || slave_dev->hard_header(skb,slave_dev,
X ETH_P_IP,NULL,NULL,skb->len) >= 0) {
+ slave->bytes_queued += skb->len;
X dev_queue_xmit (skb, slave_dev, 1);
X eql->stats->tx_packets++;
- slave->bytes_queued += skb->len;
X /* dev_kfree_skb(skb, FREE_WRITE); */
X return 0;
X }
diff -u --recursive --new-file v2.0.36/linux/drivers/net/eth16i.c linux/drivers/net/eth16i.c
--- v2.0.36/linux/drivers/net/eth16i.c Sun Nov 15 21:51:46 1998
+++ linux/drivers/net/eth16i.c Sun Jun 13 10:21:01 1999
@@ -886,7 +886,7 @@
X creg[0] &= 0x0F; /* Mask collision cnr */
X creg[2] &= 0x7F; /* Mask DCLEN bit */
X
-#ifdef 0
+#if 0
X /*
X This was removed because the card was sometimes left to state
X from which it couldn't be find anymore. If there is need
diff -u --recursive --new-file v2.0.36/linux/drivers/net/lance.c linux/drivers/net/lance.c
--- v2.0.36/linux/drivers/net/lance.c Sun Nov 15 21:51:46 1998
+++ linux/drivers/net/lance.c Sun Jun 13 10:21:01 1999
@@ -334,14 +334,17 @@
X dev->base_addr = io[this_dev];
X dev->dma = dma[this_dev];
X dev->init = lance_probe;
+#if NO_AUTOPROBE_MODULE
X if (io[this_dev] == 0) {
X if (this_dev != 0) break; /* only complain once */
X printk(KERN_NOTICE "lance.c: Module autoprobing not allowed. Append \"io=0xNNN\" value(s).\n");
X return -EPERM;
X }
+#endif
X if (register_netdev(dev) != 0) {
- printk(KERN_WARNING "lance.c: No PCnet/LANCE card found (i/o = 0x%x).\n", io[this_dev]);
- if (found != 0) return 0; /* Got at least one. */
+ if (found != 0)
+ return 0; /* Got at least one. */
+ printk(KERN_WARNING "lance.c: No PCnet/LANCE card found\n");
X return -ENXIO;
X }
X found++;
@@ -350,8 +353,7 @@


X return 0;
X }
X

-void
-cleanup_module(void)
+void cleanup_module(void)
X {

X int this_dev;
X
@@ -390,15 +392,21 @@
X unsigned short pci_command;
X
X if (pcibios_find_device (PCI_VENDOR_ID_AMD,
- PCI_DEVICE_ID_AMD_LANCE, pci_index,
- &pci_bus, &pci_device_fn) != 0)
+ PCI_DEVICE_ID_AMD_LANCE, pci_index,
+ &pci_bus, &pci_device_fn) != 0)
X break;
X pcibios_read_config_byte(pci_bus, pci_device_fn,
- PCI_INTERRUPT_LINE, &pci_irq_line);
+ PCI_INTERRUPT_LINE, &pci_irq_line);
X pcibios_read_config_dword(pci_bus, pci_device_fn,
- PCI_BASE_ADDRESS_0, &pci_ioaddr);
+ PCI_BASE_ADDRESS_0, &pci_ioaddr);
X /* Remove I/O space marker in bit 0. */
X pci_ioaddr &= ~3;
+
+ /* Avoid already found cards from previous calls
+ */
+ if (check_region(pci_ioaddr, LANCE_TOTAL_SIZE))
+ continue;
+
X /* PCI Spec 2.1 states that it is either the driver or PCI card's
X * responsibility to set the PCI Master Enable Bit if needed.
X * (From Mark Stockton <ma...@schooner.sys.hou.compaq.com>)
diff -u --recursive --new-file v2.0.36/linux/drivers/net/ne.c linux/drivers/net/ne.c
--- v2.0.36/linux/drivers/net/ne.c Mon Jul 13 13:46:29 1998
+++ linux/drivers/net/ne.c Sun Jun 13 10:21:01 1999
@@ -43,6 +43,7 @@
X #include <linux/bios32.h>


X #include <asm/system.h>
X #include <asm/io.h>

+#include <linux/delay.h>
X
X #include <linux/netdevice.h>
X #include <linux/etherdevice.h>
@@ -97,6 +98,7 @@
X {"ET-100","ET-200", {0x00, 0x45, 0x54}}, /* YANG and YA clone */
X {"COMPEX","COMPEX16",{0x00,0x80,0x48}}, /* Broken ISA Compex cards */
X {"E-LAN100", "E-LAN200", {0x00, 0x00, 0x5d}}, /* Broken ne1000 clones */
+ {"PCM-4823", "PCM-4823", {0x00, 0xc0, 0x6c}}, /* Broken Advantech MoBo */
X {0,}
X };
X #endif
@@ -422,6 +424,7 @@
X outb_p(0x00, ioaddr + EN0_RCNTLO);
X outb_p(0x00, ioaddr + EN0_RCNTHI);


SHAR_EOF
true || echo 'restore of patch-2.0.37 failed'
fi

echo 'End of part 11'
echo 'File patch-2.0.37 is continued in part 12'
echo 12 > _shar_seq_.tmp

Thomas...@ciw.uni-karlsruhe.de

unread,
Jun 16, 1999, 3:00:00 AM6/16/99
to
Archive-name: v2.0/patch-2.0.37/part12

#!/bin/sh
# this is part 12 of a 45 - part archive


# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.0.37 continued
if test ! -r _shar_seq_.tmp; then
echo 'Please unpack part 1 first!'
exit 1
fi
(read Scheck

if test "$Scheck" != 12; then


echo Please unpack part "$Scheck" next!
exit 1
else
exit 0
fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.0.37'
else
echo 'x - continuing with patch-2.0.37'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.0.37' &&

X outb_p(E8390_RREAD+E8390_START, ioaddr); /* Trigger it... */
+ udelay(10000); /* wait 10ms for interrupt to propagate */
X outb_p(0x00, ioaddr + EN0_IMR); /* Mask it again. */
X dev->irq = autoirq_report(0);
X if (ei_debug > 2)
@@ -675,9 +678,7 @@
X outb_p(0x00, nic_base + EN0_RSARHI);
X outb_p(E8390_RREAD+E8390_START, nic_base + NE_CMD);
X /* Make certain that the dummy read has occurred. */
- SLOW_DOWN_IO;
- SLOW_DOWN_IO;
- SLOW_DOWN_IO;
+ udelay(6);
X #endif
X
X outb_p(ENISR_RDC, nic_base + EN0_ISR);
diff -u --recursive --new-file v2.0.36/linux/drivers/net/ni52.c linux/drivers/net/ni52.c
--- v2.0.36/linux/drivers/net/ni52.c Sun Nov 15 10:49:39 1998
+++ linux/drivers/net/ni52.c Sun Jun 13 10:21:01 1999
@@ -363,10 +363,11 @@
X #endif
X int base_addr = dev->base_addr;
X
- if (base_addr > 0x1ff) /* Check a single specified location. */
+ if (base_addr > 0x1ff) { /* Check a single specified location. */
X if( (inb(base_addr+NI52_MAGIC1) == NI52_MAGICVAL1) &&
X (inb(base_addr+NI52_MAGIC2) == NI52_MAGICVAL2))
X return ni52_probe1(dev, base_addr);
+ }
X else if (base_addr > 0) /* Don't probe at all. */
X return ENXIO;
X
diff -u --recursive --new-file v2.0.36/linux/drivers/net/pi2.c linux/drivers/net/pi2.c
--- v2.0.36/linux/drivers/net/pi2.c Sun Nov 15 10:49:39 1998
+++ linux/drivers/net/pi2.c Sun Jun 13 10:21:01 1999
@@ -1452,7 +1452,7 @@
X static int pi_open(struct device *dev)
X {
X unsigned long flags;
- static first_time = 1;
+ static int first_time = 1;
X
X struct pi_local *lp = (struct pi_local *) dev->priv;
X
diff -u --recursive --new-file v2.0.36/linux/drivers/net/ppp.c linux/drivers/net/ppp.c
--- v2.0.36/linux/drivers/net/ppp.c Mon Jul 13 13:46:30 1998
+++ linux/drivers/net/ppp.c Sun Jun 13 10:21:01 1999
@@ -3155,7 +3155,7 @@
X ppp_stats.tx_heartbeat_errors = 0;
X
X if (ppp->flags & SC_DEBUG)
- printk (KERN_INFO "ppp_dev_stats called");
+ printk (KERN_INFO "ppp_dev_stats called\n");
X return &ppp_stats;
X }
X
diff -u --recursive --new-file v2.0.36/linux/drivers/net/pt.c linux/drivers/net/pt.c
--- v2.0.36/linux/drivers/net/pt.c Sun Nov 15 10:49:40 1998
+++ linux/drivers/net/pt.c Sun Jun 13 10:21:01 1999
@@ -909,7 +909,7 @@
X {
X unsigned long flags;
X struct pt_local *lp = dev->priv;
- static first_time = 1;
+ static int first_time = 1;
X
X if (dev->base_addr & CHANA)
X {
diff -u --recursive --new-file v2.0.36/linux/drivers/net/rcif.h linux/drivers/net/rcif.h
--- v2.0.36/linux/drivers/net/rcif.h Sun Nov 15 21:51:46 1998
+++ linux/drivers/net/rcif.h Sun Jun 13 10:21:01 1999
@@ -8,7 +8,7 @@
X ** RedCreek InterFace include file.
X **
X ** ---------------------------------------------------------------------
-** --- Copyright (c) 1998, RedCreek Communications Inc. ---
+** --- Copyright (c) 1998-1999, RedCreek Communications Inc. ---
X ** --- All rights reserved. ---
X ** ---------------------------------------------------------------------
X **
@@ -38,7 +38,7 @@
X
X /* The following protocol revision # should be incremented every time
X a new protocol or new structures are used in this file. */
-int USER_PROTOCOL_REV = 1; /* used to track different protocol revisions */
+int USER_PROTOCOL_REV = 2; /* used to track different protocol revisions */
X
X /* define a single TCB & buffer */
X typedef struct /* a single buffer */
@@ -124,6 +124,31 @@
X U32 LinkSpeedCode;
X } RCgetspeed; /* <---- RCgetspeed */
X
+ /* SETSPEED structure */
+ struct RCsetspeed_tag {
+ U16 LinkSpeedCode;
+ } RCsetspeed; /* <---- RCsetspeed */
+
+ /* GETPROM structure */
+ struct RCgetprom_tag {
+ U32 PromMode;
+ } RCgetprom; /* <---- RCgetprom */
+
+ /* SETPROM structure */
+ struct RCsetprom_tag {
+ U16 PromMode;
+ } RCsetprom; /* <---- RCsetprom */
+
+ /* GETBROADCAST structure */
+ struct RCgetbroadcast_tag {
+ U32 BroadcastMode;
+ } RCgetbroadcast; /* <---- RCgetbroadcast */
+
+ /* SETBROADCAST structure */
+ struct RCsetbroadcast_tag {
+ U16 BroadcastMode;
+ } RCsetbroadcast; /* <---- RCsetbroadcast */
+
X /* GETFIRMWAREVER structure */
X #define FirmStringLen 80
X struct RCgetfwver_tag {
@@ -136,12 +161,23 @@
X U32 NetMask;
X } RCgetipandmask; /* <---- RCgetipandmask */
X
+ /* SETIPANDMASK structure */
+ struct RCsetipnmask_tag {
+ U32 IpAddr;
+ U32 NetMask;
+ } RCsetipandmask; /* <---- RCsetipandmask */
+
X /* GETMAC structure */
X #define MAC_SIZE 10
X struct RCgetmac_tag {
X U8 mac[MAC_SIZE];
X } RCgetmac; /* <---- RCgetmac */
X
+ /* SETMAC structure */
+ struct RCsetmac_tag {
+ U8 mac[MAC_SIZE];
+ } RCsetmac; /* <---- RCsetmac */
+
X /* GETLINKSTATUS structure */
X struct RCgetlnkstatus_tag {
X U32 ReturnStatus;
@@ -166,35 +202,56 @@
X union RC_user_data_tag { /* structure tags used are taken from RC_user_tag structure above */
X struct RCgetinfo_tag *getinfo;
X struct RCgetspeed_tag *getspeed;
+ struct RCgetprom_tag *getprom;
+ struct RCgetbroadcast_tag *getbroadcast;
X struct RCgetfwver_tag *getfwver;
X struct RCgetipnmask_tag *getipandmask;
X struct RCgetmac_tag *getmac;
X struct RCgetlnkstatus_tag *getlinkstatus;
X struct RCgetlinkstats_tag *getlinkstatistics;
X struct RCdefault_tag *rcdefault;
+ struct RCsetspeed_tag *setspeed;
+ struct RCsetprom_tag *setprom;
+ struct RCsetbroadcast_tag *setbroadcast;
+ struct RCsetipnmask_tag *setipandmask;
+ struct RCsetmac_tag *setmac;
X } _RC_user_data; /* declare as a global, so the defines below will work */
X
X /* 3) Structure short-cut entry */
X /* define structure short-cuts */ /* structure names are taken from RC_user_tag structure above */
X #define RCUS_GETINFO data.RCgetinfo;
X #define RCUS_GETSPEED data.RCgetspeed;
+#define RCUS_GETPROM data.RCgetprom;
+#define RCUS_GETBROADCAST data.RCgetbroadcast;
X #define RCUS_GETFWVER data.RCgetfwver;
X #define RCUS_GETIPANDMASK data.RCgetipandmask;
X #define RCUS_GETMAC data.RCgetmac;
X #define RCUS_GETLINKSTATUS data.RCgetlnkstatus;
X #define RCUS_GETLINKSTATISTICS data.RCgetlinkstats;
X #define RCUS_DEFAULT data.RCdefault;
+#define RCUS_SETSPEED data.RCsetspeed;
+#define RCUS_SETPROM data.RCsetprom;
+#define RCUS_SETBROADCAST data.RCsetbroadcast;
+#define RCUS_SETIPANDMASK data.RCsetipandmask;
+#define RCUS_SETMAC data.RCsetmac;
X
X /* 4) Data short-cut entry */
X /* define data short-cuts */ /* pointer names are from RC_user_data_tag union (just below RC_user_tag) */
X #define RCUD_GETINFO _RC_user_data.getinfo
X #define RCUD_GETSPEED _RC_user_data.getspeed
+#define RCUD_GETPROM _RC_user_data.getprom
+#define RCUD_GETBROADCAST _RC_user_data.getbroadcast
X #define RCUD_GETFWVER _RC_user_data.getfwver
X #define RCUD_GETIPANDMASK _RC_user_data.getipandmask
X #define RCUD_GETMAC _RC_user_data.getmac
X #define RCUD_GETLINKSTATUS _RC_user_data.getlinkstatus
X #define RCUD_GETLINKSTATISTICS _RC_user_data.getlinkstatistics
X #define RCUD_DEFAULT _RC_user_data.rcdefault
+#define RCUD_SETSPEED _RC_user_data.setspeed
+#define RCUD_SETPROM _RC_user_data.setprom
+#define RCUD_SETBROADCAST _RC_user_data.setbroadcast
+#define RCUD_SETIPANDMASK _RC_user_data.setipandmask
+#define RCUD_SETMAC _RC_user_data.setmac
X
X /* 5) Command identifier entry */
X /* define command identifiers */
@@ -205,7 +262,14 @@
X #define RCUC_GETMAC 0x05
X #define RCUC_GETLINKSTATUS 0x06
X #define RCUC_GETLINKSTATISTICS 0x07
+#define RCUC_GETPROM 0x14
+#define RCUC_GETBROADCAST 0x15
X #define RCUC_DEFAULT 0xff
+#define RCUC_SETSPEED 0x08
+#define RCUC_SETIPANDMASK 0x09
+#define RCUC_SETMAC 0x0a
+#define RCUC_SETPROM 0x16
+#define RCUC_SETBROADCAST 0x17
X
X /* define ioctl commands to use, when talking to RC 45/PCI driver */
X #define RCU_PROTOCOL_REV SIOCDEVPRIVATE
diff -u --recursive --new-file v2.0.36/linux/drivers/net/rclanmtl.c linux/drivers/net/rclanmtl.c
--- v2.0.36/linux/drivers/net/rclanmtl.c Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/rclanmtl.c Sun Jun 13 10:21:01 1999
@@ -0,0 +1,2311 @@
+/*
+** *************************************************************************
+**
+**
+** R C L A N M T L . C $Revision: 6 $
+**
+**
+** RedCreek I2O LAN Message Transport Layer program module.
+**
+** ---------------------------------------------------------------------
+** --- Copyright (c) 1997-1999, RedCreek Communications Inc. ---
+** --- All rights reserved. ---
+** ---------------------------------------------------------------------
+**
+** File Description:
+**
+** Host side I2O (Intelligent I/O) LAN message transport layer.
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+** 1998-1999, LAN API was modified and enhanced by Alice Hennessy.
+**
+** Sometime in 1997, LAN API was written from scratch by Wendell Nichols.
+** *************************************************************************
+*/
+
+#undef DEBUG
+
+#define RC_LINUX_MODULE
+#include "rclanmtl.h"
+
+#define dprintf kprintf
+
+extern int printk(const char * fmt, ...);
+
+ /* RedCreek LAN device Target ID */
+#define RC_LAN_TARGET_ID 0x10
+ /* RedCreek's OSM default LAN receive Initiator */
+#define DEFAULT_RECV_INIT_CONTEXT 0xA17
+
+
+/*
+** I2O message structures
+*/
+
+#define I2O_TID_SZ 12
+#define I2O_FUNCTION_SZ 8
+
+/* Transaction Reply Lists (TRL) Control Word structure */
+
+#define I2O_TRL_FLAGS_SINGLE_FIXED_LENGTH 0x00
+#define I2O_TRL_FLAGS_SINGLE_VARIABLE_LENGTH 0x40
+#define I2O_TRL_FLAGS_MULTIPLE_FIXED_LENGTH 0x80
+
+/* LAN Class specific functions */
+
+#define I2O_LAN_PACKET_SEND 0x3B
+#define I2O_LAN_SDU_SEND 0x3D
+#define I2O_LAN_RECEIVE_POST 0x3E
+#define I2O_LAN_RESET 0x35
+#define I2O_LAN_SHUTDOWN 0x37
+
+/* Private Class specfic function */
+#define I2O_PRIVATE 0xFF
+
+/* I2O Executive Function Codes. */
+
+#define I2O_EXEC_ADAPTER_ASSIGN 0xB3
+#define I2O_EXEC_ADAPTER_READ 0xB2
+#define I2O_EXEC_ADAPTER_RELEASE 0xB5
+#define I2O_EXEC_BIOS_INFO_SET 0xA5
+#define I2O_EXEC_BOOT_DEVICE_SET 0xA7
+#define I2O_EXEC_CONFIG_VALIDATE 0xBB
+#define I2O_EXEC_CONN_SETUP 0xCA
+#define I2O_EXEC_DEVICE_ASSIGN 0xB7
+#define I2O_EXEC_DEVICE_RELEASE 0xB9
+#define I2O_EXEC_HRT_GET 0xA8
+#define I2O_EXEC_IOP_CLEAR 0xBE
+#define I2O_EXEC_IOP_CONNECT 0xC9
+#define I2O_EXEC_IOP_RESET 0xBD
+#define I2O_EXEC_LCT_NOTIFY 0xA2
+#define I2O_EXEC_OUTBOUND_INIT 0xA1
+#define I2O_EXEC_PATH_ENABLE 0xD3
+#define I2O_EXEC_PATH_QUIESCE 0xC5
+#define I2O_EXEC_PATH_RESET 0xD7
+#define I2O_EXEC_STATIC_MF_CREATE 0xDD
+#define I2O_EXEC_STATIC_MF_RELEASE 0xDF
+#define I2O_EXEC_STATUS_GET 0xA0
+#define I2O_EXEC_SW_DOWNLOAD 0xA9
+#define I2O_EXEC_SW_UPLOAD 0xAB
+#define I2O_EXEC_SW_REMOVE 0xAD
+#define I2O_EXEC_SYS_ENABLE 0xD1
+#define I2O_EXEC_SYS_MODIFY 0xC1
+#define I2O_EXEC_SYS_QUIESCE 0xC3
+#define I2O_EXEC_SYS_TAB_SET 0xA3
+
+
+ /* Init Outbound Q status */
+#define I2O_EXEC_OUTBOUND_INIT_IN_PROGRESS 0x01
+#define I2O_EXEC_OUTBOUND_INIT_REJECTED 0x02
+#define I2O_EXEC_OUTBOUND_INIT_FAILED 0x03
+#define I2O_EXEC_OUTBOUND_INIT_COMPLETE 0x04
+
+
+#define I2O_UTIL_NOP 0x00
+
+
+/* I2O Get Status State values */
+
+#define I2O_IOP_STATE_INITIALIZING 0x01
+#define I2O_IOP_STATE_RESET 0x02
+#define I2O_IOP_STATE_HOLD 0x04
+#define I2O_IOP_STATE_READY 0x05
+#define I2O_IOP_STATE_OPERATIONAL 0x08
+#define I2O_IOP_STATE_FAILED 0x10
+#define I2O_IOP_STATE_FAULTED 0x11
+
+
+/* Defines for Request Status Codes: Table 3-1 Reply Status Codes. */
+
+#define I2O_REPLY_STATUS_SUCCESS 0x00
+#define I2O_REPLY_STATUS_ABORT_DIRTY 0x01
+#define I2O_REPLY_STATUS_ABORT_NO_DATA_TRANSFER 0x02
+#define I2O_REPLY_STATUS_ABORT_PARTIAL_TRANSFER 0x03
+#define I2O_REPLY_STATUS_ERROR_DIRTY 0x04
+#define I2O_REPLY_STATUS_ERROR_NO_DATA_TRANSFER 0x05
+#define I2O_REPLY_STATUS_ERROR_PARTIAL_TRANSFER 0x06
+#define I2O_REPLY_STATUS_PROCESS_ABORT_DIRTY 0x07
+#define I2O_REPLY_STATUS_PROCESS_ABORT_NO_DATA_TRANSFER 0x08
+#define I2O_REPLY_STATUS_PROCESS_ABORT_PARTIAL_TRANSFER 0x09
+#define I2O_REPLY_STATUS_TRANSACTION_ERROR 0x0A
+#define I2O_REPLY_STATUS_PROGRESS_REPORT 0x80
+
+
+/* DetailedStatusCode defines for ALL messages: Table 3-2 Detailed Status Codes.*/
+
+#define I2O_DETAIL_STATUS_SUCCESS 0x0000
+#define I2O_DETAIL_STATUS_BAD_KEY 0x0001
+#define I2O_DETAIL_STATUS_CHAIN_BUFFER_TOO_LARGE 0x0002
+#define I2O_DETAIL_STATUS_DEVICE_BUSY 0x0003
+#define I2O_DETAIL_STATUS_DEVICE_LOCKED 0x0004
+#define I2O_DETAIL_STATUS_DEVICE_NOT_AVAILABLE 0x0005
+#define I2O_DETAIL_STATUS_DEVICE_RESET 0x0006
+#define I2O_DETAIL_STATUS_INAPPROPRIATE_FUNCTION 0x0007
+#define I2O_DETAIL_STATUS_INSUFFICIENT_RESOURCE_HARD 0x0008
+#define I2O_DETAIL_STATUS_INSUFFICIENT_RESOURCE_SOFT 0x0009
+#define I2O_DETAIL_STATUS_INVALID_INITIATOR_ADDRESS 0x000A
+#define I2O_DETAIL_STATUS_INVALID_MESSAGE_FLAGS 0x000B
+#define I2O_DETAIL_STATUS_INVALID_OFFSET 0x000C
+#define I2O_DETAIL_STATUS_INVALID_PARAMETER 0x000D
+#define I2O_DETAIL_STATUS_INVALID_REQUEST 0x000E
+#define I2O_DETAIL_STATUS_INVALID_TARGET_ADDRESS 0x000F
+#define I2O_DETAIL_STATUS_MESSAGE_TOO_LARGE 0x0010
+#define I2O_DETAIL_STATUS_MESSAGE_TOO_SMALL 0x0011
+#define I2O_DETAIL_STATUS_MISSING_PARAMETER 0x0012
+#define I2O_DETAIL_STATUS_NO_SUCH_PAGE 0x0013
+#define I2O_DETAIL_STATUS_REPLY_BUFFER_FULL 0x0014
+#define I2O_DETAIL_STATUS_TCL_ERROR 0x0015
+#define I2O_DETAIL_STATUS_TIMEOUT 0x0016
+#define I2O_DETAIL_STATUS_UNKNOWN_ERROR 0x0017
+#define I2O_DETAIL_STATUS_UNKNOWN_FUNCTION 0x0018
+#define I2O_DETAIL_STATUS_UNSUPPORTED_FUNCTION 0x0019
+#define I2O_DETAIL_STATUS_UNSUPPORTED_VERSION 0x001A
+
+ /* I2O msg header defines for VersionOffset */
+#define I2OMSGVER_1_5 0x0001
+#define SGL_OFFSET_0 I2OMSGVER_1_5
+#define SGL_OFFSET_4 (0x0040 | I2OMSGVER_1_5)
+#define TRL_OFFSET_5 (0x0050 | I2OMSGVER_1_5)
+#define TRL_OFFSET_6 (0x0060 | I2OMSGVER_1_5)
+
+ /* I2O msg header defines for MsgFlags */
+#define MSG_STATIC 0x0100
+#define MSG_64BIT_CNTXT 0x0200
+#define MSG_MULTI_TRANS 0x1000
+#define MSG_FAIL 0x2000
+#define MSG_LAST 0x4000
+#define MSG_REPLY 0x8000
+
+ /* normal LAN request message MsgFlags and VersionOffset (0x1041) */
+#define LAN_MSG_REQST (MSG_MULTI_TRANS | SGL_OFFSET_4)
+
+ /* minimum size msg */
+#define THREE_WORD_MSG_SIZE 0x00030000
+#define FOUR_WORD_MSG_SIZE 0x00040000
+#define FIVE_WORD_MSG_SIZE 0x00050000
+#define SIX_WORD_MSG_SIZE 0x00060000
+#define SEVEN_WORD_MSG_SIZE 0x00070000
+#define EIGHT_WORD_MSG_SIZE 0x00080000
+#define NINE_WORD_MSG_SIZE 0x00090000
+
+/* Special TID Assignments */
+
+#define I2O_IOP_TID 0
+#define I2O_HOST_TID 0xB91
+
+ /* RedCreek I2O private message codes */
+#define RC_PRIVATE_GET_MAC_ADDR 0x0001/**/ /* OBSOLETE */
+#define RC_PRIVATE_SET_MAC_ADDR 0x0002
+#define RC_PRIVATE_GET_NIC_STATS 0x0003
+#define RC_PRIVATE_GET_LINK_STATUS 0x0004
+#define RC_PRIVATE_SET_LINK_SPEED 0x0005
+#define RC_PRIVATE_SET_IP_AND_MASK 0x0006
+/* #define RC_PRIVATE_GET_IP_AND_MASK 0x0007 */ /* OBSOLETE */
+#define RC_PRIVATE_GET_LINK_SPEED 0x0008
+#define RC_PRIVATE_GET_FIRMWARE_REV 0x0009
+/* #define RC_PRIVATE_GET_MAC_ADDR 0x000A *//**/
+#define RC_PRIVATE_GET_IP_AND_MASK 0x000B /**/
+#define RC_PRIVATE_DEBUG_MSG 0x000C
+#define RC_PRIVATE_REPORT_DRIVER_CAPABILITY 0x000D
+#define RC_PRIVATE_SET_PROMISCUOUS_MODE 0x000e
+#define RC_PRIVATE_GET_PROMISCUOUS_MODE 0x000f
+#define RC_PRIVATE_SET_BROADCAST_MODE 0x0010
+#define RC_PRIVATE_GET_BROADCAST_MODE 0x0011
+
+#define RC_PRIVATE_REBOOT 0x00FF
+
+
+/* I2O message header */
+typedef struct _I2O_MESSAGE_FRAME
+{
+ U8 VersionOffset;
+ U8 MsgFlags;
+ U16 MessageSize;
+ BF TargetAddress:I2O_TID_SZ;
+ BF InitiatorAddress:I2O_TID_SZ;
+ BF Function:I2O_FUNCTION_SZ;
+ U32 InitiatorContext;
+ /* SGL[] */
+}
+I2O_MESSAGE_FRAME, *PI2O_MESSAGE_FRAME;
+
+
+ /* assumed a 16K minus 256 byte space for outbound queue message frames */
+#define MSG_FRAME_SIZE 512
+#define NMBR_MSG_FRAMES 30
+
+/*
+** Message Unit CSR definitions for RedCreek PCI45 board
+*/
+typedef struct tag_rcatu
+{
+ volatile unsigned long APICRegSel; /* APIC Register Select */
+ volatile unsigned long reserved0;
+ volatile unsigned long APICWinReg; /* APIC Window Register */
+ volatile unsigned long reserved1;
+ volatile unsigned long InMsgReg0; /* inbound message register 0 */
+ volatile unsigned long InMsgReg1; /* inbound message register 1 */
+ volatile unsigned long OutMsgReg0; /* outbound message register 0 */
+ volatile unsigned long OutMsgReg1; /* outbound message register 1 */
+ volatile unsigned long InDoorReg; /* inbound doorbell register */
+ volatile unsigned long InIntStat; /* inbound interrupt status register */
+ volatile unsigned long InIntMask; /* inbound interrupt mask register */
+ volatile unsigned long OutDoorReg; /* outbound doorbell register */
+ volatile unsigned long OutIntStat; /* outbound interrupt status register */
+ volatile unsigned long OutIntMask; /* outbound interrupt mask register */
+ volatile unsigned long reserved2;
+ volatile unsigned long reserved3;
+ volatile unsigned long InQueue; /* inbound queue port */
+ volatile unsigned long OutQueue; /* outbound queue port */
+ volatile unsigned long reserved4;
+ volatile unsigned long reserver5;
+ /* RedCreek extension */
+ volatile unsigned long EtherMacLow;
+ volatile unsigned long EtherMacHi;
+ volatile unsigned long IPaddr;
+ volatile unsigned long IPmask;
+}
+ATU, *PATU;
+
+ /*
+ ** typedef PAB
+ **
+ ** PCI Adapter Block - holds instance specific information and is located
+ ** in a reserved space at the start of the message buffer allocated by user.
+ */
+typedef struct
+{
+ PATU p_atu; /* ptr to ATU register block */
+ PU8 pPci45LinBaseAddr;
+ PU8 pLinOutMsgBlock;
+ U32 outMsgBlockPhyAddr;
+ PFNTXCALLBACK pTransCallbackFunc;
+ PFNRXCALLBACK pRecvCallbackFunc;
+ PFNCALLBACK pRebootCallbackFunc;
+ PFNCALLBACK pCallbackFunc;
+ U16 IOPState;
+ U16 InboundMFrameSize;
+}
+PAB, *PPAB;
+
+ /*
+ ** in reserved space right after PAB in host memory is area for returning
+ ** values from card
+ */
+
+ /*
+ ** Array of pointers to PCI Adapter Blocks.
+ ** Indexed by a zero based (0-31) interface number.
+ */
+#define MAX_ADAPTERS 32
+static PPAB PCIAdapterBlock[MAX_ADAPTERS] =
+{
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+
+/*
+** typedef NICSTAT
+**
+** Data structure for NIC statistics retruned from PCI card. Data copied from
+** here to user allocated RCLINKSTATS (see rclanmtl.h) structure.
+*/
+typedef struct tag_NicStat
+{
+ unsigned long TX_good;
+ unsigned long TX_maxcol;
+ unsigned long TX_latecol;
+ unsigned long TX_urun;
+ unsigned long TX_crs; /* lost carrier sense */
+ unsigned long TX_def; /* transmit deferred */
+ unsigned long TX_singlecol; /* single collisions */
+ unsigned long TX_multcol;
+ unsigned long TX_totcol;
+ unsigned long Rcv_good;
+ unsigned long Rcv_CRCerr;
+ unsigned long Rcv_alignerr;
+ unsigned long Rcv_reserr; /* rnr'd pkts */
+ unsigned long Rcv_orun;
+ unsigned long Rcv_cdt;
+ unsigned long Rcv_runt;
+ unsigned long dump_status; /* last field directly from the chip */
+}
+NICSTAT, *P_NICSTAT;
+
+
+#define DUMP_DONE 0x0000A005 /* completed statistical dump */
+#define DUMP_CLEAR 0x0000A007 /* completed stat dump and clear counters */
+
+
+static volatile int msgFlag;
+
+
+/* local function prototypes */
+static void ProcessOutboundI2OMsg(PPAB pPab, U32 phyMsgAddr);
+static int FillI2OMsgSGLFromTCB(PU32 pMsg, PRCTCB pXmitCntrlBlock);
+static int GetI2OStatus(PPAB pPab);
+static int SendI2OOutboundQInitMsg(PPAB pPab);
+static int SendEnableSysMsg(PPAB pPab);
+
+
+/* 1st 100h bytes of message block is reserved for messenger instance */
+#define ADAPTER_BLOCK_RESERVED_SPACE 0x100
+
+/*
+** =========================================================================
+** RCInitI2OMsgLayer()
+**
+** Initialize the RedCreek I2O Module and adapter.
+**
+** Inputs: AdapterID - interface number from 0 to 15
+** pciBaseAddr - virual base address of PCI (set by BIOS)
+** p_msgbuf - virual address to private message block (min. 16K)
+** p_phymsgbuf - physical address of private message block
+** TransmitCallbackFunction - address of transmit callback function
+** ReceiveCallbackFunction - address of receive callback function
+**
+** private message block is allocated by user. It must be in locked pages.
+** p_msgbuf and p_phymsgbuf point to the same location. Must be contigous
+** memory block of a minimum of 16K byte and long word aligned.
+** =========================================================================
+*/
+RC_RETURN
+RCInitI2OMsgLayer(U16 AdapterID, U32 pciBaseAddr,
+ PU8 p_msgbuf, PU8 p_phymsgbuf,
+ PFNTXCALLBACK TransmitCallbackFunction,
+ PFNRXCALLBACK ReceiveCallbackFunction,
+ PFNCALLBACK RebootCallbackFunction)
+{
+ int result;
+ PPAB pPab;
+
+#ifdef DEBUG
+ kprintf("InitI2O: Adapter:0x%04.4ux ATU:0x%08.8ulx msgbuf:0x%08.8ulx phymsgbuf:0x%08.8ulx\n"
+ "TransmitCallbackFunction:0x%08.8ulx ReceiveCallbackFunction:0x%08.8ulx\n",
+ AdapterID, pciBaseAddr, p_msgbuf, p_phymsgbuf, TransmitCallbackFunction, ReceiveCallbackFunction);
+#endif /* DEBUG */
+
+
+ /* Check if this interface already initialized - if so, shut it down */
+ if (PCIAdapterBlock[AdapterID] != NULL)
+ {
+ printk("PCIAdapterBlock[%d]!=NULL\n", AdapterID);
+// RCResetLANCard(AdapterID, 0, (PU32)NULL, (PFNCALLBACK)NULL);
+ PCIAdapterBlock[AdapterID] = NULL;
+ }
+
+ /*
+ ** store adapter instance values in adapter block.
+ ** Adapter block is at beginning of message buffer
+ */
+ pPab = (PPAB)p_msgbuf;
+
+ pPab->p_atu = (PATU)pciBaseAddr;
+ pPab->pPci45LinBaseAddr = (PU8)pciBaseAddr;
+
+ /* Set outbound message frame addr - skip over Adapter Block */
+ pPab->outMsgBlockPhyAddr = (U32)(p_phymsgbuf + ADAPTER_BLOCK_RESERVED_SPACE);
+ pPab->pLinOutMsgBlock = (PU8)(p_msgbuf + ADAPTER_BLOCK_RESERVED_SPACE);
+
+ /* store callback function addresses */
+ pPab->pTransCallbackFunc = TransmitCallbackFunction;
+ pPab->pRecvCallbackFunc = ReceiveCallbackFunction;
+ pPab->pRebootCallbackFunc = RebootCallbackFunction;
+ pPab->pCallbackFunc = (PFNCALLBACK)NULL;
+
+ /*
+ ** Initialize I2O IOP
+ */
+ result = GetI2OStatus(pPab);
+
+ if (result != RC_RTN_NO_ERROR)
+ return result;
+
+ if (pPab->IOPState == I2O_IOP_STATE_OPERATIONAL)
+ {
+ printk("pPab->IOPState == op: resetting adapter\n");
+ RCResetLANCard(AdapterID, 0, (PU32)NULL, (PFNCALLBACK)NULL);
+ }
+
+ result = SendI2OOutboundQInitMsg(pPab);
+
+ if (result != RC_RTN_NO_ERROR)
+ return result;
+
+ result = SendEnableSysMsg(pPab);
+
+ if (result != RC_RTN_NO_ERROR)
+ return result;
+
+ PCIAdapterBlock[AdapterID] = pPab;
+ return RC_RTN_NO_ERROR;
+}
+
+/*
+** =========================================================================
+** Disable and Enable I2O interrupts. I2O interrupts are enabled at Init time
+** but can be disabled and re-enabled through these two function calls.
+** Packets will still be put into any posted received buffers and packets will
+** be sent through RCI2OSendPacket() functions. Disabling I2O interrupts
+** will prevent hardware interrupt to host even though the outbound I2O msg
+** queue is not emtpy.
+** =========================================================================
+*/
+#define i960_OUT_POST_Q_INT_BIT 0x0008 /* bit set masks interrupts */
+
+RC_RETURN RCDisableI2OInterrupts(U16 AdapterID)
+{
+ PPAB pPab;
+
+
+ pPab = PCIAdapterBlock[AdapterID];
+
+ if (pPab == NULL)
+ return RC_RTN_ADPTR_NOT_REGISTERED;
+
+ pPab->p_atu->OutIntMask |= i960_OUT_POST_Q_INT_BIT;
+
+ return RC_RTN_NO_ERROR;
+}
+
+RC_RETURN RCEnableI2OInterrupts(U16 AdapterID)
+{
+ PPAB pPab;
+
+ pPab = PCIAdapterBlock[AdapterID];
+
+ if (pPab == NULL)
+ return RC_RTN_ADPTR_NOT_REGISTERED;
+
+ pPab->p_atu->OutIntMask &= ~i960_OUT_POST_Q_INT_BIT;
+
+ return RC_RTN_NO_ERROR;


+
+}
+
+
+/*

+** =========================================================================
+** RCI2OSendPacket()
+** =========================================================================
+*/
+RC_RETURN
+RCI2OSendPacket(U16 AdapterID, U32 InitiatorContext, PRCTCB pTransCtrlBlock)
+{
+ U32 msgOffset;
+ PU32 pMsg;
+ int size;
+ PPAB pPab;
+
+#ifdef DEBUG
+ kprintf("RCI2OSendPacket()...\n");
+#endif /* DEBUG */
+
+ pPab = PCIAdapterBlock[AdapterID];
+
+ if (pPab == NULL)
+ return RC_RTN_ADPTR_NOT_REGISTERED;
+
+ /* get Inbound free Q entry - reading from In Q gets free Q entry */
+ /* offset to Msg Frame in PCI msg block */
+
+ msgOffset = pPab->p_atu->InQueue;
+
+ if (msgOffset == 0xFFFFFFFF)
+ {
+#ifdef DEBUG
+ kprintf("RCI2OSendPacket(): Inbound Free Q empty!\n");
+#endif /* DEBUG */
+ return RC_RTN_FREE_Q_EMPTY;
+ }
+
+ /* calc virual address of msg - virual already mapped to physical */
+ pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset);
+
+ size = FillI2OMsgSGLFromTCB(pMsg + 4, pTransCtrlBlock);
+
+ if (size == -1) /* error processing TCB - send NOP msg */
+ {
+#ifdef DEBUG
+ kprintf("RCI2OSendPacket(): Error Rrocess TCB!\n");
+#endif /* DEBUG */
+ pMsg[0] = THREE_WORD_MSG_SIZE | SGL_OFFSET_0;
+ pMsg[1] = I2O_UTIL_NOP << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID;
+ return RC_RTN_TCB_ERROR;
+ }
+ else /* send over msg header */
+ {
+ pMsg[0] = (size + 4) << 16 | LAN_MSG_REQST; /* send over message size and flags */
+ pMsg[1] = I2O_LAN_PACKET_SEND << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID;
+ pMsg[2] = InitiatorContext;
+ pMsg[3] = 0; /* batch reply */
+ /* post to Inbound Post Q */
+ pPab->p_atu->InQueue = msgOffset;
+ return RC_RTN_NO_ERROR;


+ }
+}
+
+
+/*

+** =========================================================================
+** RCI2OPostRecvBuffer()
+**
+** inputs: pBufrCntrlBlock - pointer to buffer control block
+**
+** returns TRUE if successful in sending message, else FALSE.
+** =========================================================================
+*/
+RC_RETURN
+RCPostRecvBuffers(U16 AdapterID, PRCTCB pTransCtrlBlock)
+{
+ U32 msgOffset;
+ PU32 pMsg;
+ int size;
+ PPAB pPab;
+
+#ifdef DEBUG
+ kprintf("RCPostRecvBuffers()...\n");
+#endif /* DEBUG */
+
+ /* search for DeviceHandle */
+ pPab = PCIAdapterBlock[AdapterID];
+
+ if (pPab == NULL)
+ return RC_RTN_ADPTR_NOT_REGISTERED;
+
+
+ /* get Inbound free Q entry - reading from In Q gets free Q entry */
+ /* offset to Msg Frame in PCI msg block */
+ msgOffset = pPab->p_atu->InQueue;
+
+ if (msgOffset == 0xFFFFFFFF)
+ {
+#ifdef DEBUG
+ kprintf("RCPostRecvBuffers(): Inbound Free Q empty!\n");
+#endif /* DEBUG */
+ return RC_RTN_FREE_Q_EMPTY;
+
+ }
+ /* calc virual address of msg - virual already mapped to physical */
+ pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset);
+
+ size = FillI2OMsgSGLFromTCB(pMsg + 4, pTransCtrlBlock);
+
+ if (size == -1) /* error prcessing TCB - send 3 DWORD private msg == NOP */
+ {
+#ifdef DEBUG
+ kprintf("RCPostRecvBuffers(): Error Processing TCB! size = %d\n", size);
+#endif /* DEBUG */
+ pMsg[0] = THREE_WORD_MSG_SIZE | SGL_OFFSET_0;
+ pMsg[1] = I2O_UTIL_NOP << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID;
+ /* post to Post Q */
+ pPab->p_atu->InQueue = msgOffset;
+ return RC_RTN_TCB_ERROR;
+ }
+ else /* send over size msg header */
+ {
+ pMsg[0] = (size + 4) << 16 | LAN_MSG_REQST; /* send over message size and flags */
+ pMsg[1] = I2O_LAN_RECEIVE_POST << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID;
+ pMsg[2] = DEFAULT_RECV_INIT_CONTEXT;
+ pMsg[3] = *(PU32)pTransCtrlBlock; /* number of packet buffers */
+ /* post to Post Q */
+ pPab->p_atu->InQueue = msgOffset;
+ return RC_RTN_NO_ERROR;


+ }
+}
+
+
+/*

+** =========================================================================
+** RCProcI2OMsgQ()
+**
+** Process I2O outbound message queue until empty.
+** =========================================================================
+*/
+void
+RCProcI2OMsgQ(U16 AdapterID)
+{
+ U32 phyAddrMsg;
+ PU8 p8Msg;
+ PU32 p32;
+ U16 count;
+ PPAB pPab;
+ unsigned char debug_msg[20];
+
+ pPab = PCIAdapterBlock[AdapterID];
+
+ if (pPab == NULL)
+ return;
+
+ phyAddrMsg = pPab->p_atu->OutQueue;
+
+ while (phyAddrMsg != 0xFFFFFFFF)
+ {
+ p8Msg = pPab->pLinOutMsgBlock + (phyAddrMsg - pPab->outMsgBlockPhyAddr);
+ p32 = (PU32)p8Msg;
+
+ //printk(" msg: 0x%x 0x%x \n", p8Msg[7], p32[5]);
+
+ /*
+ ** Send Packet Reply Msg
+ */
+ if (I2O_LAN_PACKET_SEND == p8Msg[7]) /* function code byte */
+ {
+ count = *(PU16)(p8Msg+2);
+ count -= p8Msg[0] >> 4;
+ /* status, count, context[], adapter */
+ (*pPab->pTransCallbackFunc)(p8Msg[19], count, p32+5, AdapterID);
+ }
+ /*
+ ** Receive Packet Reply Msg */
+ else if (I2O_LAN_RECEIVE_POST == p8Msg[7])
+ {
+#ifdef DEBUG
+ kprintf("I2O_RECV_REPLY pPab:0x%08.8ulx p8Msg:0x%08.8ulx p32:0x%08.8ulx\n", pPab, p8Msg, p32);
+ kprintf("msg: 0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx\n",
+ p32[0], p32[1], p32[2], p32[3]);
+ kprintf(" 0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx\n",
+ p32[4], p32[5], p32[6], p32[7]);
+ kprintf(" 0x%08.8ulx:0X%08.8ulx:0x%08.8ulx:0x%08.8ulx\n",
+ p32[8], p32[9], p32[10], p32[11]);
+#endif
+ /* status, count, buckets remaining, packetParmBlock, adapter */
+ (*pPab->pRecvCallbackFunc)(p8Msg[19], p8Msg[12], p32[5], p32+6, AdapterID);
+
+
+ }
+ else if (I2O_LAN_RESET == p8Msg[7] || I2O_LAN_SHUTDOWN == p8Msg[7])
+ {
+ if (pPab->pCallbackFunc)
+ {
+ (*pPab->pCallbackFunc)(p8Msg[19],0,0,AdapterID);
+ }
+ else
+ {
+ pPab->pCallbackFunc = (PFNCALLBACK) 1;
+ }
+ //PCIAdapterBlock[AdapterID] = 0;
+ }
+ else if (I2O_PRIVATE == p8Msg[7])
+ {
+ //printk("i2o private 0x%x, 0x%x \n", p8Msg[7], p32[5]);
+ switch (p32[5])
+ {
+ case RC_PRIVATE_DEBUG_MSG:
+ msgFlag = 1;
+ /*printk("Received I2O_PRIVATE msg\n");*/
+ debug_msg[15] = (p32[6]&0xff000000) >> 24;
+ debug_msg[14] = (p32[6]&0x00ff0000) >> 16;
+ debug_msg[13] = (p32[6]&0x0000ff00) >> 8;
+ debug_msg[12] = (p32[6]&0x000000ff);
+
+ debug_msg[11] = (p32[7]&0xff000000) >> 24;
+ debug_msg[10] = (p32[7]&0x00ff0000) >> 16;
+ debug_msg[ 9] = (p32[7]&0x0000ff00) >> 8;
+ debug_msg[ 8] = (p32[7]&0x000000ff);
+
+ debug_msg[ 7] = (p32[8]&0xff000000) >> 24;
+ debug_msg[ 6] = (p32[8]&0x00ff0000) >> 16;
+ debug_msg[ 5] = (p32[8]&0x0000ff00) >> 8;
+ debug_msg[ 4] = (p32[8]&0x000000ff);
+
+ debug_msg[ 3] = (p32[9]&0xff000000) >> 24;
+ debug_msg[ 2] = (p32[9]&0x00ff0000) >> 16;
+ debug_msg[ 1] = (p32[9]&0x0000ff00) >> 8;
+ debug_msg[ 0] = (p32[9]&0x000000ff);
+
+ debug_msg[16] = '\0';
+ printk (debug_msg);
+ break;
+ case RC_PRIVATE_REBOOT:
+ printk("Adapter reboot initiated...\n");
+ if (pPab->pRebootCallbackFunc)
+ {
+ (*pPab->pRebootCallbackFunc)(0,0,0,AdapterID);
+ }
+ break;
+ default:
+ printk("Unknown private I2O msg received: 0x%x\n",
+ p32[5]);
+ break;
+ }
+ }
+
+ /*
+ ** Process other Msg's
+ */
+ else
+ {
+ ProcessOutboundI2OMsg(pPab, phyAddrMsg);
+ }
+
+ /* return MFA to outbound free Q*/
+ pPab->p_atu->OutQueue = phyAddrMsg;
+
+ /* any more msgs? */
+ phyAddrMsg = pPab->p_atu->OutQueue;


+ }
+}
+
+
+/*

+** =========================================================================
+** Returns LAN interface statistical counters to space provided by caller at
+** StatsReturnAddr. Returns 0 if success, else RC_RETURN code.
+** This function will call the WaitCallback function provided by
+** user while waiting for card to respond.
+** =========================================================================
+*/
+RC_RETURN
+RCGetLinkStatistics(U16 AdapterID,
+ P_RCLINKSTATS StatsReturnAddr,
+ PFNWAITCALLBACK WaitCallback)
+{
+ U32 msgOffset;
+ volatile U32 timeout;
+ volatile PU32 pMsg;
+ volatile PU32 p32, pReturnAddr;
+ P_NICSTAT pStats;
+ int i;
+ PPAB pPab;
+
+/*kprintf("Get82558Stats() StatsReturnAddr:0x%08.8ulx\n", StatsReturnAddr);*/
+
+ pPab = PCIAdapterBlock[AdapterID];
+
+ if (pPab == NULL)
+ return RC_RTN_ADPTR_NOT_REGISTERED;
+
+ msgOffset = pPab->p_atu->InQueue;
+
+ if (msgOffset == 0xFFFFFFFF)
+ {
+#ifdef DEBUG
+ kprintf("Get8255XStats(): Inbound Free Q empty!\n");
+#endif
+ return RC_RTN_FREE_Q_EMPTY;
+ }
+
+ /* calc virual address of msg - virual already mapped to physical */
+ pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset);
+
+/*dprintf("Get82558Stats - pMsg = 0x%08ulx, InQ msgOffset = 0x%08ulx\n", pMsg, msgOffset);*/
+/*dprintf("Get82558Stats - pMsg = 0x%08X, InQ msgOffset = 0x%08X\n", pMsg, msgOffset);*/
+
+ pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0;
+ pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID;
+ pMsg[2] = DEFAULT_RECV_INIT_CONTEXT;
+ pMsg[3] = 0x112; /* transaction context */
+ pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_NIC_STATS;
+ pMsg[5] = pPab->outMsgBlockPhyAddr - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB);
+
+ p32 = (PU32)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB));
+
+ pStats = (P_NICSTAT)p32;
+ pStats->dump_status = 0xFFFFFFFF;
+
+ /* post to Inbound Post Q */
+ pPab->p_atu->InQueue = msgOffset;
+
+ timeout = 100000;
+ while (1)
+ {
+ if (WaitCallback)
+ (*WaitCallback)();
+
+ for (i = 0; i < 1000; i++)
+ ;
+
+ if (pStats->dump_status != 0xFFFFFFFF)
+ break;
+
+ if (!timeout--)
+ {
+#ifdef DEBUG
+ kprintf("RCGet82558Stats() Timeout waiting for NIC statistics\n");
+#endif
+ return RC_RTN_MSG_REPLY_TIMEOUT;
+ }
+ }
+
+ pReturnAddr = (PU32)StatsReturnAddr;
+
+ /* copy Nic stats to user's structure */
+ for (i = 0; i < (int) sizeof(RCLINKSTATS) / 4; i++)
+ pReturnAddr[i] = p32[i];
+
+ return RC_RTN_NO_ERROR;
+}
+
+
+/*
+** =========================================================================
+** Get82558LinkStatus()
+** =========================================================================
+*/
+RC_RETURN
+RCGetLinkStatus(U16 AdapterID, PU32 ReturnAddr, PFNWAITCALLBACK WaitCallback)
+{
+ U32 msgOffset;
+ volatile U32 timeout;
+ volatile PU32 pMsg;
+ volatile PU32 p32;
+ PPAB pPab;
+
+/*kprintf("Get82558LinkStatus() ReturnPhysAddr:0x%08.8ulx\n", ReturnAddr);*/
+
+ pPab = PCIAdapterBlock[AdapterID];
+
+ if (pPab == NULL)
+ return RC_RTN_ADPTR_NOT_REGISTERED;
+
+ msgOffset = pPab->p_atu->InQueue;
+
+ if (msgOffset == 0xFFFFFFFF)
+ {
+#ifdef DEBUG
+ dprintf("Get82558LinkStatus(): Inbound Free Q empty!\n");
+#endif
+ return RC_RTN_FREE_Q_EMPTY;
+ }
+
+ /* calc virual address of msg - virual already mapped to physical */
+ pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset);
+/*dprintf("Get82558LinkStatus - pMsg = 0x%08ulx, InQ msgOffset = 0x%08ulx\n", pMsg, msgOffset);*/
+/*dprintf("Get82558LinkStatus - pMsg = 0x%08X, InQ msgOffset = 0x%08X\n", pMsg, msgOffset);*/
+
+ pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0;
+ pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID;
+ pMsg[2] = DEFAULT_RECV_INIT_CONTEXT;
+ pMsg[3] = 0x112; /* transaction context */
+ pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_LINK_STATUS;
+ pMsg[5] = pPab->outMsgBlockPhyAddr - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB);
+
+ p32 = (PU32)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB));
+ *p32 = 0xFFFFFFFF;
+
+ /* post to Inbound Post Q */
+ pPab->p_atu->InQueue = msgOffset;
+
+ timeout = 100000;
+ while (1)
+ {
+ U32 i;
+
+ if (WaitCallback)
+ (*WaitCallback)();
+
+ for (i = 0; i < 1000; i++)
+ ;
+
+ if (*p32 != 0xFFFFFFFF)
+ break;
+
+ if (!timeout--)
+ {
+#ifdef DEBUG
+ kprintf("Timeout waiting for link status\n");
+#endif
+ return RC_RTN_MSG_REPLY_TIMEOUT;
+ }
+ }
+
+ *ReturnAddr = *p32; /* 1 = up 0 = down */
+
+ return RC_RTN_NO_ERROR;
+
+}
+
+/*
+** =========================================================================
+** RCGetMAC()
+**
+** get the MAC address the adapter is listening for in non-promiscous mode.
+** MAC address is in media format.
+** =========================================================================
+*/
+RC_RETURN
+RCGetMAC(U16 AdapterID, PU8 mac, PFNWAITCALLBACK WaitCallback)
+{
+ unsigned i, timeout;
+ U32 off;
+ PU32 p;
+ U32 temp[2];
+ PPAB pPab;
+ PATU p_atu;
+
+ pPab = PCIAdapterBlock[AdapterID];
+
+ if (pPab == NULL)
+ return RC_RTN_ADPTR_NOT_REGISTERED;
+
+ p_atu = pPab->p_atu;
+
+ p_atu->EtherMacLow = 0; /* first zero return data */
+ p_atu->EtherMacHi = 0;
+
+ off = p_atu->InQueue; /* get addresss of message */
+
+ if (0xFFFFFFFF == off)
+ return RC_RTN_FREE_Q_EMPTY;
+
+ p = (PU32)(pPab->pPci45LinBaseAddr + off);
+
+#ifdef RCDEBUG
+ printk("RCGetMAC: p_atu 0x%08x, off 0x%08x, p 0x%08x\n",
+ (uint)p_atu, (uint)off, (uint)p);
+#endif /* RCDEBUG */
+ /* setup private message */
+ p[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0;
+ p[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID;
+ p[2] = 0; /* initiator context */
+ p[3] = 0x218; /* transaction context */
+ p[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_MAC_ADDR;
+
+
+ p_atu->InQueue = off; /* send it to the I2O device */
+#ifdef RCDEBUG
+ printk("RCGetMAC: p_atu 0x%08x, off 0x%08x, p 0x%08x\n",
+ (uint)p_atu, (uint)off, (uint)p);
+#endif /* RCDEBUG */
+
+ /* wait for the rcpci45 board to update the info */
+ timeout = 1000000;
+ while (0 == p_atu->EtherMacLow)
+ {
+ if (WaitCallback)
+ (*WaitCallback)();
+
+ for (i = 0; i < 1000; i++)
+ ;
+
+ if (!timeout--)
+ {
+ printk("rc_getmac: Timeout\n");
+ return RC_RTN_MSG_REPLY_TIMEOUT;
+ }
+ }
+
+ /* read the mac address */
+ temp[0] = p_atu->EtherMacLow;
+ temp[1] = p_atu->EtherMacHi;
+ memcpy((char *)mac, (char *)temp, 6);
+
+
+#ifdef RCDEBUG
+// printk("rc_getmac: 0x%X\n", ptr);
+#endif /* RCDEBUG */
+
+ return RC_RTN_NO_ERROR;
+}
+
+
+/*
+** =========================================================================
+** RCSetMAC()
+**
+** set MAC address the adapter is listening for in non-promiscous mode.
+** MAC address is in media format.
+** =========================================================================
+*/
+RC_RETURN
+RCSetMAC(U16 AdapterID, PU8 mac)
+{
+ U32 off;
+ PU32 pMsg;
+ PPAB pPab;
+
+
+ pPab = PCIAdapterBlock[AdapterID];
+
+ if (pPab == NULL)
+ return RC_RTN_ADPTR_NOT_REGISTERED;
+
+ off = pPab->p_atu->InQueue; /* get addresss of message */
+
+ if (0xFFFFFFFF == off)
+ return RC_RTN_FREE_Q_EMPTY;
+
+ pMsg = (PU32)(pPab->pPci45LinBaseAddr + off);
+
+ /* setup private message */
+ pMsg[0] = SEVEN_WORD_MSG_SIZE | SGL_OFFSET_0;
+ pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID;
+ pMsg[2] = 0; /* initiator context */
+ pMsg[3] = 0x219; /* transaction context */
+ pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_SET_MAC_ADDR;
+ pMsg[5] = *(unsigned *)mac; /* first four bytes */
+ pMsg[6] = *(unsigned *)(mac + 4); /* last two bytes */
+
+ pPab->p_atu->InQueue = off; /* send it to the I2O device */
+
+ return RC_RTN_NO_ERROR ;
+}
+
+
+/*
+** =========================================================================
+** RCSetLinkSpeed()
+**
+** set ethernet link speed.
+** input: speedControl - determines action to take as follows
+** 0 = reset and auto-negotiate (NWay)
+** 1 = Full Duplex 100BaseT
+** 2 = Half duplex 100BaseT
+** 3 = Full Duplex 10BaseT
+** 4 = Half duplex 10BaseT
+** all other values are ignore (do nothing)
+** =========================================================================
+*/
+RC_RETURN
+RCSetLinkSpeed(U16 AdapterID, U16 LinkSpeedCode)
+{
+ U32 off;
+ PU32 pMsg;
+ PPAB pPab;
+
+
+ pPab =PCIAdapterBlock[AdapterID];
+
+ if (pPab == NULL)
+ return RC_RTN_ADPTR_NOT_REGISTERED;
+
+ off = pPab->p_atu->InQueue; /* get addresss of message */
+
+ if (0xFFFFFFFF == off)
+ return RC_RTN_FREE_Q_EMPTY;
+
+ pMsg = (PU32)(pPab->pPci45LinBaseAddr + off);
+
+ /* setup private message */
+ pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0;
+ pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID;
+ pMsg[2] = 0; /* initiator context */
+ pMsg[3] = 0x219; /* transaction context */
+ pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_SET_LINK_SPEED;
+ pMsg[5] = LinkSpeedCode; /* link speed code */
+
+ pPab->p_atu->InQueue = off; /* send it to the I2O device */
+
+ return RC_RTN_NO_ERROR ;
+}
+/*
+** =========================================================================
+** RCSetPromiscuousMode()
+**
+** Defined values for Mode:
+** 0 - turn off promiscuous mode
+** 1 - turn on promiscuous mode
+**
+** =========================================================================
+*/
+RC_RETURN
+RCSetPromiscuousMode(U16 AdapterID, U16 Mode)
+{
+ U32 off;
+ PU32 pMsg;
+ PPAB pPab;
+
+ pPab =PCIAdapterBlock[AdapterID];
+
+ if (pPab == NULL)
+ return RC_RTN_ADPTR_NOT_REGISTERED;
+
+ off = pPab->p_atu->InQueue; /* get addresss of message */
+
+ if (0xFFFFFFFF == off)
+ return RC_RTN_FREE_Q_EMPTY;
+
+ pMsg = (PU32)(pPab->pPci45LinBaseAddr + off);
+
+ /* setup private message */
+ pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0;
+ pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID;
+ pMsg[2] = 0; /* initiator context */
+ pMsg[3] = 0x219; /* transaction context */
+ pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_SET_PROMISCUOUS_MODE;
+ pMsg[5] = Mode; /* promiscuous mode setting */
+
+ pPab->p_atu->InQueue = off; /* send it to the device */
+
+ return RC_RTN_NO_ERROR ;
+}
+/*
+** =========================================================================
+** RCGetPromiscuousMode()
+**
+** get promiscuous mode setting
+**
+** Possible return values placed in pMode:
+** 0 = promisuous mode not set
+** 1 = promisuous mode is set
+**
+** =========================================================================
+*/
+RC_RETURN
+RCGetPromiscuousMode(U16 AdapterID, PU32 pMode, PFNWAITCALLBACK WaitCallback)
+{
+ U32 msgOffset, timeout;
+ PU32 pMsg;
+ volatile PU32 p32;
+ PPAB pPab;
+
+ pPab =PCIAdapterBlock[AdapterID];
+
+
+ msgOffset = pPab->p_atu->InQueue;
+
+
+ if (msgOffset == 0xFFFFFFFF)
+ {
+ kprintf("RCGetLinkSpeed(): Inbound Free Q empty!\n");
+ return RC_RTN_FREE_Q_EMPTY;
+ }
+
+ /* calc virtual address of msg - virtual already mapped to physical */
+ pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset);
+
+ /* virtual pointer to return buffer - clear first two dwords */
+ p32 = (volatile PU32)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB));
+ p32[0] = 0xff;
+
+ /* setup private message */
+ pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0;
+ pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID;
+ pMsg[2] = 0; /* initiator context */
+ pMsg[3] = 0x219; /* transaction context */
+ pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_PROMISCUOUS_MODE;
+ /* phys address to return status - area right after PAB */
+ pMsg[5] = pPab->outMsgBlockPhyAddr - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB);
+
+ /* post to Inbound Post Q */
+
+ pPab->p_atu->InQueue = msgOffset;
+
+ /* wait for response */
+ timeout = 1000000;
+ while(1)


+ {
+ int i;
+

+ if (WaitCallback)
+ (*WaitCallback)();
+
+ for (i = 0; i < 1000; i++) /* please don't hog the bus!!! */
+ ;
+
+ if (p32[0] != 0xff)
+ break;
+
+ if (!timeout--)
+ {
+ kprintf("Timeout waiting for promiscuous mode from adapter\n");
+ kprintf("0x%08.8ulx\n", p32[0]);
+ return RC_RTN_NO_LINK_SPEED;
+ }
+ }
+
+ /* get mode */
+ *pMode = (U8)((volatile PU8)p32)[0] & 0x0f;
+
+ return RC_RTN_NO_ERROR;
+}
+/*
+** =========================================================================
+** RCSetBroadcastMode()
+**
+** Defined values for Mode:
+** 0 - turn off promiscuous mode
+** 1 - turn on promiscuous mode
+**
+** =========================================================================
+*/
+RC_RETURN
+RCSetBroadcastMode(U16 AdapterID, U16 Mode)
+{
+ U32 off;
+ PU32 pMsg;
+ PPAB pPab;
+
+ pPab =PCIAdapterBlock[AdapterID];
+
+ if (pPab == NULL)
+ return RC_RTN_ADPTR_NOT_REGISTERED;
+
+ off = pPab->p_atu->InQueue; /* get addresss of message */
+
+ if (0xFFFFFFFF == off)
+ return RC_RTN_FREE_Q_EMPTY;
+
+ pMsg = (PU32)(pPab->pPci45LinBaseAddr + off);
+
+ /* setup private message */
+ pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0;
+ pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID;
+ pMsg[2] = 0; /* initiator context */
+ pMsg[3] = 0x219; /* transaction context */
+ pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_SET_BROADCAST_MODE;
+ pMsg[5] = Mode; /* promiscuous mode setting */
+
+ pPab->p_atu->InQueue = off; /* send it to the device */
+
+ return RC_RTN_NO_ERROR ;
+}
+/*
+** =========================================================================
+** RCGetBroadcastMode()
+**
+** get promiscuous mode setting
+**
+** Possible return values placed in pMode:
+** 0 = promisuous mode not set
+** 1 = promisuous mode is set
+**
+** =========================================================================
+*/
+RC_RETURN
+RCGetBroadcastMode(U16 AdapterID, PU32 pMode, PFNWAITCALLBACK WaitCallback)
+{
+ U32 msgOffset, timeout;
+ PU32 pMsg;
+ volatile PU32 p32;
+ PPAB pPab;
+
+ pPab =PCIAdapterBlock[AdapterID];
+
+
+ msgOffset = pPab->p_atu->InQueue;
+
+
+ if (msgOffset == 0xFFFFFFFF)
+ {
+ kprintf("RCGetLinkSpeed(): Inbound Free Q empty!\n");
+ return RC_RTN_FREE_Q_EMPTY;
+ }
+
+ /* calc virtual address of msg - virtual already mapped to physical */
+ pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset);
+
+ /* virtual pointer to return buffer - clear first two dwords */
+ p32 = (volatile PU32)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB));
+ p32[0] = 0xff;
+
+ /* setup private message */
+ pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0;
+ pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID;
+ pMsg[2] = 0; /* initiator context */
+ pMsg[3] = 0x219; /* transaction context */
+ pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_BROADCAST_MODE;
+ /* phys address to return status - area right after PAB */
+ pMsg[5] = pPab->outMsgBlockPhyAddr - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB);
+
+ /* post to Inbound Post Q */
+
+ pPab->p_atu->InQueue = msgOffset;
+
+ /* wait for response */
+ timeout = 1000000;
+ while(1)


+ {
+ int i;
+

+ if (WaitCallback)
+ (*WaitCallback)();
+
+ for (i = 0; i < 1000; i++) /* please don't hog the bus!!! */
+ ;
+
+ if (p32[0] != 0xff)
+ break;
+
+ if (!timeout--)
+ {
+ kprintf("Timeout waiting for promiscuous mode from adapter\n");
+ kprintf("0x%08.8ulx\n", p32[0]);
+ return RC_RTN_NO_LINK_SPEED;
+ }
+ }
+
+ /* get mode */
+ *pMode = (U8)((volatile PU8)p32)[0] & 0x0f;
+
+ return RC_RTN_NO_ERROR;
+}
+
+/*
+** =========================================================================
+** RCGetLinkSpeed()
+**
+** get ethernet link speed.
+**
+** 0 = Unknown
+** 1 = Full Duplex 100BaseT
+** 2 = Half duplex 100BaseT
+** 3 = Full Duplex 10BaseT
+** 4 = Half duplex 10BaseT
+**
+** =========================================================================
+*/
+RC_RETURN
+RCGetLinkSpeed(U16 AdapterID, PU32 pLinkSpeedCode, PFNWAITCALLBACK WaitCallback)
+{
+ U32 msgOffset, timeout;
+ PU32 pMsg;
+ volatile PU32 p32;
+ U8 IOPLinkSpeed;
+ PPAB pPab;
+
+ pPab =PCIAdapterBlock[AdapterID];
+
+
+ msgOffset = pPab->p_atu->InQueue;
+
+
+ if (msgOffset == 0xFFFFFFFF)
+ {
+ kprintf("RCGetLinkSpeed(): Inbound Free Q empty!\n");
+ return RC_RTN_FREE_Q_EMPTY;
+ }
+
+ /* calc virtual address of msg - virtual already mapped to physical */
+ pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset);
+
+ /* virtual pointer to return buffer - clear first two dwords */
+ p32 = (volatile PU32)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB));
+ p32[0] = 0xff;
+
+ /* setup private message */
+ pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0;
+ pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID;
+ pMsg[2] = 0; /* initiator context */
+ pMsg[3] = 0x219; /* transaction context */
+ pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_LINK_SPEED;
+ /* phys address to return status - area right after PAB */
+ pMsg[5] = pPab->outMsgBlockPhyAddr - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB);
+
+ /* post to Inbound Post Q */
+
+ pPab->p_atu->InQueue = msgOffset;
+
+ /* wait for response */
+ timeout = 1000000;
+ while(1)


+ {
+ int i;
+

+ if (WaitCallback)
+ (*WaitCallback)();
+
+ for (i = 0; i < 1000; i++) /* please don't hog the bus!!! */
+ ;
+
+ if (p32[0] != 0xff)
+ break;
+
+ if (!timeout--)
+ {
+ kprintf("Timeout waiting for link speed from IOP\n");
+ kprintf("0x%08.8ulx\n", p32[0]);
+ return RC_RTN_NO_LINK_SPEED;
+ }
+ }
+
+ /* get Link speed */
+ IOPLinkSpeed = (U8)((volatile PU8)p32)[0] & 0x0f;
+
+ *pLinkSpeedCode= IOPLinkSpeed;
+
+ return RC_RTN_NO_ERROR;
+}
+
+/*
+** =========================================================================
+** RCReportDriverCapability(U16 AdapterID, U32 capability)
+**
+** Currently defined bits:
+** WARM_REBOOT_CAPABLE 0x01
+**
+** =========================================================================
+*/
+RC_RETURN
+RCReportDriverCapability(U16 AdapterID, U32 capability)
+{
+ U32 off;
+ PU32 pMsg;
+ PPAB pPab;
+
+ pPab =PCIAdapterBlock[AdapterID];
+
+ if (pPab == NULL)
+ return RC_RTN_ADPTR_NOT_REGISTERED;
+
+ off = pPab->p_atu->InQueue; /* get addresss of message */
+
+ if (0xFFFFFFFF == off)
+ return RC_RTN_FREE_Q_EMPTY;
+
+ pMsg = (PU32)(pPab->pPci45LinBaseAddr + off);
+
+ /* setup private message */
+ pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0;
+ pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID;
+ pMsg[2] = 0; /* initiator context */
+ pMsg[3] = 0x219; /* transaction context */
+ pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_REPORT_DRIVER_CAPABILITY;
+ pMsg[5] = capability;
+
+ pPab->p_atu->InQueue = off; /* send it to the I2O device */
+
+ return RC_RTN_NO_ERROR ;
+}
+
+/*
+** =========================================================================
+** RCGetFirmwareVer()
+**
+** Return firmware version in the form "SoftwareVersion : Bt BootVersion"
+**
+** =========================================================================
+*/
+RC_RETURN
+RCGetFirmwareVer(U16 AdapterID, PU8 pFirmString, PFNWAITCALLBACK WaitCallback)


SHAR_EOF
true || echo 'restore of patch-2.0.37 failed'
fi

echo 'End of part 12'
echo 'File patch-2.0.37 is continued in part 13'
echo 13 > _shar_seq_.tmp

Thomas...@ciw.uni-karlsruhe.de

unread,
Jun 16, 1999, 3:00:00 AM6/16/99
to
Archive-name: v2.0/patch-2.0.37/part14

#!/bin/sh
# this is part 14 of a 45 - part archive


# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.0.37 continued
if test ! -r _shar_seq_.tmp; then
echo 'Please unpack part 1 first!'
exit 1
fi
(read Scheck

if test "$Scheck" != 14; then


echo Please unpack part "$Scheck" next!
exit 1
else
exit 0
fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.0.37'
else
echo 'x - continuing with patch-2.0.37'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.0.37' &&

-#define RC_PRIVATE_SET_MAC_ADDR 0x0002
-#define RC_PRIVATE_GET_LAN_STATS 0x0003
-#define RC_PRIVATE_GET_LINK_STATUS 0x0004
-#define RC_PRIVATE_SET_LINK_SPEED 0x0005
-#define RC_PRIVATE_SET_IP_AND_MASK 0x0006
-/* #define RC_PRIVATE_GET_IP_AND_MASK 0x0007 */ /* OBSOLETE */
-#define RC_PRIVATE_GET_LINK_SPEED 0x0008
-#define RC_PRIVATE_GET_FIRMWARE_REV 0x0009
-/* #define RC_PRIVATE_GET_MAC_ADDR 0x000A *//**/
-#define RC_PRIVATE_GET_IP_AND_MASK 0x000B /**/
-#define RC_PRIVATE_DEBUG_MSG 0x000C
-#define RC_PRIVATE_REPORT_DRIVER_CAPABILITY 0x000D
-
-#define RC_PRIVATE_REBOOT 0x00FF
-
-
-/* RC message header */
-typedef struct _RC_MSG_FRAME
-{
- U8 VersionOffset;
- U8 MsgFlags;
- U16 MessageSize;
- BF TargetAddress:TID_SZ;
- BF InitiatorAddress:TID_SZ;
- BF Function:FUNCTION_SZ;
- U32 InitiatorContext;
- /* SGL[] */
-}
- RC_MSG_FRAME, *PRC_MSG_FRAME;
-
-
- /* assumed a 16K minus 256 byte space for outbound queue message frames */
-#define MSG_FRAME_SIZE 512
-#define NMBR_MSG_FRAMES 30
-
-/*
-** Message Unit CSR definitions for RedCreek PCI45 board
-*/
-typedef struct tag_rcatu
-{
- volatile unsigned long APICRegSel; /* APIC Register Select */
- volatile unsigned long reserved0;
- volatile unsigned long APICWinReg; /* APIC Window Register */
- volatile unsigned long reserved1;
- volatile unsigned long InMsgReg0; /* inbound message register 0 */
- volatile unsigned long InMsgReg1; /* inbound message register 1 */
- volatile unsigned long OutMsgReg0; /* outbound message register 0 */
- volatile unsigned long OutMsgReg1; /* outbound message register 1 */
- volatile unsigned long InDoorReg; /* inbound doorbell register */
- volatile unsigned long InIntStat; /* inbound interrupt status register */
- volatile unsigned long InIntMask; /* inbound interrupt mask register */
- volatile unsigned long OutDoorReg; /* outbound doorbell register */
- volatile unsigned long OutIntStat; /* outbound interrupt status register */
- volatile unsigned long OutIntMask; /* outbound interrupt mask register */
- volatile unsigned long reserved2;
- volatile unsigned long reserved3;
- volatile unsigned long InQueue; /* inbound queue port */
- volatile unsigned long OutQueue; /* outbound queue port */
- volatile unsigned long reserved4;
- volatile unsigned long reserver5;
- /* RedCreek extension */
- volatile unsigned long EtherMacLow;
- volatile unsigned long EtherMacHi;
- volatile unsigned long IPaddr;
- volatile unsigned long IPmask;
-}
- ATU, *PATU;
-
- /*
- ** typedef PAB
- **
- ** PCI Adapter Block - holds instance specific information and is located
- ** in a reserved space at the start of the message buffer allocated by user.
- */
-typedef struct
-{
- PATU p_atu; /* ptr to ATU register block */
- PU8 pPci45LinBaseAddr;
- PU8 pLinOutMsgBlock;
- U32 outMsgBlockPhyAddr;
- PFNTXCALLBACK pTransCallbackFunc;
- PFNRXCALLBACK pRecvCallbackFunc;
- PFNCALLBACK pRebootCallbackFunc;
- PFNCALLBACK pCallbackFunc;
- U16 ADAPTERState;
- U16 InboundMFrameSize;
-}
- PAB, *PPAB;
-
- /*
- ** in reserved space right after PAB in host memory is area for returning
- ** values from card
- */
-
- /*
- ** Array of pointers to PCI Adapter Blocks.
- ** Indexed by a zero based (0-31) interface number.
- */
-#define MAX_ADAPTERS 32
-static PPAB PCIAdapterBlock[MAX_ADAPTERS] =
-{
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
-};
-
-
-/*
-** typedef NICSTAT
-**
-** Data structure for NIC statistics retruned from PCI card. Data copied from
-** here to user allocated RCLINKSTATS (see rclanmtl.h) structure.
-*/
-typedef struct tag_NicStat
-{
- unsigned long TX_good;
- unsigned long TX_maxcol;
- unsigned long TX_latecol;
- unsigned long TX_urun;
- unsigned long TX_crs; /* lost carrier sense */
- unsigned long TX_def; /* transmit deferred */
- unsigned long TX_singlecol; /* single collisions */
- unsigned long TX_multcol;
- unsigned long TX_totcol;
- unsigned long Rcv_good;
- unsigned long Rcv_CRCerr;
- unsigned long Rcv_alignerr;
- unsigned long Rcv_reserr; /* rnr'd pkts */
- unsigned long Rcv_orun;
- unsigned long Rcv_cdt;
- unsigned long Rcv_runt;
- unsigned long dump_status; /* last field directly from the chip */
-}
- NICSTAT, *P_NICSTAT;
-
-
-#define DUMP_DONE 0x0000A005 /* completed statistical dump */
-#define DUMP_CLEAR 0x0000A007 /* completed stat dump and clear counters */
-
-
-static volatile int msgFlag;
-
-
-/* local function prototypes */
-static void ProcessOutboundAdapterMsg(PPAB pPab, U32 phyMsgAddr);
-static int FillAdapterMsgSGLFromTCB(PU32 pMsg, PRCTCB pXmitCntrlBlock);
-static int GetAdapterStatus(PPAB pPab);
-static int SendAdapterOutboundQInitMsg(PPAB pPab);
-static int SendEnableSysMsg(PPAB pPab);
-
-
- /* 1st 100h bytes of message block is reserved for messenger instance */
-#define ADAPTER_BLOCK_RESERVED_SPACE 0x100
-
-/*
-** =========================================================================
-** InitRCApiMsgLayer()
-**
-** Initialize the RedCreek API Module and adapter.
-**
-** Inputs: AdapterID - interface number from 0 to 15
-** pciBaseAddr - virual base address of PCI (set by BIOS)
-** p_msgbuf - virual address to private message block (min. 16K)
-** p_phymsgbuf - physical address of private message block
-** TransmitCallbackFunction - address of transmit callback function
-** ReceiveCallbackFunction - address of receive callback function
-**
-** private message block is allocated by user. It must be in locked pages.
-** p_msgbuf and p_phymsgbuf point to the same location. Must be contigous
-** memory block of a minimum of 16K byte and long word aligned.
-** =========================================================================
-*/
-RC_RETURN
-InitRCApiMsgLayer(U16 AdapterID, U32 pciBaseAddr,
- PU8 p_msgbuf, PU8 p_phymsgbuf,
- PFNTXCALLBACK TransmitCallbackFunction,
- PFNRXCALLBACK ReceiveCallbackFunction,
- PFNCALLBACK RebootCallbackFunction)
-{
- int result;
- PPAB pPab;
-
-#ifdef DEBUG
- kprintf("InitAPI: Adapter:0x%04.4ux ATU:0x%08.8ulx msgbuf:0x%08.8ulx phymsgbuf:0x%08.8ulx\n"
- "TransmitCallbackFunction:0x%08.8ulx ReceiveCallbackFunction:0x%08.8ulx\n",
- AdapterID, pciBaseAddr, p_msgbuf, p_phymsgbuf, TransmitCallbackFunction, ReceiveCallbackFunction);
-#endif /* DEBUG */
-
-
- /* Check if this interface already initialized - if so, shut it down */
- if (PCIAdapterBlock[AdapterID] != NULL)
- {
- printk("PCIAdapterBlock[%d]!=NULL\n", AdapterID);
-// RCResetLANCard(AdapterID, 0, (PU32)NULL, (PFNCALLBACK)NULL);
- PCIAdapterBlock[AdapterID] = NULL;
- }
-
- /*
- ** store adapter instance values in adapter block.
- ** Adapter block is at beginning of message buffer
- */
- pPab = (PPAB)p_msgbuf;
-
- pPab->p_atu = (PATU)pciBaseAddr;
- pPab->pPci45LinBaseAddr = (PU8)pciBaseAddr;
-
- /* Set outbound message frame addr - skip over Adapter Block */
- pPab->outMsgBlockPhyAddr = (U32)(p_phymsgbuf + ADAPTER_BLOCK_RESERVED_SPACE);
- pPab->pLinOutMsgBlock = (PU8)(p_msgbuf + ADAPTER_BLOCK_RESERVED_SPACE);
-
- /* store callback function addresses */
- pPab->pTransCallbackFunc = TransmitCallbackFunction;
- pPab->pRecvCallbackFunc = ReceiveCallbackFunction;
- pPab->pRebootCallbackFunc = RebootCallbackFunction;
- pPab->pCallbackFunc = (PFNCALLBACK)NULL;
-
- /*
- ** Initialize API
- */
- result = GetAdapterStatus(pPab);
-
- if (result != RC_RTN_NO_ERROR)
- return result;
-
- if (pPab->ADAPTERState == ADAPTER_STATE_OPERATIONAL)
- {
- printk("pPab->ADAPTERState == op: resetting adapter\n");
- RCResetLANCard(AdapterID, 0, (PU32)NULL, (PFNCALLBACK)NULL);
- }
-
- result = SendAdapterOutboundQInitMsg(pPab);
-
- if (result != RC_RTN_NO_ERROR)
- return result;
-
- result = SendEnableSysMsg(pPab);
-
- if (result != RC_RTN_NO_ERROR)
- return result;
-
- PCIAdapterBlock[AdapterID] = pPab;
- return RC_RTN_NO_ERROR;
-}
-
-/*
-** =========================================================================
-** Disable and Enable Adapter interrupts. Adapter interrupts are enabled at Init time
-** but can be disabled and re-enabled through these two function calls.
-** Packets will still be put into any posted received buffers and packets will
-** be sent through RCSendPacket() functions. Disabling Adapter interrupts
-** will prevent hardware interrupt to host even though the outbound Adapter msg
-** queue is not emtpy.
-** =========================================================================
-*/
-#define i960_OUT_POST_Q_INT_BIT 0x0008 /* bit set masks interrupts */
-
-RC_RETURN RCDisableAdapterInterrupts(U16 AdapterID)
-{
- PPAB pPab;
-
-
- pPab = PCIAdapterBlock[AdapterID];
-
- if (pPab == NULL)
- return RC_RTN_ADPTR_NOT_REGISTERED;
-
- pPab->p_atu->OutIntMask |= i960_OUT_POST_Q_INT_BIT;
-
- return RC_RTN_NO_ERROR;
-}
-
-RC_RETURN RCEnableAdapterInterrupts(U16 AdapterID)
-{
- PPAB pPab;
-
- pPab = PCIAdapterBlock[AdapterID];
-
- if (pPab == NULL)
- return RC_RTN_ADPTR_NOT_REGISTERED;
-
- pPab->p_atu->OutIntMask &= ~i960_OUT_POST_Q_INT_BIT;
-
- return RC_RTN_NO_ERROR;
-
-}
-
-
-/*
-** =========================================================================
-** RCSendPacket()
-** =========================================================================
-*/
-RC_RETURN
-RCSendPacket(U16 AdapterID, U32 InitiatorContext, PRCTCB pTransCtrlBlock)
-{
- U32 msgOffset;
- PU32 pMsg;
- int size;
- PPAB pPab;
-
-#ifdef DEBUG
-kprintf("RCSendPacket()...\n");
-#endif /* DEBUG */
-
- pPab = PCIAdapterBlock[AdapterID];
-
- if (pPab == NULL)
- return RC_RTN_ADPTR_NOT_REGISTERED;
-
- /* get Inbound free Q entry - reading from In Q gets free Q entry */
- /* offset to Msg Frame in PCI msg block */
-
- msgOffset = pPab->p_atu->InQueue;
-
- if (msgOffset == 0xFFFFFFFF)
- {
-#ifdef DEBUG
- kprintf("RCSendPacket(): Inbound Free Q empty!\n");
-#endif /* DEBUG */
- return RC_RTN_FREE_Q_EMPTY;
- }
-
- /* calc virual address of msg - virual already mapped to physical */
- pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset);
-
- size = FillAdapterMsgSGLFromTCB(pMsg + 4, pTransCtrlBlock);
-
- if (size == -1) /* error processing TCB - send NOP msg */
- {
-#ifdef DEBUG
- kprintf("RCSendPacket(): Error Rrocess TCB!\n");
-#endif /* DEBUG */
- pMsg[0] = THREE_WORD_MSG_SIZE | SGL_OFFSET_0;
- pMsg[1] = UTIL_NOP << 24 | HOST_TID << 12 | LAN_TARGET_ID;
- return RC_RTN_TCB_ERROR;
- }
- else /* send over msg header */
- {
- pMsg[0] = (size + 4) << 16 | LAN_MSG_REQST; /* send over message size and flags */
- pMsg[1] = LAN_PACKET_SEND << 24 | HOST_TID << 12 | LAN_TARGET_ID;
- pMsg[2] = InitiatorContext;
- pMsg[3] = 0; /* batch reply */
- /* post to Inbound Post Q */
- pPab->p_atu->InQueue = msgOffset;
- return RC_RTN_NO_ERROR;
- }
-}
-
-
-/*
-** =========================================================================
-** RCPostRecvBuffer()
-**
-** inputs: pBufrCntrlBlock - pointer to buffer control block
-**
-** returns TRUE if successful in sending message, else FALSE.
-** =========================================================================
-*/
-RC_RETURN
-RCPostRecvBuffers(U16 AdapterID, PRCTCB pTransCtrlBlock)
-{
- U32 msgOffset;
- PU32 pMsg;
- int size;
- PPAB pPab;
-
-#ifdef DEBUG
-kprintf("RCPostRecvBuffers()...\n");
-#endif /* DEBUG */
-
- /* search for DeviceHandle */
- pPab = PCIAdapterBlock[AdapterID];
-
- if (pPab == NULL)
- return RC_RTN_ADPTR_NOT_REGISTERED;
-
-
- /* get Inbound free Q entry - reading from In Q gets free Q entry */
- /* offset to Msg Frame in PCI msg block */
- msgOffset = pPab->p_atu->InQueue;
-
- if (msgOffset == 0xFFFFFFFF)
- {
-#ifdef DEBUG
- kprintf("RCPostRecvBuffers(): Inbound Free Q empty!\n");
-#endif /* DEBUG */
- return RC_RTN_FREE_Q_EMPTY;
-
- }
- /* calc virual address of msg - virual already mapped to physical */
- pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset);
-
- size = FillAdapterMsgSGLFromTCB(pMsg + 4, pTransCtrlBlock);
-
- if (size == -1) /* error prcessing TCB - send 3 DWORD private msg == NOP */
- {
-#ifdef DEBUG
- kprintf("RCPostRecvBuffers(): Error Processing TCB! size = %d\n", size);
-#endif /* DEBUG */
- pMsg[0] = THREE_WORD_MSG_SIZE | SGL_OFFSET_0;
- pMsg[1] = UTIL_NOP << 24 | HOST_TID << 12 | LAN_TARGET_ID;
- /* post to Post Q */
- pPab->p_atu->InQueue = msgOffset;
- return RC_RTN_TCB_ERROR;
- }
- else /* send over size msg header */
- {
- pMsg[0] = (size + 4) << 16 | LAN_MSG_REQST; /* send over message size and flags */
- pMsg[1] = LAN_RECEIVE_POST << 24 | HOST_TID << 12 | LAN_TARGET_ID;
- pMsg[2] = DEFAULT_RECV_INIT_CONTEXT;
- pMsg[3] = *(PU32)pTransCtrlBlock; /* number of packet buffers */
- /* post to Post Q */
- pPab->p_atu->InQueue = msgOffset;
- return RC_RTN_NO_ERROR;
- }
-}
-
-
-/*
-** =========================================================================
-** RCProcMsgQ()
-**
-** Process outbound message queue until empty.
-** =========================================================================
-*/
-void
-RCProcMsgQ(U16 AdapterID)
-{
- U32 phyAddrMsg;
- PU8 p8Msg;
- PU32 p32;
- U16 count;
- PPAB pPab;
- unsigned char debug_msg[20];
-
- pPab = PCIAdapterBlock[AdapterID];
-
- if (pPab == NULL)
- return;
-
- phyAddrMsg = pPab->p_atu->OutQueue;
-
- while (phyAddrMsg != 0xFFFFFFFF)
- {
- p8Msg = pPab->pLinOutMsgBlock + (phyAddrMsg - pPab->outMsgBlockPhyAddr);
- p32 = (PU32)p8Msg;
-
- //printk(" msg: 0x%x 0x%x \n", p8Msg[7], p32[5]);
-
- /*
- ** Send Packet Reply Msg
- */
- if (LAN_PACKET_SEND == p8Msg[7]) /* function code byte */
- {
- count = *(PU16)(p8Msg+2);
- count -= p8Msg[0] >> 4;
- /* status, count, context[], adapter */
- (*pPab->pTransCallbackFunc)(p8Msg[19], count, p32+5, AdapterID);
- }
- /*
- ** Receive Packet Reply Msg */
- else if (LAN_RECEIVE_POST == p8Msg[7])
- {
-#ifdef DEBUG
- kprintf("RECV_REPLY pPab:0x%08.8ulx p8Msg:0x%08.8ulx p32:0x%08.8ulx\n", pPab, p8Msg, p32);
- kprintf("msg: 0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx\n",
- p32[0], p32[1], p32[2], p32[3]);
- kprintf(" 0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx\n",
- p32[4], p32[5], p32[6], p32[7]);
- kprintf(" 0x%08.8ulx:0X%08.8ulx:0x%08.8ulx:0x%08.8ulx\n",
- p32[8], p32[9], p32[10], p32[11]);
-#endif
- /* status, count, buckets remaining, packetParmBlock, adapter */
- (*pPab->pRecvCallbackFunc)(p8Msg[19], p8Msg[12], p32[5], p32+6, AdapterID);
-
-
- }
- else if (LAN_RESET == p8Msg[7] || LAN_SHUTDOWN == p8Msg[7])
- {
- if (pPab->pCallbackFunc)
- {
- (*pPab->pCallbackFunc)(p8Msg[19],0,0,AdapterID);
- }
- else
- {
- pPab->pCallbackFunc = (PFNCALLBACK) 1;
- }
- //PCIAdapterBlock[AdapterID] = 0;
- }
- else if (RC_PRIVATE == p8Msg[7])
- {
- //printk("i2o private 0x%x, 0x%x \n", p8Msg[7], p32[5]);
- switch (p32[5])
- {
- case RC_PRIVATE_DEBUG_MSG:
- msgFlag = 1;
- /*printk("Received RC_PRIVATE msg\n");*/
- debug_msg[15] = (p32[6]&0xff000000) >> 24;
- debug_msg[14] = (p32[6]&0x00ff0000) >> 16;
- debug_msg[13] = (p32[6]&0x0000ff00) >> 8;
- debug_msg[12] = (p32[6]&0x000000ff);
-
- debug_msg[11] = (p32[7]&0xff000000) >> 24;
- debug_msg[10] = (p32[7]&0x00ff0000) >> 16;
- debug_msg[ 9] = (p32[7]&0x0000ff00) >> 8;
- debug_msg[ 8] = (p32[7]&0x000000ff);
-
- debug_msg[ 7] = (p32[8]&0xff000000) >> 24;
- debug_msg[ 6] = (p32[8]&0x00ff0000) >> 16;
- debug_msg[ 5] = (p32[8]&0x0000ff00) >> 8;
- debug_msg[ 4] = (p32[8]&0x000000ff);
-
- debug_msg[ 3] = (p32[9]&0xff000000) >> 24;
- debug_msg[ 2] = (p32[9]&0x00ff0000) >> 16;
- debug_msg[ 1] = (p32[9]&0x0000ff00) >> 8;
- debug_msg[ 0] = (p32[9]&0x000000ff);
-
- debug_msg[16] = '\0';
- printk (debug_msg);
- break;
- case RC_PRIVATE_REBOOT:
- printk("Adapter reboot initiated...\n");
- if (pPab->pRebootCallbackFunc)
- {
- (*pPab->pRebootCallbackFunc)(0,0,0,AdapterID);
- }
- break;
- default:
- printk("Unknown private msg received: 0x%x\n",
- p32[5]);
- break;
- }
- }
-
- /*
- ** Process other Msg's
- */
- else
- {
- ProcessOutboundAdapterMsg(pPab, phyAddrMsg);
- }
-
- /* return MFA to outbound free Q*/
- pPab->p_atu->OutQueue = phyAddrMsg;
-
- /* any more msgs? */
- phyAddrMsg = pPab->p_atu->OutQueue;
- }
-}
-
-
-/*
-** =========================================================================
-** Returns LAN interface statistical counters to space provided by caller at
-** StatsReturnAddr. Returns 0 if success, else RC_RETURN code.
-** This function will call the WaitCallback function provided by
-** user while waiting for card to respond.
-** =========================================================================
-*/
-RC_RETURN
-RCGetLinkStatistics(U16 AdapterID,
- P_RCLINKSTATS StatsReturnAddr,
- PFNWAITCALLBACK WaitCallback)
-{
- U32 msgOffset;
- volatile U32 timeout;
- volatile PU32 pMsg;
- volatile PU32 p32, pReturnAddr;
- P_NICSTAT pStats;
- int i;
- PPAB pPab;
-
-/*kprintf("Get82558Stats() StatsReturnAddr:0x%08.8ulx\n", StatsReturnAddr);*/
-
- pPab = PCIAdapterBlock[AdapterID];
-
- if (pPab == NULL)
- return RC_RTN_ADPTR_NOT_REGISTERED;
-
- msgOffset = pPab->p_atu->InQueue;
-
- if (msgOffset == 0xFFFFFFFF)
- {
- #ifdef DEBUG
- kprintf("Get8255XStats(): Inbound Free Q empty!\n");
- #endif
- return RC_RTN_FREE_Q_EMPTY;
- }
-
- /* calc virual address of msg - virual already mapped to physical */
- pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset);
-
-/*dprintf("Get82558Stats - pMsg = 0x%08ulx, InQ msgOffset = 0x%08ulx\n", pMsg, msgOffset);*/
-/*dprintf("Get82558Stats - pMsg = 0x%08X, InQ msgOffset = 0x%08X\n", pMsg, msgOffset);*/
-
- pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0;
- pMsg[1] = RC_PRIVATE << 24 | HOST_TID << 12 | LAN_TARGET_ID;
- pMsg[2] = DEFAULT_RECV_INIT_CONTEXT;
- pMsg[3] = 0x112; /* transaction context */
- pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_LAN_STATS;
- pMsg[5] = pPab->outMsgBlockPhyAddr - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB);
-
- p32 = (PU32)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB));
-
- pStats = (P_NICSTAT)p32;
- pStats->dump_status = 0xFFFFFFFF;
-
- /* post to Inbound Post Q */
- pPab->p_atu->InQueue = msgOffset;
-
- timeout = 100000;
- while (1)
- {
- if (WaitCallback)
- (*WaitCallback)();
-
- for (i = 0; i < 1000; i++)
- ;
-
- if (pStats->dump_status != 0xFFFFFFFF)
- break;
-
- if (!timeout--)
- {
- #ifdef DEBUG
- kprintf("RCGet82558Stats() Timeout waiting for NIC statistics\n");
- #endif
- return RC_RTN_MSG_REPLY_TIMEOUT;
- }
- }
-
- pReturnAddr = (PU32)StatsReturnAddr;
-
- /* copy Nic stats to user's structure */
- for (i = 0; i < (int) sizeof(RCLINKSTATS) / 4; i++)
- pReturnAddr[i] = p32[i];
-
- return RC_RTN_NO_ERROR;
-}
-
-
-/*
-** =========================================================================
-** Get82558LinkStatus()
-** =========================================================================
-*/
-RC_RETURN
-RCGetLinkStatus(U16 AdapterID, PU32 ReturnAddr, PFNWAITCALLBACK WaitCallback)
-{
- U32 msgOffset;
- volatile U32 timeout;
- volatile PU32 pMsg;
- volatile PU32 p32;
- PPAB pPab;
-
-/*kprintf("Get82558LinkStatus() ReturnPhysAddr:0x%08.8ulx\n", ReturnAddr);*/
-
- pPab = PCIAdapterBlock[AdapterID];
-
- if (pPab == NULL)
- return RC_RTN_ADPTR_NOT_REGISTERED;
-
- msgOffset = pPab->p_atu->InQueue;
-
- if (msgOffset == 0xFFFFFFFF)
- {
- #ifdef DEBUG
- dprintf("Get82558LinkStatus(): Inbound Free Q empty!\n");
- #endif
- return RC_RTN_FREE_Q_EMPTY;
- }
-
- /* calc virual address of msg - virual already mapped to physical */
- pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset);
-/*dprintf("Get82558LinkStatus - pMsg = 0x%08ulx, InQ msgOffset = 0x%08ulx\n", pMsg, msgOffset);*/
-/*dprintf("Get82558LinkStatus - pMsg = 0x%08X, InQ msgOffset = 0x%08X\n", pMsg, msgOffset);*/
-
- pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0;
- pMsg[1] = RC_PRIVATE << 24 | HOST_TID << 12 | LAN_TARGET_ID;
- pMsg[2] = DEFAULT_RECV_INIT_CONTEXT;
- pMsg[3] = 0x112; /* transaction context */
- pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_LINK_STATUS;
- pMsg[5] = pPab->outMsgBlockPhyAddr - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB);
-
- p32 = (PU32)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB));
- *p32 = 0xFFFFFFFF;
-
- /* post to Inbound Post Q */
- pPab->p_atu->InQueue = msgOffset;
-
- timeout = 100000;
- while (1)
- {
- U32 i;
-
- if (WaitCallback)
- (*WaitCallback)();
-
- for (i = 0; i < 1000; i++)
- ;
-
- if (*p32 != 0xFFFFFFFF)
- break;
-
- if (!timeout--)
- {
- #ifdef DEBUG
- kprintf("Timeout waiting for link status\n");
- #endif
- return RC_RTN_MSG_REPLY_TIMEOUT;
- }
- }
-
- *ReturnAddr = *p32; /* 1 = up 0 = down */
-
- return RC_RTN_NO_ERROR;
-
-}
-
-/*
-** =========================================================================
-** RCGetMAC()
-**
-** get the MAC address the adapter is listening for in non-promiscous mode.
-** MAC address is in media format.
-** =========================================================================
-*/
-RC_RETURN
-RCGetMAC(U16 AdapterID, PU8 mac, PFNWAITCALLBACK WaitCallback)
-{
- unsigned i, timeout;
- U32 off;
- PU32 p;
- U32 temp[2];
- PPAB pPab;
- PATU p_atu;
-
- pPab = PCIAdapterBlock[AdapterID];
-
- if (pPab == NULL)
- return RC_RTN_ADPTR_NOT_REGISTERED;
-
- p_atu = pPab->p_atu;
-
- p_atu->EtherMacLow = 0; /* first zero return data */
- p_atu->EtherMacHi = 0;
-
- off = p_atu->InQueue; /* get addresss of message */
-
- if (0xFFFFFFFF == off)
- return RC_RTN_FREE_Q_EMPTY;
-
- p = (PU32)(pPab->pPci45LinBaseAddr + off);
-
-#ifdef RCDEBUG
- printk("RCGetMAC: p_atu 0x%08x, off 0x%08x, p 0x%08x\n",
- (uint)p_atu, (uint)off, (uint)p);
-#endif /* RCDEBUG */
- /* setup private message */
- p[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0;
- p[1] = RC_PRIVATE << 24 | HOST_TID << 12 | LAN_TARGET_ID;
- p[2] = 0; /* initiator context */
- p[3] = 0x218; /* transaction context */
- p[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_MAC_ADDR;
-
-
- p_atu->InQueue = off; /* send it to the device */
-#ifdef RCDEBUG
- printk("RCGetMAC: p_atu 0x%08x, off 0x%08x, p 0x%08x\n",
- (uint)p_atu, (uint)off, (uint)p);
-#endif /* RCDEBUG */
-
- /* wait for the rcpci45 board to update the info */
- timeout = 1000000;
- while (0 == p_atu->EtherMacLow)
- {
- if (WaitCallback)
- (*WaitCallback)();
-
- for (i = 0; i < 1000; i++)
- ;
-
- if (!timeout--)
- {
- printk("rc_getmac: Timeout\n");
- return RC_RTN_MSG_REPLY_TIMEOUT;
- }
- }
-
- /* read the mac address */
- temp[0] = p_atu->EtherMacLow;
- temp[1] = p_atu->EtherMacHi;
- memcpy((char *)mac, (char *)temp, 6);
-
-
-#ifdef RCDEBUG
-// printk("rc_getmac: 0x%X\n", ptr);
-#endif /* RCDEBUG */
-
- return RC_RTN_NO_ERROR;
-}
-
-
-/*
-** =========================================================================
-** RCSetMAC()
-**
-** set MAC address the adapter is listening for in non-promiscous mode.
-** MAC address is in media format.
-** =========================================================================
-*/
-RC_RETURN
-RCSetMAC(U16 AdapterID, PU8 mac)
-{
- U32 off;
- PU32 pMsg;
- PPAB pPab;
-
-
- pPab = PCIAdapterBlock[AdapterID];
-
- if (pPab == NULL)
- return RC_RTN_ADPTR_NOT_REGISTERED;
-
- off = pPab->p_atu->InQueue; /* get addresss of message */
-
- if (0xFFFFFFFF == off)
- return RC_RTN_FREE_Q_EMPTY;
-
- pMsg = (PU32)(pPab->pPci45LinBaseAddr + off);
-
- /* setup private message */
- pMsg[0] = SEVEN_WORD_MSG_SIZE | SGL_OFFSET_0;
- pMsg[1] = RC_PRIVATE << 24 | HOST_TID << 12 | LAN_TARGET_ID;
- pMsg[2] = 0; /* initiator context */
- pMsg[3] = 0x219; /* transaction context */
- pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_SET_MAC_ADDR;
- pMsg[5] = *(unsigned *)mac; /* first four bytes */
- pMsg[6] = *(unsigned *)(mac + 4); /* last two bytes */
-
- pPab->p_atu->InQueue = off; /* send it to the device */
-
- return RC_RTN_NO_ERROR ;
-}
-
-
-/*
-** =========================================================================
-** RCSetLinkSpeed()
-**
-** set ethernet link speed.
-** input: speedControl - determines action to take as follows
-** 0 = reset and auto-negotiate (NWay)
-** 1 = Full Duplex 100BaseT
-** 2 = Half duplex 100BaseT
-** 3 = Full Duplex 10BaseT
-** 4 = Half duplex 10BaseT
-** all other values are ignore (do nothing)
-** =========================================================================
-*/
-RC_RETURN
-RCSetLinkSpeed(U16 AdapterID, U16 LinkSpeedCode)
-{
- U32 off;
- PU32 pMsg;
- PPAB pPab;
-
-
- pPab =PCIAdapterBlock[AdapterID];
-
- if (pPab == NULL)
- return RC_RTN_ADPTR_NOT_REGISTERED;
-
- off = pPab->p_atu->InQueue; /* get addresss of message */
-
- if (0xFFFFFFFF == off)
- return RC_RTN_FREE_Q_EMPTY;
-
- pMsg = (PU32)(pPab->pPci45LinBaseAddr + off);
-
- /* setup private message */
- pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0;
- pMsg[1] = RC_PRIVATE << 24 | HOST_TID << 12 | LAN_TARGET_ID;
- pMsg[2] = 0; /* initiator context */
- pMsg[3] = 0x219; /* transaction context */
- pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_SET_LINK_SPEED;
- pMsg[5] = LinkSpeedCode; /* link speed code */
-
- pPab->p_atu->InQueue = off; /* send it to the device */
-
- return RC_RTN_NO_ERROR ;
-}
-
-/*
-** =========================================================================
-** RCGetLinkSpeed()
-**
-** get ethernet link speed.
-**
-** 0 = Unknown
-** 1 = Full Duplex 100BaseT
-** 2 = Half duplex 100BaseT
-** 3 = Full Duplex 10BaseT
-** 4 = Half duplex 10BaseT
-**
-** =========================================================================
-*/
-RC_RETURN
-RCGetLinkSpeed(U16 AdapterID, PU32 pLinkSpeedCode, PFNWAITCALLBACK WaitCallback)
-{
- U32 msgOffset, timeout;
- PU32 pMsg;
- volatile PU32 p32;
- U8 AdapterLinkSpeed;
- PPAB pPab;
-
- pPab =PCIAdapterBlock[AdapterID];
-
-
- msgOffset = pPab->p_atu->InQueue;
-
-
- if (msgOffset == 0xFFFFFFFF)
- {
- kprintf("RCGetLinkSpeed(): Inbound Free Q empty!\n");
- return RC_RTN_FREE_Q_EMPTY;
- }
-
- /* calc virtual address of msg - virtual already mapped to physical */
- pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset);
-
- /* virtual pointer to return buffer - clear first two dwords */
- p32 = (volatile PU32)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB));
- p32[0] = 0xff;
-
- /* setup private message */
- pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0;
- pMsg[1] = RC_PRIVATE << 24 | HOST_TID << 12 | LAN_TARGET_ID;
- pMsg[2] = 0; /* initiator context */
- pMsg[3] = 0x219; /* transaction context */
- pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_LINK_SPEED;
- /* phys address to return status - area right after PAB */
- pMsg[5] = pPab->outMsgBlockPhyAddr - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB);
-
- /* post to Inbound Post Q */
-
- pPab->p_atu->InQueue = msgOffset;
-
- /* wait for response */
- timeout = 1000000;
- while(1)
- {
- int i;
-
- if (WaitCallback)
- (*WaitCallback)();
-
- for (i = 0; i < 1000; i++) /* please don't hog the bus!!! */
- ;
-
- if (p32[0] != 0xff)
- break;
-
- if (!timeout--)
- {
- kprintf("Timeout waiting for link speed from adapter\n");
- kprintf("0x%08.8ulx\n", p32[0]);
- return RC_RTN_NO_LINK_SPEED;
- }
- }
-
- /* get Link speed */
- AdapterLinkSpeed = (U8)((volatile PU8)p32)[0] & 0x0f;
-
- *pLinkSpeedCode= AdapterLinkSpeed;
-
- return RC_RTN_NO_ERROR;
-}
-
-/*
-** =========================================================================
-** RCReportDriverCapability(U16 AdapterID, U32 capability)
-**
-** Currently defined bits:
-** WARM_REBOOT_CAPABLE 0x01
-**
-** =========================================================================
-*/
-RC_RETURN
-RCReportDriverCapability(U16 AdapterID, U32 capability)
-{
- U32 off;
- PU32 pMsg;
- PPAB pPab;
-
- pPab =PCIAdapterBlock[AdapterID];
-
- if (pPab == NULL)
- return RC_RTN_ADPTR_NOT_REGISTERED;
-
- off = pPab->p_atu->InQueue; /* get addresss of message */
-
- if (0xFFFFFFFF == off)
- return RC_RTN_FREE_Q_EMPTY;
-
- pMsg = (PU32)(pPab->pPci45LinBaseAddr + off);
-
- /* setup private message */
- pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0;
- pMsg[1] = RC_PRIVATE << 24 | HOST_TID << 12 | LAN_TARGET_ID;
- pMsg[2] = 0; /* initiator context */
- pMsg[3] = 0x219; /* transaction context */
- pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_REPORT_DRIVER_CAPABILITY;
- pMsg[5] = capability;
-
- pPab->p_atu->InQueue = off; /* send it to the device */
-
- return RC_RTN_NO_ERROR ;
-}
-
-/*
-** =========================================================================
-** RCGetFirmwareVer()
-**
-** Return firmware version in the form "SoftwareVersion : Bt BootVersion"
-**
-** =========================================================================
-*/
-RC_RETURN
-RCGetFirmwareVer(U16 AdapterID, PU8 pFirmString, PFNWAITCALLBACK WaitCallback)
-{
- U32 msgOffset, timeout;
- PU32 pMsg;
- volatile PU32 p32;
- PPAB pPab;
-
- pPab =PCIAdapterBlock[AdapterID];
-
- msgOffset = pPab->p_atu->InQueue;
-
-
- if (msgOffset == 0xFFFFFFFF)
- {
- kprintf("RCGetFirmwareVer(): Inbound Free Q empty!\n");
- return RC_RTN_FREE_Q_EMPTY;
- }
-
- /* calc virtual address of msg - virtual already mapped to physical */
- pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset);
-
- /* virtual pointer to return buffer - clear first two dwords */
- p32 = (volatile PU32)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB));
- p32[0] = 0xff;
-
- /* setup private message */
- pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0;
- pMsg[1] = RC_PRIVATE << 24 | HOST_TID << 12 | LAN_TARGET_ID;
- pMsg[2] = 0; /* initiator context */
- pMsg[3] = 0x219; /* transaction context */
- pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_FIRMWARE_REV;
- /* phys address to return status - area right after PAB */
- pMsg[5] = pPab->outMsgBlockPhyAddr - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB);
-
-
-
- /* post to Inbound Post Q */
-
- pPab->p_atu->InQueue = msgOffset;
-
-
- /* wait for response */
- timeout = 1000000;
- while(1)
- {
- int i;
-
- if (WaitCallback)
- (*WaitCallback)();
-
- for (i = 0; i < 1000; i++) /* please don't hog the bus!!! */
- ;
-
- if (p32[0] != 0xff)
- break;
-
- if (!timeout--)
- {
- kprintf("Timeout waiting for link speed from adapter\n");
- return RC_RTN_NO_FIRM_VER;
- }
- }
-
- strcpy(pFirmString, (PU8)p32);
- return RC_RTN_NO_ERROR;
-}
-
-/*
-** =========================================================================
-** RCResetLANCard()
-**
-** ResourceFlags indicates whether to return buffer resource explicitly
-** to host or keep and reuse.
-** CallbackFunction (if not NULL) is the function to be called when
-** reset is complete.
-** If CallbackFunction is NULL, ReturnAddr will have a 1 placed in it when
-** reset is done (if not NULL).
-**
-** =========================================================================
-*/
-RC_RETURN
-RCResetLANCard(U16 AdapterID, U16 ResourceFlags, PU32 ReturnAddr, PFNCALLBACK CallbackFunction)
-{
- unsigned long off;
- unsigned long *pMsg;
- PPAB pPab;
- int i;
- long timeout = 0;
-
-
- pPab =PCIAdapterBlock[AdapterID];
-
- if (pPab == NULL)
- return RC_RTN_ADPTR_NOT_REGISTERED;
-
- off = pPab->p_atu->InQueue; /* get addresss of message */
-
- if (0xFFFFFFFF == off)
- return RC_RTN_FREE_Q_EMPTY;
-
- pPab->pCallbackFunc = CallbackFunction;
-
- pMsg = (PU32)(pPab->pPci45LinBaseAddr + off);
-
- /* setup message */
- pMsg[0] = FOUR_WORD_MSG_SIZE | SGL_OFFSET_0;
- pMsg[1] = LAN_RESET << 24 | HOST_TID << 12 | LAN_TARGET_ID;
- pMsg[2] = DEFAULT_RECV_INIT_CONTEXT;
- pMsg[3] = ResourceFlags << 16; /* resource flags */
-
- pPab->p_atu->InQueue = off; /* send it to the device */
-
- if (CallbackFunction == (PFNCALLBACK)NULL)
- {
- /* call RCProcMsgQ() until something in pPab->pCallbackFunc
- or until timer goes off */
- while (pPab->pCallbackFunc == (PFNCALLBACK)NULL)
- {
- RCProcMsgQ(AdapterID);
- for (i = 0; i < 100000; i++) /* please don't hog the bus!!! */
- ;
- timeout++;
- if (timeout > 10000)


- {
- break;
- }
- }

- if (ReturnAddr != (PU32)NULL)
- *ReturnAddr = (U32)pPab->pCallbackFunc;
- }
-
- return RC_RTN_NO_ERROR ;
-}
-/*
-** =========================================================================
-** RCResetAdapter()
-**
-** Send StatusGet Msg, wait for results return directly to buffer.
-**
-** =========================================================================
-*/
-RC_RETURN
-RCResetAdapter(U16 AdapterID)
-{
- U32 msgOffset, timeout;
- PU32 pMsg;
- PPAB pPab;
- volatile PU32 p32;
-
- pPab = PCIAdapterBlock[AdapterID];
- msgOffset = pPab->p_atu->InQueue;
-
- if (msgOffset == 0xFFFFFFFF)
- {
- return RC_RTN_FREE_Q_EMPTY;
- }
-
- /* calc virtual address of msg - virtual already mapped to physical */
- pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset);
-
- pMsg[0] = NINE_WORD_MSG_SIZE | SGL_OFFSET_0;
- pMsg[1] = RC_CMD_ADAPTER_RESET << 24 | HOST_TID << 12 | ADAPTER_TID;
- pMsg[2] = 0; /* universal context */
- pMsg[3] = 0; /* universal context */
- pMsg[4] = 0; /* universal context */
- pMsg[5] = 0; /* universal context */
- /* phys address to return status - area right after PAB */
- pMsg[6] = pPab->outMsgBlockPhyAddr - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB);
- pMsg[7] = 0;
- pMsg[8] = 1; /* return 1 byte */
-
- /* virual pointer to return buffer - clear first two dwords */
- p32 = (volatile PU32)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB));
- p32[0] = 0;
- p32[1] = 0;
-
- /* post to Inbound Post Q */
-
- pPab->p_atu->InQueue = msgOffset;
-
- /* wait for response */
- timeout = 1000000;
- while(1)
- {
- int i;
-
- for (i = 0; i < 1000; i++) /* please don't hog the bus!!! */
- ;
-
- if (p32[0] || p32[1])
- break;
-
- if (!timeout--)
- {
- printk("RCResetAdapter timeout\n");
- return RC_RTN_MSG_REPLY_TIMEOUT;
- }
- }
- return RC_RTN_NO_ERROR;
-}
-
-/*
-** =========================================================================
-** RCShutdownLANCard()
-**
-** ResourceFlags indicates whether to return buffer resource explicitly
-** to host or keep and reuse.
-** CallbackFunction (if not NULL) is the function to be called when
-** shutdown is complete.
-** If CallbackFunction is NULL, ReturnAddr will have a 1 placed in it when
-** shutdown is done (if not NULL).
-**
-** =========================================================================
-*/
-RC_RETURN
-RCShutdownLANCard(U16 AdapterID, U16 ResourceFlags, PU32 ReturnAddr, PFNCALLBACK CallbackFunction)
-{
- volatile PU32 pMsg;
- U32 off;
- PPAB pPab;
- int i;
- long timeout = 0;
-
- pPab = PCIAdapterBlock[AdapterID];
-
- if (pPab == NULL)
- return RC_RTN_ADPTR_NOT_REGISTERED;
-
- off = pPab->p_atu->InQueue; /* get addresss of message */
-
- if (0xFFFFFFFF == off)
- return RC_RTN_FREE_Q_EMPTY;
-
- pPab->pCallbackFunc = CallbackFunction;
-
- pMsg = (PU32)(pPab->pPci45LinBaseAddr + off);
-
- /* setup message */
- pMsg[0] = FOUR_WORD_MSG_SIZE | SGL_OFFSET_0;
- pMsg[1] = LAN_SHUTDOWN << 24 | HOST_TID << 12 | LAN_TARGET_ID;
- pMsg[2] = DEFAULT_RECV_INIT_CONTEXT;
- pMsg[3] = ResourceFlags << 16; /* resource flags */
-
- pPab->p_atu->InQueue = off; /* send it to the device */
-
- if (CallbackFunction == (PFNCALLBACK)NULL)
- {
- /* call RCProcMsgQ() until something in pPab->pCallbackFunc
- or until timer goes off */
- while (pPab->pCallbackFunc == (PFNCALLBACK)NULL)
- {
- RCProcMsgQ(AdapterID);
- for (i = 0; i < 100000; i++) /* please don't hog the bus!!! */
- ;
- timeout++;
- if (timeout > 10000)


- {
- break;
- }
- }

- if (ReturnAddr != (PU32)NULL)
- *ReturnAddr = (U32)pPab->pCallbackFunc;
- }
- return RC_RTN_NO_ERROR ;
-}
-
-
-/*
-** =========================================================================
-** RCSetRavlinIPandMask()
-**
-** Set the Ravlin 45/PCI cards IP address and network mask.
-**
-** IP address and mask must be in network byte order.
-** For example, IP address 1.2.3.4 and mask 255.255.255.0 would be
-** 0x04030201 and 0x00FFFFFF on a little endian machine.
-**
-** =========================================================================
-*/
-RC_RETURN
-RCSetRavlinIPandMask(U16 AdapterID, U32 ipAddr, U32 netMask)
-{
- volatile PU32 pMsg;
- U32 off;
- PPAB pPab;
-
- pPab = PCIAdapterBlock[AdapterID];
-
- if (pPab == NULL)
- return RC_RTN_ADPTR_NOT_REGISTERED;
-
- off = pPab->p_atu->InQueue; /* get addresss of message */
-
- if (0xFFFFFFFF == off)
- return RC_RTN_FREE_Q_EMPTY;
-
- pMsg = (PU32)(pPab->pPci45LinBaseAddr + off);
-
- /* setup private message */
- pMsg[0] = SEVEN_WORD_MSG_SIZE | SGL_OFFSET_0;
- pMsg[1] = RC_PRIVATE << 24 | HOST_TID << 12 | LAN_TARGET_ID;
- pMsg[2] = 0; /* initiator context */
- pMsg[3] = 0x219; /* transaction context */
- pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_SET_IP_AND_MASK;
- pMsg[5] = ipAddr;
- pMsg[6] = netMask;
-
-
- pPab->p_atu->InQueue = off; /* send it to the device */
- return RC_RTN_NO_ERROR ;
-
-}
-
-/*
-** =========================================================================
-** RCGetRavlinIPandMask()
-**
-** get the IP address and MASK from the card
-**
-** =========================================================================
-*/
-RC_RETURN
-RCGetRavlinIPandMask(U16 AdapterID, PU32 pIpAddr, PU32 pNetMask,
- PFNWAITCALLBACK WaitCallback)
-{
- unsigned i, timeout;
- U32 off;
- PU32 pMsg, p32;
- PPAB pPab;
- PATU p_atu;
-
-#ifdef DEBUG
- kprintf("RCGetRavlinIPandMask: pIpAddr is 0x%08.8ulx, *IpAddr is 0x%08.8ulx\n", pIpAddr, *pIpAddr);
-#endif /* DEBUG */
-
- pPab = PCIAdapterBlock[AdapterID];
-
- if (pPab == NULL)
- return RC_RTN_ADPTR_NOT_REGISTERED;
-
- p_atu = pPab->p_atu;
- off = p_atu->InQueue; /* get addresss of message */
-
- if (0xFFFFFFFF == off)
- return RC_RTN_FREE_Q_EMPTY;
-
- p32 = (volatile PU32)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB));
- *p32 = 0xFFFFFFFF;
-
- pMsg = (PU32)(pPab->pPci45LinBaseAddr + off);
-
-#ifdef DEBUG
- kprintf("RCGetRavlinIPandMask: p_atu 0x%08.8ulx, off 0x%08.8ulx, p32 0x%08.8ulx\n", p_atu, off, p32);
-#endif /* DEBUG */
- /* setup private message */
- pMsg[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0;
- pMsg[1] = RC_PRIVATE << 24 | HOST_TID << 12 | LAN_TARGET_ID;
- pMsg[2] = 0; /* initiator context */
- pMsg[3] = 0x218; /* transaction context */
- pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_IP_AND_MASK;
- pMsg[5] = pPab->outMsgBlockPhyAddr - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB);
-
- p_atu->InQueue = off; /* send it to the device */
-#ifdef DEBUG
- kprintf("RCGetRavlinIPandMask: p_atu 0x%08.8ulx, off 0x%08.8ulx, p32 0x%08.8ulx\n", p_atu, off, p32);
-#endif /* DEBUG */
-
- /* wait for the rcpci45 board to update the info */
- timeout = 100000;
- while (0xffffffff == *p32)
- {
- if (WaitCallback)
- (*WaitCallback)();
-
- for (i = 0; i < 1000; i++)
- ;
-
- if (!timeout--)
- {
- #ifdef DEBUG
- kprintf("RCGetRavlinIPandMask: Timeout\n");
- #endif /* DEBUG */
- return RC_RTN_MSG_REPLY_TIMEOUT;
- }
- }
-
-#ifdef DEBUG
- kprintf("RCGetRavlinIPandMask: after time out\n", \
- "p32[0] (IpAddr) 0x%08.8ulx, p32[1] (IPmask) 0x%08.8ulx\n", p32[0], p32[1]);
-#endif /* DEBUG */
-
- /* send IP and mask to user's space */
- *pIpAddr = p32[0];
- *pNetMask = p32[1];
-
-
-#ifdef DEBUG
- kprintf("RCGetRavlinIPandMask: pIpAddr is 0x%08.8ulx, *IpAddr is 0x%08.8ulx\n", pIpAddr, *pIpAddr);
-#endif /* DEBUG */
-
- return RC_RTN_NO_ERROR;
-}
-
-/*
-** /////////////////////////////////////////////////////////////////////////
-** /////////////////////////////////////////////////////////////////////////
-**
-** local functions
-**
-** /////////////////////////////////////////////////////////////////////////
-** /////////////////////////////////////////////////////////////////////////
-*/
-
-/*
-** =========================================================================
-** SendAdapterOutboundQInitMsg()
-**
-** =========================================================================
-*/
-static int
-SendAdapterOutboundQInitMsg(PPAB pPab)
-{
- U32 msgOffset, timeout, phyOutQFrames, i;
- volatile PU32 pMsg;
- volatile PU32 p32;
-
-
-
- msgOffset = pPab->p_atu->InQueue;
-
-
- if (msgOffset == 0xFFFFFFFF)
- {
-#ifdef DEBUG
- kprintf("SendAdapterOutboundQInitMsg(): Inbound Free Q empty!\n");
-#endif /* DEBUG */
- return RC_RTN_FREE_Q_EMPTY;
- }
-
-
- /* calc virual address of msg - virual already mapped to physical */
- pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset);
-
-#ifdef DEBUG
-kprintf("SendAdapterOutboundQInitMsg - pMsg = 0x%08.8ulx, InQ msgOffset = 0x%08.8ulx\n", pMsg, msgOffset);
-#endif /* DEBUG */
-
- pMsg[0] = EIGHT_WORD_MSG_SIZE | TRL_OFFSET_6;
- pMsg[1] = RC_CMD_OUTBOUND_INIT << 24 | HOST_TID << 12 | ADAPTER_TID;
- pMsg[2] = DEFAULT_RECV_INIT_CONTEXT;
- pMsg[3] = 0x106; /* transaction context */
- pMsg[4] = 4096; /* Host page frame size */
- pMsg[5] = MSG_FRAME_SIZE << 16 | 0x80; /* outbound msg frame size and Initcode */
- pMsg[6] = 0xD0000004; /* simple sgl element LE, EOB */
- /* phys address to return status - area right after PAB */
- pMsg[7] = pPab->outMsgBlockPhyAddr - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB);
-
- /* virual pointer to return buffer - clear first two dwords */
- p32 = (PU32)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB));
- p32[0] = 0;
-
- /* post to Inbound Post Q */
- pPab->p_atu->InQueue = msgOffset;
-
- /* wait for response */
- timeout = 100000;
- while(1)
- {
- for (i = 0; i < 1000; i++) /* please don't hog the bus!!! */
- ;
-
- if (p32[0])
- break;
-
- if (!timeout--)
- {
-#ifdef DEBUG
- kprintf("Timeout wait for InitOutQ InPrgress status from adapter\n");
-#endif /* DEBUG */
- return RC_RTN_NO_STATUS;
- }
- }
-
- timeout = 100000;
- while(1)
- {
- for (i = 0; i < 1000; i++) /* please don't hog the bus!!! */
- ;
-
- if (p32[0] == RC_CMD_OUTBOUND_INIT_COMPLETE)
- break;
-
- if (!timeout--)
- {
-#ifdef DEBUG
- kprintf("Timeout wait for InitOutQ Complete status from adapter\n");
-#endif /* DEBUG */
- return RC_RTN_NO_STATUS;
- }
- }
-
- /* load PCI outbound free Q with MF physical addresses */
- phyOutQFrames = pPab->outMsgBlockPhyAddr;
-
- for (i = 0; i < NMBR_MSG_FRAMES; i++)
- {
- pPab->p_atu->OutQueue = phyOutQFrames;
- phyOutQFrames += MSG_FRAME_SIZE;
- }
- return RC_RTN_NO_ERROR;
-}
-
-
-/*
-** =========================================================================
-** GetAdapterStatus()
-**
-** Send StatusGet Msg, wait for results return directly to buffer.
-**
-** =========================================================================
-*/
-static int
-GetAdapterStatus(PPAB pPab)
-{
- U32 msgOffset, timeout;
- PU32 pMsg;
- volatile PU32 p32;
-
-
- msgOffset = pPab->p_atu->InQueue;
- printk("GetAdapterStatus: msg offset = 0x%x\n", msgOffset);
- if (msgOffset == 0xFFFFFFFF)
- {
-#ifdef DEBUG
- kprintf("GetAdapterStatus(): Inbound Free Q empty!\n");
-#endif /* DEBUG */
- return RC_RTN_FREE_Q_EMPTY;
- }
-
- /* calc virual address of msg - virual already mapped to physical */
- pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset);
-
- pMsg[0] = NINE_WORD_MSG_SIZE | SGL_OFFSET_0;
- pMsg[1] = RC_CMD_STATUS_GET << 24 | HOST_TID << 12 | ADAPTER_TID;
- pMsg[2] = 0; /* universal context */
- pMsg[3] = 0; /* universal context */
- pMsg[4] = 0; /* universal context */
- pMsg[5] = 0; /* universal context */
- /* phys address to return status - area right after PAB */
- pMsg[6] = pPab->outMsgBlockPhyAddr - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB);
- pMsg[7] = 0;
- pMsg[8] = 88; /* return 88 bytes */
-
- /* virual pointer to return buffer - clear first two dwords */
- p32 = (volatile PU32)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB));
- p32[0] = 0;
- p32[1] = 0;
-
-#ifdef DEBUG
-kprintf("GetAdapterStatus - pMsg:0x%08.8ulx, msgOffset:0x%08.8ulx, [1]:0x%08.8ulx, [6]:0x%08.8ulx\n",
- pMsg, msgOffset, pMsg[1], pMsg[6]);
-#endif /* DEBUG */
-
- /* post to Inbound Post Q */
- pPab->p_atu->InQueue = msgOffset;
-
-#ifdef DEBUG
-kprintf("Return status to p32 = 0x%08.8ulx\n", p32);
-#endif /* DEBUG */
-
- /* wait for response */
- timeout = 1000000;
- while(1)
- {
- int i;
-
- for (i = 0; i < 1000; i++) /* please don't hog the bus!!! */
- ;
-
- if (p32[0] && p32[1])
- break;
-
- if (!timeout--)
- {
-#ifdef DEBUG
- kprintf("Timeout waiting for status from adapter\n");
-kprintf("0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx\n", p32[0], p32[1], p32[2], p32[3]);
-kprintf("0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx\n", p32[4], p32[5], p32[6], p32[7]);
-kprintf("0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx\n", p32[8], p32[9], p32[10], p32[11]);
-#endif /* DEBUG */
- return RC_RTN_NO_STATUS;
- }
- }
-
-#ifdef DEBUG
-kprintf("0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx\n", p32[0], p32[1], p32[2], p32[3]);
-kprintf("0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx\n", p32[4], p32[5], p32[6], p32[7]);
-kprintf("0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx\n", p32[8], p32[9], p32[10], p32[11]);
-#endif /* DEBUG */
- /* get adapter state */
- pPab->ADAPTERState = ((volatile PU8)p32)[10];
- pPab->InboundMFrameSize = ((volatile PU16)p32)[6];
-
-#ifdef DEBUG
- kprintf("adapter state 0x%02.2x InFrameSize = 0x%04.4x\n",
- pPab->ADAPTERState, pPab->InboundMFrameSize);
-#endif /* DEBUG */
- return RC_RTN_NO_ERROR;
-}
-
-
-/*
-** =========================================================================
-** SendEnableSysMsg()
-**
-**
-** =========================================================================
-*/
-static int
-SendEnableSysMsg(PPAB pPab)
-{
- U32 msgOffset; // timeout;
- volatile PU32 pMsg;
-
- msgOffset = pPab->p_atu->InQueue;
-
- if (msgOffset == 0xFFFFFFFF)
- {
-#ifdef DEBUG
- kprintf("SendEnableSysMsg(): Inbound Free Q empty!\n");
-#endif /* DEBUG */
- return RC_RTN_FREE_Q_EMPTY;
- }
-
- /* calc virual address of msg - virual already mapped to physical */
- pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset);
-
-#ifdef DEBUG
-kprintf("SendEnableSysMsg - pMsg = 0x%08.8ulx, InQ msgOffset = 0x%08.8ulx\n", pMsg, msgOffset);
-#endif /* DEBUG */
-
- pMsg[0] = FOUR_WORD_MSG_SIZE | SGL_OFFSET_0;
- pMsg[1] = RC_CMD_SYS_ENABLE << 24 | HOST_TID << 12 | ADAPTER_TID;
- pMsg[2] = DEFAULT_RECV_INIT_CONTEXT;
- pMsg[3] = 0x110; /* transaction context */
- pMsg[4] = 0x50657465; /* RedCreek Private */
-
- /* post to Inbound Post Q */
- pPab->p_atu->InQueue = msgOffset;
-
- return RC_RTN_NO_ERROR;
-}
-
-
-/*
-** =========================================================================
-** FillI12OMsgFromTCB()
-**
-** inputs pMsgU32 - virual pointer (mapped to physical) of message frame
-** pXmitCntrlBlock - pointer to caller buffer control block.
-**
-** fills in LAN SGL after Transaction Control Word or Bucket Count.
-** =========================================================================
-*/
-static int
-FillAdapterMsgSGLFromTCB(PU32 pMsgFrame, PRCTCB pTransCtrlBlock)
-{
- unsigned int nmbrBuffers, nmbrSeg, nmbrDwords, context, flags;
- PU32 pTCB, pMsg;
-
- /* SGL element flags */
-#define EOB 0x40000000
-#define LE 0x80000000
-#define SIMPLE_SGL 0x10000000
-#define BC_PRESENT 0x01000000
-
- pTCB = (PU32)pTransCtrlBlock;
- pMsg = pMsgFrame;
- nmbrDwords = 0;
-
-#ifdef DEBUG
- kprintf("FillAdapterMsgSGLFromTCBX\n");
-kprintf("TCB 0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx\n",
- pTCB[0], pTCB[1], pTCB[2], pTCB[3], pTCB[4]);
-kprintf("pTCB 0x%08.8ulx, pMsg 0x%08.8ulx\n", pTCB, pMsg);
-#endif /* DEBUG */
-
- nmbrBuffers = *pTCB++;
-
- if (!nmbrBuffers)
- {
- return -1;
- }
-
- do
- {
- context = *pTCB++; /* buffer tag (context) */
- nmbrSeg = *pTCB++; /* number of segments */
-
- if (!nmbrSeg)
- {
- return -1;
- }
-
- flags = SIMPLE_SGL | BC_PRESENT;
-
- if (1 == nmbrSeg)
- {
- flags |= EOB;
-
- if (1 == nmbrBuffers)
- flags |= LE;
- }
-
- /* 1st SGL buffer element has context */
- pMsg[0] = pTCB[0] | flags ; /* send over count (segment size) */
- pMsg[1] = context;
- pMsg[2] = pTCB[1]; /* send buffer segment physical address */
- nmbrDwords += 3;
- pMsg += 3;
- pTCB += 2;
-
-
- if (--nmbrSeg)
- {
- do
- {
- flags = SIMPLE_SGL;
-
- if (1 == nmbrSeg)
- {
- flags |= EOB;
-
- if (1 == nmbrBuffers)
- flags |= LE;
- }
-
- pMsg[0] = pTCB[0] | flags; /* send over count */
- pMsg[1] = pTCB[1]; /* send buffer segment physical address */
- nmbrDwords += 2;
- pTCB += 2;
- pMsg += 2;
-
- } while (--nmbrSeg);
- }
-
- } while (--nmbrBuffers);
-
- return nmbrDwords;
-}
-
-
-/*
-** =========================================================================
-** ProcessOutboundAdapterMsg()
-**
-** process reply message
-** * change to msg structure *
-** =========================================================================
-*/
-static void
-ProcessOutboundAdapterMsg(PPAB pPab, U32 phyAddrMsg)
-{
- PU8 p8Msg;
- PU32 p32;
- // U16 count;
-
-
- p8Msg = pPab->pLinOutMsgBlock + (phyAddrMsg - pPab->outMsgBlockPhyAddr);
- p32 = (PU32)p8Msg;
-
-#ifdef DEBUG
- kprintf("VXD: ProcessOutboundAdapterMsg - pPab 0x%08.8ulx, phyAdr 0x%08.8ulx, linAdr 0x%08.8ulx\n", pPab, phyAddrMsg, p8Msg);
- kprintf("msg :0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx\n", p32[0], p32[1], p32[2], p32[3]);
- kprintf("msg :0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx\n", p32[4], p32[5], p32[6], p32[7]);
-#endif /* DEBUG */
-
- if (p32[4] >> 24 != RC_REPLY_STATUS_SUCCESS)
- {
-#ifdef DEBUG
- kprintf("Message reply status not success\n");
-#endif /* DEBUG */
- return;
- }
-
- switch (p8Msg[7] ) /* function code byte */
- {
- case RC_CMD_SYS_TAB_SET:
- msgFlag = 1;
-#ifdef DEBUG
- kprintf("Received RC_CMD_SYS_TAB_SET reply\n");
-#endif /* DEBUG */
- break;
-
- case RC_CMD_HRT_GET:
- msgFlag = 1;
-#ifdef DEBUG
- kprintf("Received RC_CMD_HRT_GET reply\n");
-#endif /* DEBUG */
- break;
-
- case RC_CMD_LCT_NOTIFY:
- msgFlag = 1;
-#ifdef DEBUG
- kprintf("Received RC_CMD_LCT_NOTIFY reply\n");
-#endif /* DEBUG */
- break;
-
- case RC_CMD_SYS_ENABLE:
- msgFlag = 1;
-#ifdef DEBUG
- kprintf("Received RC_CMD_SYS_ENABLE reply\n");
-#endif /* DEBUG */
- break;
-
- default:
-#ifdef DEBUG
- kprintf("Received UNKNOWN reply\n");
-#endif /* DEBUG */
- break;
- }
-}
diff -u --recursive --new-file v2.0.36/linux/drivers/net/rcmtl.h linux/drivers/net/rcmtl.h
--- v2.0.36/linux/drivers/net/rcmtl.h Sun Nov 15 21:51:46 1998
+++ linux/drivers/net/rcmtl.h Wed Dec 31 16:00:00 1969
@@ -1,580 +0,0 @@
-/*
-** *************************************************************************
-**
-**
-** R C M T L . H $Revision: 3 $
-**
-**
-** RedCreek Message Transport Layer header file.
-**
-** ---------------------------------------------------------------------
-** --- Copyright (c) 1997-1998, RedCreek Communications Inc. ---
-** --- All rights reserved. ---
-** ---------------------------------------------------------------------
-**
-** File Description:
-**
-** Header file for host message transport layer API and data types.
-**
-** This program is free software; you can redistribute it and/or modify
-** it under the terms of the GNU General Public License as published by
-** the Free Software Foundation; either version 2 of the License, or


SHAR_EOF
true || echo 'restore of patch-2.0.37 failed'
fi

echo 'End of part 14'
echo 'File patch-2.0.37 is continued in part 15'
echo 15 > _shar_seq_.tmp
exit 0

Thomas...@ciw.uni-karlsruhe.de

unread,
Jun 16, 1999, 3:00:00 AM6/16/99
to
Archive-name: v2.0/patch-2.0.37/part13

#!/bin/sh
# this is part 13 of a 45 - part archive


# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.0.37 continued
if test ! -r _shar_seq_.tmp; then
echo 'Please unpack part 1 first!'
exit 1
fi
(read Scheck

if test "$Scheck" != 13; then


echo Please unpack part "$Scheck" next!
exit 1
else
exit 0
fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.0.37'
else
echo 'x - continuing with patch-2.0.37'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.0.37' &&

+{
+ U32 msgOffset, timeout;
+ PU32 pMsg;
+ volatile PU32 p32;
+ PPAB pPab;
+
+ pPab =PCIAdapterBlock[AdapterID];
+
+ msgOffset = pPab->p_atu->InQueue;
+
+
+ if (msgOffset == 0xFFFFFFFF)
+ {

+ kprintf("RCGetFirmwareVer(): Inbound Free Q empty!\n");


+ return RC_RTN_FREE_Q_EMPTY;
+ }
+
+ /* calc virtual address of msg - virtual already mapped to physical */
+ pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset);
+
+ /* virtual pointer to return buffer - clear first two dwords */
+ p32 = (volatile PU32)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB));
+ p32[0] = 0xff;
+
+ /* setup private message */
+ pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0;
+ pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID;
+ pMsg[2] = 0; /* initiator context */
+ pMsg[3] = 0x219; /* transaction context */

+ pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_FIRMWARE_REV;


+ /* phys address to return status - area right after PAB */
+ pMsg[5] = pPab->outMsgBlockPhyAddr - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB);
+
+
+
+ /* post to Inbound Post Q */
+
+ pPab->p_atu->InQueue = msgOffset;
+
+

+ /* wait for response */
+ timeout = 1000000;
+ while(1)
+ {
+ int i;
+
+ if (WaitCallback)
+ (*WaitCallback)();
+
+ for (i = 0; i < 1000; i++) /* please don't hog the bus!!! */
+ ;
+
+ if (p32[0] != 0xff)
+ break;
+
+ if (!timeout--)
+ {
+ kprintf("Timeout waiting for link speed from IOP\n");

+ return RC_RTN_NO_FIRM_VER;
+ }
+ }
+
+ strcpy(pFirmString, (PU8)p32);


+ return RC_RTN_NO_ERROR;
+}
+
+/*
+** =========================================================================

+** RCResetLANCard()
+**
+** ResourceFlags indicates whether to return buffer resource explicitly
+** to host or keep and reuse.
+** CallbackFunction (if not NULL) is the function to be called when
+** reset is complete.
+** If CallbackFunction is NULL, ReturnAddr will have a 1 placed in it when
+** reset is done (if not NULL).


+**
+** =========================================================================
+*/
+RC_RETURN

+RCResetLANCard(U16 AdapterID, U16 ResourceFlags, PU32 ReturnAddr, PFNCALLBACK CallbackFunction)
+{
+ unsigned long off;
+ unsigned long *pMsg;
+ PPAB pPab;
+ int i;
+ long timeout = 0;


+
+
+ pPab =PCIAdapterBlock[AdapterID];
+
+ if (pPab == NULL)
+ return RC_RTN_ADPTR_NOT_REGISTERED;
+
+ off = pPab->p_atu->InQueue; /* get addresss of message */
+
+ if (0xFFFFFFFF == off)
+ return RC_RTN_FREE_Q_EMPTY;
+

+ pPab->pCallbackFunc = CallbackFunction;


+
+ pMsg = (PU32)(pPab->pPci45LinBaseAddr + off);
+

+ /* setup message */
+ pMsg[0] = FOUR_WORD_MSG_SIZE | SGL_OFFSET_0;
+ pMsg[1] = I2O_LAN_RESET << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID;


+ pMsg[2] = DEFAULT_RECV_INIT_CONTEXT;

+ pMsg[3] = ResourceFlags << 16; /* resource flags */


+
+ pPab->p_atu->InQueue = off; /* send it to the I2O device */
+

+ if (CallbackFunction == (PFNCALLBACK)NULL)
+ {
+ /* call RCProcI2OMsgQ() until something in pPab->pCallbackFunc
+ or until timer goes off */
+ while (pPab->pCallbackFunc == (PFNCALLBACK)NULL)
+ {
+ RCProcI2OMsgQ(AdapterID);
+ for (i = 0; i < 100000; i++) /* please don't hog the bus!!! */
+ ;
+ timeout++;
+ if (timeout > 10000)
+ {
+ break;
+ }
+ }
+ if (ReturnAddr != (PU32)NULL)
+ *ReturnAddr = (U32)pPab->pCallbackFunc;
+ }


+
+ return RC_RTN_NO_ERROR ;
+}
+/*
+** =========================================================================

+** RCResetIOP()
+**
+** Send StatusGet Msg, wait for results return directly to buffer.


+**
+** =========================================================================
+*/
+RC_RETURN

+RCResetIOP(U16 AdapterID)


+{
+ U32 msgOffset, timeout;
+ PU32 pMsg;

+ PPAB pPab;


+ volatile PU32 p32;
+

+ pPab = PCIAdapterBlock[AdapterID];

+ msgOffset = pPab->p_atu->InQueue;
+
+ if (msgOffset == 0xFFFFFFFF)
+ {

+ return RC_RTN_FREE_Q_EMPTY;
+ }
+
+ /* calc virtual address of msg - virtual already mapped to physical */
+ pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset);
+

+ pMsg[0] = NINE_WORD_MSG_SIZE | SGL_OFFSET_0;
+ pMsg[1] = I2O_EXEC_IOP_RESET << 24 | I2O_HOST_TID << 12 | I2O_IOP_TID;
+ pMsg[2] = 0; /* universal context */
+ pMsg[3] = 0; /* universal context */
+ pMsg[4] = 0; /* universal context */
+ pMsg[5] = 0; /* universal context */


+ /* phys address to return status - area right after PAB */

+ pMsg[6] = pPab->outMsgBlockPhyAddr - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB);
+ pMsg[7] = 0;
+ pMsg[8] = 1; /* return 1 byte */
+
+ /* virual pointer to return buffer - clear first two dwords */


+ p32 = (volatile PU32)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB));

+ p32[0] = 0;
+ p32[1] = 0;


+
+ /* post to Inbound Post Q */
+
+ pPab->p_atu->InQueue = msgOffset;
+
+ /* wait for response */
+ timeout = 1000000;
+ while(1)
+ {
+ int i;
+

+ for (i = 0; i < 1000; i++) /* please don't hog the bus!!! */
+ ;
+

+ if (p32[0] || p32[1])
+ break;
+
+ if (!timeout--)
+ {
+ printk("RCResetIOP timeout\n");


+ return RC_RTN_MSG_REPLY_TIMEOUT;
+ }
+ }

+ return RC_RTN_NO_ERROR;
+}
+
+/*
+** =========================================================================

+** RCShutdownLANCard()
+**
+** ResourceFlags indicates whether to return buffer resource explicitly
+** to host or keep and reuse.
+** CallbackFunction (if not NULL) is the function to be called when
+** shutdown is complete.
+** If CallbackFunction is NULL, ReturnAddr will have a 1 placed in it when
+** shutdown is done (if not NULL).


+**
+** =========================================================================
+*/
+RC_RETURN

+RCShutdownLANCard(U16 AdapterID, U16 ResourceFlags, PU32 ReturnAddr, PFNCALLBACK CallbackFunction)
+{
+ volatile PU32 pMsg;
+ U32 off;
+ PPAB pPab;
+ int i;
+ long timeout = 0;


+
+ pPab = PCIAdapterBlock[AdapterID];
+
+ if (pPab == NULL)
+ return RC_RTN_ADPTR_NOT_REGISTERED;
+
+ off = pPab->p_atu->InQueue; /* get addresss of message */
+
+ if (0xFFFFFFFF == off)
+ return RC_RTN_FREE_Q_EMPTY;
+

+ pPab->pCallbackFunc = CallbackFunction;


+
+ pMsg = (PU32)(pPab->pPci45LinBaseAddr + off);
+

+ /* setup message */
+ pMsg[0] = FOUR_WORD_MSG_SIZE | SGL_OFFSET_0;
+ pMsg[1] = I2O_LAN_SHUTDOWN << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID;


+ pMsg[2] = DEFAULT_RECV_INIT_CONTEXT;

+ pMsg[3] = ResourceFlags << 16; /* resource flags */


+
+ pPab->p_atu->InQueue = off; /* send it to the I2O device */
+

+ if (CallbackFunction == (PFNCALLBACK)NULL)
+ {
+ /* call RCProcI2OMsgQ() until something in pPab->pCallbackFunc
+ or until timer goes off */
+ while (pPab->pCallbackFunc == (PFNCALLBACK)NULL)
+ {
+ RCProcI2OMsgQ(AdapterID);
+ for (i = 0; i < 100000; i++) /* please don't hog the bus!!! */
+ ;
+ timeout++;
+ if (timeout > 10000)
+ {
+ printk("RCShutdownLANCard(): timeout\n");
+ break;
+ }
+ }
+ if (ReturnAddr != (PU32)NULL)
+ *ReturnAddr = (U32)pPab->pCallbackFunc;


+ }
+ return RC_RTN_NO_ERROR ;
+}
+
+
+/*
+** =========================================================================

+** RCSetRavlinIPandMask()
+**
+** Set the Ravlin 45/PCI cards IP address and network mask.
+**
+** IP address and mask must be in network byte order.
+** For example, IP address 1.2.3.4 and mask 255.255.255.0 would be
+** 0x04030201 and 0x00FFFFFF on a little endian machine.


+**
+** =========================================================================
+*/
+RC_RETURN

+RCSetRavlinIPandMask(U16 AdapterID, U32 ipAddr, U32 netMask)
+{
+ volatile PU32 pMsg;
+ U32 off;


+ PPAB pPab;
+
+ pPab = PCIAdapterBlock[AdapterID];
+
+ if (pPab == NULL)
+ return RC_RTN_ADPTR_NOT_REGISTERED;
+

+ off = pPab->p_atu->InQueue; /* get addresss of message */
+
+ if (0xFFFFFFFF == off)
+ return RC_RTN_FREE_Q_EMPTY;
+
+ pMsg = (PU32)(pPab->pPci45LinBaseAddr + off);
+
+ /* setup private message */
+ pMsg[0] = SEVEN_WORD_MSG_SIZE | SGL_OFFSET_0;
+ pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID;
+ pMsg[2] = 0; /* initiator context */
+ pMsg[3] = 0x219; /* transaction context */

+ pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_SET_IP_AND_MASK;
+ pMsg[5] = ipAddr;
+ pMsg[6] = netMask;
+


+
+ pPab->p_atu->InQueue = off; /* send it to the I2O device */

+ return RC_RTN_NO_ERROR ;
+
+}
+
+/*
+** =========================================================================

+** RCGetRavlinIPandMask()
+**
+** get the IP address and MASK from the card


+**
+** =========================================================================
+*/
+RC_RETURN

+RCGetRavlinIPandMask(U16 AdapterID, PU32 pIpAddr, PU32 pNetMask,
+ PFNWAITCALLBACK WaitCallback)
+{


+ unsigned i, timeout;
+ U32 off;

+ PU32 pMsg, p32;
+ PPAB pPab;
+ PATU p_atu;
+
+#ifdef DEBUG
+ kprintf("RCGetRavlinIPandMask: pIpAddr is 0x%08.8ulx, *IpAddr is 0x%08.8ulx\n", pIpAddr, *pIpAddr);


+#endif /* DEBUG */
+
+ pPab = PCIAdapterBlock[AdapterID];
+
+ if (pPab == NULL)
+ return RC_RTN_ADPTR_NOT_REGISTERED;
+

+ p_atu = pPab->p_atu;

+ off = p_atu->InQueue; /* get addresss of message */
+
+ if (0xFFFFFFFF == off)
+ return RC_RTN_FREE_Q_EMPTY;
+

+ p32 = (volatile PU32)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB));

+ *p32 = 0xFFFFFFFF;
+

+ pMsg = (PU32)(pPab->pPci45LinBaseAddr + off);
+

+#ifdef DEBUG
+ kprintf("RCGetRavlinIPandMask: p_atu 0x%08.8ulx, off 0x%08.8ulx, p32 0x%08.8ulx\n", p_atu, off, p32);
+#endif /* DEBUG */


+ /* setup private message */

+ pMsg[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0;


+ pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID;
+ pMsg[2] = 0; /* initiator context */

+ pMsg[3] = 0x218; /* transaction context */
+ pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_IP_AND_MASK;


+ pMsg[5] = pPab->outMsgBlockPhyAddr - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB);
+

+ p_atu->InQueue = off; /* send it to the I2O device */

+#ifdef DEBUG
+ kprintf("RCGetRavlinIPandMask: p_atu 0x%08.8ulx, off 0x%08.8ulx, p32 0x%08.8ulx\n", p_atu, off, p32);


+#endif /* DEBUG */
+

+ /* wait for the rcpci45 board to update the info */

+ timeout = 100000;
+ while (0xffffffff == *p32)


+ {
+ if (WaitCallback)
+ (*WaitCallback)();
+
+ for (i = 0; i < 1000; i++)
+ ;
+
+ if (!timeout--)
+ {

+#ifdef DEBUG
+ kprintf("RCGetRavlinIPandMask: Timeout\n");
+#endif /* DEBUG */
+ return RC_RTN_MSG_REPLY_TIMEOUT;
+ }
+ }
+
+#ifdef DEBUG
+ kprintf("RCGetRavlinIPandMask: after time out\n", \
+ "p32[0] (IpAddr) 0x%08.8ulx, p32[1] (IPmask) 0x%08.8ulx\n", p32[0], p32[1]);


+#endif /* DEBUG */
+

+ /* send IP and mask to user's space */
+ *pIpAddr = p32[0];
+ *pNetMask = p32[1];
+
+
+#ifdef DEBUG
+ kprintf("RCGetRavlinIPandMask: pIpAddr is 0x%08.8ulx, *IpAddr is 0x%08.8ulx\n", pIpAddr, *pIpAddr);


+#endif /* DEBUG */
+

+ return RC_RTN_NO_ERROR;
+}
+
+/*

+** /////////////////////////////////////////////////////////////////////////
+** /////////////////////////////////////////////////////////////////////////
+**
+** local functions
+**
+** /////////////////////////////////////////////////////////////////////////
+** /////////////////////////////////////////////////////////////////////////
+*/
+
+/*
+** =========================================================================
+** SendI2OOutboundQInitMsg()
+**
+** =========================================================================
+*/
+static int
+SendI2OOutboundQInitMsg(PPAB pPab)
+{
+ U32 msgOffset, timeout, phyOutQFrames, i;


+ volatile PU32 pMsg;
+ volatile PU32 p32;
+

+
+
+ msgOffset = pPab->p_atu->InQueue;
+
+
+ if (msgOffset == 0xFFFFFFFF)
+ {

+#ifdef DEBUG
+ kprintf("SendI2OOutboundQInitMsg(): Inbound Free Q empty!\n");


+#endif /* DEBUG */
+ return RC_RTN_FREE_Q_EMPTY;
+ }
+
+
+ /* calc virual address of msg - virual already mapped to physical */
+ pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset);
+

+#ifdef DEBUG
+ kprintf("SendI2OOutboundQInitMsg - pMsg = 0x%08.8ulx, InQ msgOffset = 0x%08.8ulx\n", pMsg, msgOffset);


+#endif /* DEBUG */
+

+ pMsg[0] = EIGHT_WORD_MSG_SIZE | TRL_OFFSET_6;
+ pMsg[1] = I2O_EXEC_OUTBOUND_INIT << 24 | I2O_HOST_TID << 12 | I2O_IOP_TID;


+ pMsg[2] = DEFAULT_RECV_INIT_CONTEXT;

+ pMsg[3] = 0x106; /* transaction context */
+ pMsg[4] = 4096; /* Host page frame size */
+ pMsg[5] = MSG_FRAME_SIZE << 16 | 0x80; /* outbound msg frame size and Initcode */
+ pMsg[6] = 0xD0000004; /* simple sgl element LE, EOB */


+ /* phys address to return status - area right after PAB */

+ pMsg[7] = pPab->outMsgBlockPhyAddr - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB);
+
+ /* virual pointer to return buffer - clear first two dwords */


+ p32 = (PU32)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB));

+ p32[0] = 0;


+
+ /* post to Inbound Post Q */
+ pPab->p_atu->InQueue = msgOffset;
+

+ /* wait for response */

+ timeout = 100000;
+ while(1)


+ {
+ for (i = 0; i < 1000; i++) /* please don't hog the bus!!! */
+ ;
+

+ if (p32[0])
+ break;
+

+ if (!timeout--)
+ {
+#ifdef DEBUG

+ kprintf("Timeout wait for InitOutQ InPrgress status from IOP\n");
+#endif /* DEBUG */
+ return RC_RTN_NO_I2O_STATUS;
+ }
+ }


+
+ timeout = 100000;
+ while(1)

+ {
+ for (i = 0; i < 1000; i++) /* please don't hog the bus!!! */
+ ;
+

+ if (p32[0] == I2O_EXEC_OUTBOUND_INIT_COMPLETE)


+ break;
+
+ if (!timeout--)
+ {
+#ifdef DEBUG

+ kprintf("Timeout wait for InitOutQ Complete status from IOP\n");
+#endif /* DEBUG */
+ return RC_RTN_NO_I2O_STATUS;
+ }
+ }
+
+ /* load PCI outbound free Q with MF physical addresses */
+ phyOutQFrames = pPab->outMsgBlockPhyAddr;
+
+ for (i = 0; i < NMBR_MSG_FRAMES; i++)
+ {
+ pPab->p_atu->OutQueue = phyOutQFrames;
+ phyOutQFrames += MSG_FRAME_SIZE;


+ }
+ return RC_RTN_NO_ERROR;
+}
+
+
+/*
+** =========================================================================

+** GetI2OStatus()
+**
+** Send StatusGet Msg, wait for results return directly to buffer.
+**
+** =========================================================================
+*/
+static int
+GetI2OStatus(PPAB pPab)


+{
+ U32 msgOffset, timeout;
+ PU32 pMsg;
+ volatile PU32 p32;
+

+
+ msgOffset = pPab->p_atu->InQueue;

+#ifdef DEBUG
+ printk("GetI2OStatus: msg offset = 0x%x\n", msgOffset);
+#endif /* DEBUG */


+ if (msgOffset == 0xFFFFFFFF)
+ {
+#ifdef DEBUG

+ kprintf("GetI2OStatus(): Inbound Free Q empty!\n");


+#endif /* DEBUG */
+ return RC_RTN_FREE_Q_EMPTY;
+ }
+
+ /* calc virual address of msg - virual already mapped to physical */
+ pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset);
+

+ pMsg[0] = NINE_WORD_MSG_SIZE | SGL_OFFSET_0;
+ pMsg[1] = I2O_EXEC_STATUS_GET << 24 | I2O_HOST_TID << 12 | I2O_IOP_TID;
+ pMsg[2] = 0; /* universal context */
+ pMsg[3] = 0; /* universal context */
+ pMsg[4] = 0; /* universal context */
+ pMsg[5] = 0; /* universal context */


+ /* phys address to return status - area right after PAB */

+ pMsg[6] = pPab->outMsgBlockPhyAddr - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB);
+ pMsg[7] = 0;
+ pMsg[8] = 88; /* return 88 bytes */
+
+ /* virual pointer to return buffer - clear first two dwords */


+ p32 = (volatile PU32)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB));

+ p32[0] = 0;
+ p32[1] = 0;
+
+#ifdef DEBUG
+ kprintf("GetI2OStatus - pMsg:0x%08.8ulx, msgOffset:0x%08.8ulx, [1]:0x%08.8ulx, [6]:0x%08.8ulx\n",
+ pMsg, msgOffset, pMsg[1], pMsg[6]);


+#endif /* DEBUG */
+

+ /* post to Inbound Post Q */
+ pPab->p_atu->InQueue = msgOffset;
+

+#ifdef DEBUG
+ kprintf("Return status to p32 = 0x%08.8ulx\n", p32);


+#endif /* DEBUG */
+

+ /* wait for response */
+ timeout = 1000000;
+ while(1)
+ {
+ int i;
+

+ for (i = 0; i < 1000; i++) /* please don't hog the bus!!! */
+ ;
+

+ if (p32[0] && p32[1])
+ break;
+

+ if (!timeout--)
+ {
+#ifdef DEBUG

+ kprintf("Timeout waiting for status from IOP\n");
+ kprintf("0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx\n", p32[0], p32[1], p32[2], p32[3]);
+ kprintf("0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx\n", p32[4], p32[5], p32[6], p32[7]);
+ kprintf("0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx\n", p32[8], p32[9], p32[10], p32[11]);
+#endif /* DEBUG */
+ return RC_RTN_NO_I2O_STATUS;
+ }
+ }
+
+#ifdef DEBUG
+ kprintf("0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx\n", p32[0], p32[1], p32[2], p32[3]);
+ kprintf("0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx\n", p32[4], p32[5], p32[6], p32[7]);
+ kprintf("0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx\n", p32[8], p32[9], p32[10], p32[11]);
+#endif /* DEBUG */
+ /* get IOP state */
+ pPab->IOPState = ((volatile PU8)p32)[10];
+ pPab->InboundMFrameSize = ((volatile PU16)p32)[6];
+
+#ifdef DEBUG
+ kprintf("IOP state 0x%02.2x InFrameSize = 0x%04.4x\n",
+ pPab->IOPState, pPab->InboundMFrameSize);
+#endif /* DEBUG */


+ return RC_RTN_NO_ERROR;
+}
+
+
+/*
+** =========================================================================

+** SendEnableSysMsg()
+**
+**
+** =========================================================================
+*/
+static int
+SendEnableSysMsg(PPAB pPab)
+{
+ U32 msgOffset; // timeout;


+ volatile PU32 pMsg;
+

+ msgOffset = pPab->p_atu->InQueue;
+
+ if (msgOffset == 0xFFFFFFFF)
+ {
+#ifdef DEBUG

+ kprintf("SendEnableSysMsg(): Inbound Free Q empty!\n");


+#endif /* DEBUG */
+ return RC_RTN_FREE_Q_EMPTY;
+ }
+
+ /* calc virual address of msg - virual already mapped to physical */
+ pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset);
+

+#ifdef DEBUG
+ kprintf("SendEnableSysMsg - pMsg = 0x%08.8ulx, InQ msgOffset = 0x%08.8ulx\n", pMsg, msgOffset);


+#endif /* DEBUG */
+

+ pMsg[0] = FOUR_WORD_MSG_SIZE | SGL_OFFSET_0;
+ pMsg[1] = I2O_EXEC_SYS_ENABLE << 24 | I2O_HOST_TID << 12 | I2O_IOP_TID;


+ pMsg[2] = DEFAULT_RECV_INIT_CONTEXT;

+ pMsg[3] = 0x110; /* transaction context */
+ pMsg[4] = 0x50657465; /* RedCreek Private */


+
+ /* post to Inbound Post Q */
+ pPab->p_atu->InQueue = msgOffset;
+

+ return RC_RTN_NO_ERROR;
+}
+
+
+/*
+** =========================================================================

+** FillI2OMsgFromTCB()
+**
+** inputs pMsgU32 - virual pointer (mapped to physical) of message frame
+** pXmitCntrlBlock - pointer to caller buffer control block.
+**
+** fills in LAN SGL after Transaction Control Word or Bucket Count.
+** =========================================================================
+*/
+static int
+FillI2OMsgSGLFromTCB(PU32 pMsgFrame, PRCTCB pTransCtrlBlock)
+{
+ unsigned int nmbrBuffers, nmbrSeg, nmbrDwords, context, flags;
+ PU32 pTCB, pMsg;
+
+ /* SGL element flags */
+#define EOB 0x40000000
+#define LE 0x80000000
+#define SIMPLE_SGL 0x10000000
+#define BC_PRESENT 0x01000000
+
+ pTCB = (PU32)pTransCtrlBlock;
+ pMsg = pMsgFrame;
+ nmbrDwords = 0;
+
+#ifdef DEBUG
+ kprintf("FillI2OMsgSGLFromTCBX\n");
+ kprintf("TCB 0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx\n",
+ pTCB[0], pTCB[1], pTCB[2], pTCB[3], pTCB[4]);
+ kprintf("pTCB 0x%08.8ulx, pMsg 0x%08.8ulx\n", pTCB, pMsg);


+#endif /* DEBUG */
+

+ nmbrBuffers = *pTCB++;
+
+ if (!nmbrBuffers)
+ {
+ return -1;
+ }
+
+ do
+ {
+ context = *pTCB++; /* buffer tag (context) */
+ nmbrSeg = *pTCB++; /* number of segments */
+
+ if (!nmbrSeg)
+ {
+ return -1;
+ }
+
+ flags = SIMPLE_SGL | BC_PRESENT;
+
+ if (1 == nmbrSeg)
+ {
+ flags |= EOB;
+
+ if (1 == nmbrBuffers)
+ flags |= LE;
+ }
+
+ /* 1st SGL buffer element has context */
+ pMsg[0] = pTCB[0] | flags ; /* send over count (segment size) */
+ pMsg[1] = context;
+ pMsg[2] = pTCB[1]; /* send buffer segment physical address */
+ nmbrDwords += 3;
+ pMsg += 3;
+ pTCB += 2;
+
+
+ if (--nmbrSeg)
+ {
+ do
+ {
+ flags = SIMPLE_SGL;
+
+ if (1 == nmbrSeg)
+ {
+ flags |= EOB;
+
+ if (1 == nmbrBuffers)
+ flags |= LE;
+ }
+
+ pMsg[0] = pTCB[0] | flags; /* send over count */
+ pMsg[1] = pTCB[1]; /* send buffer segment physical address */
+ nmbrDwords += 2;
+ pTCB += 2;
+ pMsg += 2;
+
+ } while (--nmbrSeg);
+ }
+
+ } while (--nmbrBuffers);
+
+ return nmbrDwords;


+}
+
+
+/*
+** =========================================================================

+** ProcessOutboundI2OMsg()
+**
+** process I2O reply message
+** * change to msg structure *
+** =========================================================================
+*/
+static void
+ProcessOutboundI2OMsg(PPAB pPab, U32 phyAddrMsg)
+{


+ PU8 p8Msg;
+ PU32 p32;

+ // U16 count;
+

+
+ p8Msg = pPab->pLinOutMsgBlock + (phyAddrMsg - pPab->outMsgBlockPhyAddr);
+ p32 = (PU32)p8Msg;
+

+#ifdef DEBUG
+ kprintf("VXD: ProcessOutboundI2OMsg - pPab 0x%08.8ulx, phyAdr 0x%08.8ulx, linAdr 0x%08.8ulx\n", pPab, phyAddrMsg, p8Msg);
+ kprintf("msg :0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx\n", p32[0], p32[1], p32[2], p32[3]);
+ kprintf("msg :0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx\n", p32[4], p32[5], p32[6], p32[7]);


+#endif /* DEBUG */
+

+ if (p32[4] >> 24 != I2O_REPLY_STATUS_SUCCESS)
+ {
+#ifdef DEBUG
+ kprintf("Message reply status not success\n");
+#endif /* DEBUG */
+ return;
+ }
+
+ switch (p8Msg[7] ) /* function code byte */
+ {
+ case I2O_EXEC_SYS_TAB_SET:
+ msgFlag = 1;
+#ifdef DEBUG
+ kprintf("Received I2O_EXEC_SYS_TAB_SET reply\n");
+#endif /* DEBUG */
+ break;
+
+ case I2O_EXEC_HRT_GET:
+ msgFlag = 1;
+#ifdef DEBUG
+ kprintf("Received I2O_EXEC_HRT_GET reply\n");
+#endif /* DEBUG */
+ break;
+
+ case I2O_EXEC_LCT_NOTIFY:
+ msgFlag = 1;
+#ifdef DEBUG
+ kprintf("Received I2O_EXEC_LCT_NOTIFY reply\n");
+#endif /* DEBUG */
+ break;
+
+ case I2O_EXEC_SYS_ENABLE:
+ msgFlag = 1;
+#ifdef DEBUG
+ kprintf("Received I2O_EXEC_SYS_ENABLE reply\n");
+#endif /* DEBUG */
+ break;
+
+ default:
+#ifdef DEBUG
+ kprintf("Received UNKNOWN reply\n");
+#endif /* DEBUG */
+ break;
+ }
+}
diff -u --recursive --new-file v2.0.36/linux/drivers/net/rclanmtl.h linux/drivers/net/rclanmtl.h
--- v2.0.36/linux/drivers/net/rclanmtl.h Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/rclanmtl.h Sun Jun 13 10:21:01 1999
@@ -0,0 +1,637 @@


+/*
+** *************************************************************************
+**
+**

+** R C L A N M T L . H $Revision: 6 $
+**
+**
+** RedCreek I2O LAN Message Transport Layer header file.


+**
+** ---------------------------------------------------------------------
+** --- Copyright (c) 1997-1999, RedCreek Communications Inc. ---
+** --- All rights reserved. ---
+** ---------------------------------------------------------------------
+**
+** File Description:
+**

+** Header file for host I2O (Intelligent I/O) LAN message transport layer
+** API and data types.


+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**

+** *************************************************************************
+*/
+
+#ifndef RCLANMTL_H
+#define RCLANMTL_H
+
+/* Linux specific includes */
+#define kprintf printk
+#ifdef RC_LINUX_MODULE /* linux modules need non-library version of string functions */
+#include <linux/string.h>
+#else
+#include <string.h>
+#endif
+
+/* PCI/45 Configuration space values */
+#define RC_PCI45_VENDOR_ID 0x4916
+#define RC_PCI45_DEVICE_ID 0x1960
+
+
+ /* RedCreek API function return values */
+#define RC_RTN_NO_ERROR 0
+#define RC_RTN_I2O_NOT_INIT 1
+#define RC_RTN_FREE_Q_EMPTY 2
+#define RC_RTN_TCB_ERROR 3
+#define RC_RTN_TRANSACTION_ERROR 4
+#define RC_RTN_ADAPTER_ALREADY_INIT 5
+#define RC_RTN_MALLOC_ERROR 6
+#define RC_RTN_ADPTR_NOT_REGISTERED 7
+#define RC_RTN_MSG_REPLY_TIMEOUT 8
+#define RC_RTN_NO_I2O_STATUS 9
+#define RC_RTN_NO_FIRM_VER 10
+#define RC_RTN_NO_LINK_SPEED 11
+
+/* Driver capability flags */
+#define WARM_REBOOT_CAPABLE 0x01
+
+ /* scalar data types */
+typedef unsigned char U8;
+typedef unsigned char* PU8;
+typedef unsigned short U16;
+typedef unsigned short* PU16;
+typedef unsigned long U32;
+typedef unsigned long* PU32;
+typedef unsigned long BF;
+typedef int RC_RETURN;
+
+
+ /*
+ ** type PFNWAITCALLBACK
+ **
+ ** pointer to void function - type used for WaitCallback in some functions
+ */
+typedef void (*PFNWAITCALLBACK)(void); /* void argument avoids compiler complaint */
+
+ /*
+ ** type PFNTXCALLBACK
+ **
+ ** Pointer to user's transmit callback function. This user function is
+ ** called from RCProcI2OMsgQ() when packet have been transmitted from buffers
+ ** given in the RCI2OSendPacket() function. BufferContext is a pointer to
+ ** an array of 32 bit context values. These are the values the user assigned
+ ** and passed in the TCB to the RCI2OSendPacket() function. PcktCount
+ ** indicates the number of buffer context values in the BufferContext[] array.
+ ** The User's TransmitCallbackFunction should recover (put back in free queue)
+ ** the packet buffers associated with the buffer context values.
+ */
+typedef void (*PFNTXCALLBACK)(U32 Status,
+ U16 PcktCount,
+ PU32 BufferContext,
+ U16 AdaterID);
+
+ /*
+ ** type PFNRXCALLBACK
+ **
+ ** Pointer to user's receive callback function. This user function
+ ** is called from RCProcI2OMsgQ() when packets have been received into
+ ** previously posted packet buffers throught the RCPostRecvBuffers() function.
+ ** The received callback function should process the Packet Descriptor Block
+ ** pointed to by PacketDescBlock. See Packet Decription Block below.
+ */
+typedef void (*PFNRXCALLBACK)(U32 Status,
+ U8 PktCount,
+ U32 BucketsRemain,
+ PU32 PacketDescBlock,
+ U16 AdapterID);
+
+ /*
+ ** type PFNCALLBACK
+ **
+ ** Pointer to user's generic callback function. This user function
+ ** can be passed to LANReset or LANShutdown and is called when the
+ ** the reset or shutdown is complete.
+ ** Param1 and Param2 are invalid for LANReset and LANShutdown.
+ */
+typedef void (*PFNCALLBACK)(U32 Status,
+ U32 Param1,
+ U32 Param2,
+ U16 AdapterID);
+
+/*
+** Status - Transmit and Receive callback status word
+**
+** A 32 bit Status is returned to the TX and RX callback functions. This value
+** contains both the reply status and the detailed status as follows:
+**
+** 32 24 16 0
+** +------+------+------------+
+** | Reply| | Detailed |
+** |Status| 0 | Status |
+** +------+------+------------+
+**
+** Reply Status and Detailed Status of zero indicates No Errors.
+*/
+ /* reply message status defines */
+#define I2O_REPLY_STATUS_SUCCESS 0x00
+#define I2O_REPLY_STATUS_ABORT_NO_DATA_TRANSFER 0x02
+#define I2O_REPLY_STATUS_TRANSACTION_ERROR 0x0A
+
+
+/* DetailedStatusCode defines */
+#define I2O_LAN_DSC_SUCCESS 0x0000
+#define I2O_LAN_DSC_DEVICE_FAILURE 0x0001
+#define I2O_LAN_DSC_DESTINATION_NOT_FOUND 0x0002
+#define I2O_LAN_DSC_TRANSMIT_ERROR 0x0003
+#define I2O_LAN_DSC_TRANSMIT_ABORTED 0x0004
+#define I2O_LAN_DSC_RECEIVE_ERROR 0x0005
+#define I2O_LAN_DSC_RECEIVE_ABORTED 0x0006
+#define I2O_LAN_DSC_DMA_ERROR 0x0007
+#define I2O_LAN_DSC_BAD_PACKET_DETECTED 0x0008
+#define I2O_LAN_DSC_OUT_OF_MEMORY 0x0009
+#define I2O_LAN_DSC_BUCKET_OVERRUN 0x000A
+#define I2O_LAN_DSC_IOP_INTERNAL_ERROR 0x000B
+#define I2O_LAN_DSC_CANCELED 0x000C
+#define I2O_LAN_DSC_INVALID_TRANSACTION_CONTEXT 0x000D
+#define I2O_LAN_DSC_DESTINATION_ADDRESS_DETECTED 0x000E
+#define I2O_LAN_DSC_DESTINATION_ADDRESS_OMITTED 0x000F
+#define I2O_LAN_DSC_PARTIAL_PACKET_RETURNED 0x0010
+
+
+/*
+** Packet Description Block (Received packets)
+**
+** A pointer to this block structure is returned to the ReceiveCallback
+** function. It contains the list of packet buffers which have either been
+** filled with a packet or returned to host due to a LANReset function.
+** Currently there will only be one packet per receive bucket (buffer) posted.
+**
+** 32 24 0
+** +-----------------------+ -\
+** | Buffer 1 Context | \
+** +-----------------------+ \
+** | 0xC0000000 | / First Bucket Descriptor
+** +-----+-----------------+ /
+** | 0 | packet 1 length | /
+** +-----------------------+ -\
+** | Buffer 2 Context | \
+** +-----------------------+ \
+** | 0xC0000000 | / Second Bucket Descriptor
+** +-----+-----------------+ /
+** | 0 | packet 2 length | /
+** +-----+-----------------+ -
+** | ... | ----- more bucket descriptors
+** +-----------------------+ -\
+** | Buffer n Context | \
+** +-----------------------+ \
+** | 0xC0000000 | / Last Bucket Descriptor
+** +-----+-----------------+ /
+** | 0 | packet n length | /
+** +-----+-----------------+ -
+**
+** Buffer Context values are those given to adapter in the TCB on calls to
+** RCPostRecvBuffers().
+**
+*/
+
+
+
+/*
+** Transaction Control Block (TCB) structure
+**
+** A structure like this is filled in by the user and passed by reference to
+** RCI2OSendPacket() and RCPostRecvBuffers() functions. Minimum size is five
+** 32-bit words for one buffer with one segment descriptor.
+** MAX_NMBR_POST_BUFFERS_PER_MSG defines the maximum single segment buffers
+** that can be described in a given TCB.
+**
+** 32 0
+** +-----------------------+
+** | Buffer Count | Number of buffers in the TCB
+** +-----------------------+
+** | Buffer 1 Context | first buffer reference
+** +-----------------------+
+** | Buffer 1 Seg Count | number of segments in buffer
+** +-----------------------+
+** | Buffer 1 Seg Desc 1 | first segment descriptor (size, physical address)
+** +-----------------------+
+** | ... | more segment descriptors (size, physical address)
+** +-----------------------+
+** | Buffer 1 Seg Desc n | last segment descriptor (size, physical address)
+** +-----------------------+
+** | Buffer 2 Context | second buffer reference
+** +-----------------------+
+** | Buffer 2 Seg Count | number of segments in buffer
+** +-----------------------+
+** | Buffer 2 Seg Desc 1 | segment descriptor (size, physical address)
+** +-----------------------+
+** | ... | more segment descriptors (size, physical address)
+** +-----------------------+
+** | Buffer 2 Seg Desc n |
+** +-----------------------+
+** | ... | more buffer descriptor blocks ...
+** +-----------------------+
+** | Buffer n Context |
+** +-----------------------+
+** | Buffer n Seg Count |
+** +-----------------------+
+** | Buffer n Seg Desc 1 |
+** +-----------------------+
+** | ... |
+** +-----------------------+
+** | Buffer n Seg Desc n |
+** +-----------------------+
+**
+**
+** A TCB for one contigous packet buffer would look like the following:
+**
+** 32 0
+** +-----------------------+
+** | 1 | one buffer in the TCB
+** +-----------------------+
+** | <user's Context> | user's buffer reference
+** +-----------------------+
+** | 1 | one segment buffer
+** +-----------------------+ _
+** | <buffer size> | size \
+** +-----------------------+ \ segment descriptor
+** | <physical address> | physical address of buffer /
+** +-----------------------+ _/
+**
+*/
+
+ /* Buffer Segment Descriptor */
+typedef struct
+{
+ U32 size;
+ U32 phyAddress;
+}
+ BSD, *PBSD;
+
+typedef PU32 PRCTCB;
+/*
+** -------------------------------------------------------------------------
+** Exported functions comprising the API to the LAN I2O message transport layer
+** -------------------------------------------------------------------------
+*/
+
+
+ /*
+ ** InitRCI2OMsgLayer()
+ **
+ ** Called once prior to using the I2O LAN message transport layer. User
+ ** provides both the physical and virual address of a locked page buffer
+ ** that is used as a private buffer for the RedCreek I2O message
+ ** transport layer. This buffer must be a contigous memory block of a
+ ** minimum of 16K bytes and long word aligned. The user also must provide
+ ** the base address of the RedCreek PCI adapter assigned by BIOS or operating
+ ** system. The user provided value AdapterID is a zero based index of the
+ ** Ravlin 45/PCI adapter. This interface number is used in all subsequent API
+ ** calls to identify which adpapter for which the function is intended.
+ ** Up to sixteen interfaces are supported with this API.
+ **
+ ** Inputs: AdapterID - interface number from 0 to 15
+ ** pciBaseAddr - virual base address of PCI (set by BIOS)
+ ** p_msgbuf - virual address to private message block (min. 16K)
+ ** p_phymsgbuf - physical address of private message block
+ ** TransmitCallbackFunction - address of user's TX callback function
+ ** ReceiveCallbackFunction - address of user's RX callback function
+ **
+ */
+RC_RETURN RCInitI2OMsgLayer(U16 AdapterID, U32 pciBaseAddr,

+ PU8 p_msgbuf, PU8 p_phymsgbuf,
+ PFNTXCALLBACK TransmitCallbackFunction,
+ PFNRXCALLBACK ReceiveCallbackFunction,
+ PFNCALLBACK RebootCallbackFunction);
+

+ /*
+ ** RCSetRavlinIPandMask()
+ **
+ ** Set the Ravlin 45/PCI cards IP address and network mask.
+ **
+ ** IP address and mask must be in network byte order.
+ ** For example, IP address 1.2.3.4 and mask 255.255.255.0 would be
+ ** 0x04030201 and 0x00FFFFFF on a little endian machine.
+ **
+ */
+RC_RETURN RCSetRavlinIPandMask(U16 AdapterID, U32 ipAddr, U32 netMask);


+
+
+/*
+** =========================================================================

+** RCGetRavlinIPandMask()
+**
+** get the IP address and MASK from the card


+**
+** =========================================================================
+*/
+RC_RETURN

+RCGetRavlinIPandMask(U16 AdapterID, PU32 pIpAddr, PU32 pNetMask,
+ PFNWAITCALLBACK WaitCallback);
+
+ /*
+ ** RCProcI2OMsgQ()
+ **
+ ** Called from user's polling loop or Interrupt Service Routine for a PCI
+ ** interrupt from the RedCreek PCI adapter. User responsible for determining
+ ** and hooking the PCI interrupt. This function will call the registered
+ ** callback functions, TransmitCallbackFunction or ReceiveCallbackFunction,
+ ** if a TX or RX transaction has completed.
+ */
+void RCProcI2OMsgQ(U16 AdapterID);
+
+
+ /*
+ ** Disable and Enable I2O interrupts. I2O interrupts are enabled at Init time
+ ** but can be disabled and re-enabled through these two function calls.
+ ** Packets will still be put into any posted recieved buffers and packets will
+ ** be sent through RCI2OSendPacket() functions. Disabling I2O interrupts
+ ** will prevent hardware interrupt to host even though the outbound I2O msg


+ ** queue is not emtpy.

+ */
+RC_RETURN RCEnableI2OInterrupts(U16 adapterID);


+RC_RETURN RCDisableI2OInterrupts(U16 AdapterID);
+
+

+ /*
+ ** RCPostRecvBuffers()
+ **
+ ** Post user's page locked buffers for use by the PCI adapter to
+ ** return ethernet packets received from the LAN. Transaction Control Block,
+ ** provided by user, contains buffer descriptor(s) which includes a buffer
+ ** context number along with buffer size and physical address. See TCB above.
+ ** The buffer context and actual packet length are returned to the
+ ** ReceiveCallbackFunction when packets have been received. Buffers posted
+ ** to the RedCreek adapter are considered owned by the adapter until the
+ ** context is return to user through the ReceiveCallbackFunction.
+ */
+RC_RETURN RCPostRecvBuffers(U16 AdapterID, PRCTCB pTransactionCtrlBlock);
+#define MAX_NMBR_POST_BUFFERS_PER_MSG 32
+
+ /*
+ ** RCI2OSendPacket()
+ **
+ ** Send user's ethernet packet from a locked page buffer.
+ ** Packet must have full MAC header, however without a CRC.
+ ** Initiator context is a user provided value that is returned
+ ** to the TransmitCallbackFunction when packet buffer is free.
+ ** Transmit buffer are considered owned by the adapter until context's
+ ** returned to user through the TransmitCallbackFunction.
+ */
+RC_RETURN RCI2OSendPacket(U16 AdapterID,
+ U32 context,
+ PRCTCB pTransactionCtrlBlock);
+
+
+ /* Ethernet Link Statistics structure */
+typedef struct tag_RC_link_stats
+{
+ U32 TX_good; /* good transmit frames */
+ U32 TX_maxcol; /* frames not TX due to MAX collisions */
+ U32 TX_latecol; /* frames not TX due to late collisions */
+ U32 TX_urun; /* frames not TX due to DMA underrun */
+ U32 TX_crs; /* frames TX with lost carrier sense */
+ U32 TX_def; /* frames deferred due to activity on link */
+ U32 TX_singlecol; /* frames TX with one and only on collision */
+ U32 TX_multcol; /* frames TX with more than one collision */
+ U32 TX_totcol; /* total collisions detected during TX */
+ U32 Rcv_good; /* good frames received */
+ U32 Rcv_CRCerr; /* frames RX and discarded with CRC errors */
+ U32 Rcv_alignerr; /* frames RX with alignment and CRC errors */
+ U32 Rcv_reserr; /* good frames discarded due to no RX buffer */
+ U32 Rcv_orun; /* RX frames lost due to FIFO overrun */
+ U32 Rcv_cdt; /* RX frames with collision during RX */
+ U32 Rcv_runt; /* RX frames shorter than 64 bytes */
+}
+ RCLINKSTATS, *P_RCLINKSTATS;
+
+ /*
+ ** RCGetLinkStatistics()
+ **
+ ** Returns link statistics in user's structure at address StatsReturnAddr
+ ** If given, not NULL, the function WaitCallback is called during the wait
+ ** loop while waiting for the adapter to respond.
+ */
+RC_RETURN RCGetLinkStatistics(U16 AdapterID,


+ P_RCLINKSTATS StatsReturnAddr,
+ PFNWAITCALLBACK WaitCallback);
+

+ /*
+ ** RCGetLinkStatus()
+ **
+ ** Return link status, up or down, to user's location addressed by ReturnAddr.
+ ** If given, not NULL, the function WaitCallback is called during the wait
+ ** loop while waiting for the adapter to respond.
+ */
+RC_RETURN RCGetLinkStatus(U16 AdapterID,
+ PU32 pReturnStatus,
+ PFNWAITCALLBACK WaitCallback);
+
+ /* Link Status defines - value returned in pReturnStatus */
+#define RC_LAN_LINK_STATUS_DOWN 0
+#define RC_LAN_LINK_STATUS_UP 1
+
+ /*
+ ** RCGetMAC()
+ **
+ ** Get the current MAC address assigned to user. RedCreek Ravlin 45/PCI
+ ** has two MAC addresses. One which is private to the PCI Card, and
+ ** another MAC which is given to the user as its link layer MAC address. The
+ ** adapter runs in promiscous mode because of the dual address requirement.
+ ** The MAC address is returned to the unsigned char array pointer to by mac.
+ */
+RC_RETURN RCGetMAC(U16 AdapterID, PU8 mac, PFNWAITCALLBACK WaitCallback);
+
+ /*
+ ** RCSetMAC()
+ **
+ ** Set a new user port MAC address. This address will be returned on
+ ** subsequent RCGetMAC() calls.
+ */
+RC_RETURN RCSetMAC(U16 AdapterID, PU8 mac);
+
+ /*
+ ** RCSetLinkSpeed()
+ **
+ ** set adapter's link speed based on given input code.
+ */
+RC_RETURN RCSetLinkSpeed(U16 AdapterID, U16 LinkSpeedCode);
+ /* Set link speed codes */
+#define LNK_SPD_AUTO_NEG_NWAY 0
+#define LNK_SPD_100MB_FULL 1
+#define LNK_SPD_100MB_HALF 2
+#define LNK_SPD_10MB_FULL 3
+#define LNK_SPD_10MB_HALF 4
+


+
+
+
+ /*

+ ** RCGetLinkSpeed()
+ **
+ ** Return link speed code.
+ */
+ /* Return link speed codes */
+#define LNK_SPD_UNKNOWN 0
+#define LNK_SPD_100MB_FULL 1
+#define LNK_SPD_100MB_HALF 2
+#define LNK_SPD_10MB_FULL 3
+#define LNK_SPD_10MB_HALF 4
+
+RC_RETURN
+RCGetLinkSpeed(U16 AdapterID, PU32 pLinkSpeedCode, PFNWAITCALLBACK WaitCallback);
+/*
+** =========================================================================
+** RCSetPromiscuousMode(U16 AdapterID, U16 Mode)


+**
+** Defined values for Mode:
+** 0 - turn off promiscuous mode
+** 1 - turn on promiscuous mode
+**
+** =========================================================================
+*/

+#define PROMISCUOUS_MODE_OFF 0
+#define PROMISCUOUS_MODE_ON 1
+RC_RETURN
+RCSetPromiscuousMode(U16 AdapterID, U16 Mode);
+/*
+** =========================================================================
+** RCGetPromiscuousMode(U16 AdapterID, PU32 pMode, PFNWAITCALLBACK WaitCallback)


+**
+** get promiscuous mode setting
+**
+** Possible return values placed in pMode:
+** 0 = promisuous mode not set
+** 1 = promisuous mode is set
+**
+** =========================================================================
+*/
+RC_RETURN
+RCGetPromiscuousMode(U16 AdapterID, PU32 pMode, PFNWAITCALLBACK WaitCallback);
+

+/*
+** =========================================================================
+** RCSetBroadcastMode(U16 AdapterID, U16 Mode)


+**
+** Defined values for Mode:
+** 0 - turn off promiscuous mode
+** 1 - turn on promiscuous mode
+**
+** =========================================================================
+*/

+#define BROADCAST_MODE_OFF 0
+#define BROADCAST_MODE_ON 1
+RC_RETURN
+RCSetBroadcastMode(U16 AdapterID, U16 Mode);
+/*
+** =========================================================================
+** RCGetBroadcastMode(U16 AdapterID, PU32 pMode, PFNWAITCALLBACK WaitCallback)
+**
+** get broadcast mode setting


+**
+** Possible return values placed in pMode:

+** 0 = broadcast mode not set
+** 1 = broadcast mode is set


+**
+** =========================================================================
+*/
+RC_RETURN

+RCGetBroadcastMode(U16 AdapterID, PU32 pMode, PFNWAITCALLBACK WaitCallback);


+/*
+** =========================================================================
+** RCReportDriverCapability(U16 AdapterID, U32 capability)
+**
+** Currently defined bits:
+** WARM_REBOOT_CAPABLE 0x01
+**
+** =========================================================================
+*/
+RC_RETURN
+RCReportDriverCapability(U16 AdapterID, U32 capability);
+

+/*


+** RCGetFirmwareVer()
+**
+** Return firmware version in the form "SoftwareVersion : Bt BootVersion"
+**

+** WARNING: user's space pointed to by pFirmString should be at least 60 bytes.
+*/
+RC_RETURN
+RCGetFirmwareVer(U16 AdapterID, PU8 pFirmString, PFNWAITCALLBACK WaitCallback);
+
+/*
+** ----------------------------------------------
+** LAN adapter Reset and Shutdown functions
+** ----------------------------------------------
+*/
+ /* resource flag bit assignments for RCResetLANCard() & RCShutdownLANCard() */
+#define RC_RESOURCE_RETURN_POSTED_RX_BUCKETS 0x0001
+#define RC_RESOURCE_RETURN_PEND_TX_BUFFERS 0x0002
+
+ /*
+ ** RCResetLANCard()
+ **
+ ** Reset LAN card operation. Causes a software reset of the ethernet
+ ** controller and restarts the command and receive units. Depending on
+ ** the ResourceFlags given, the buffers are either returned to the
+ ** host with reply status of I2O_REPLY_STATUS_ABORT_NO_DATA_TRANSFER and
+ ** detailed status of I2O_LAN_DSC_CANCELED (new receive buffers must be
+ ** posted after issuing this) OR the buffers are kept and reused by
+ ** the ethernet controller. If CallbackFunction is not NULL, the function
+ ** will be called when the reset is complete. If the CallbackFunction is
+ ** NULL,a 1 will be put into the ReturnAddr after waiting for the reset
+ ** to complete (please disable I2O interrupts during this method).
+ ** Any outstanding transmit or receive buffers that are complete will be
+ ** returned via the normal reply messages before the requested resource
+ ** buffers are returned.
+ ** A call to RCPostRecvBuffers() is needed to return the ethernet to full
+ ** operation if the receive buffers were returned during LANReset.
+ ** Note: The IOP status is not affected by a LAN reset.
+ */
+RC_RETURN RCResetLANCard(U16 AdapterID, U16 ResourceFlags, PU32 ReturnAddr, PFNCALLBACK CallbackFunction);
+
+
+ /*
+ ** RCShutdownLANCard()
+ **
+ ** Shutdown LAN card operation and put into an idle (suspended) state.
+ ** The LAN card is restarted with RCResetLANCard() function.
+ ** Depending on the ResourceFlags given, the buffers are either returned
+ ** to the host with reply status of I2O_REPLY_STATUS_ABORT_NO_DATA_TRANSFER
+ ** and detailed status of I2O_LAN_DSC_CANCELED (new receive buffers must be
+ ** posted after issuing this) OR the buffers are kept and reused by
+ ** the ethernet controller. If CallbackFunction is not NULL, the function
+ ** will be called when the reset is complete. If the CallbackFunction is
+ ** NULL,a 1 will be put into the ReturnAddr after waiting for the reset
+ ** to complete (please disable I2O interrupts during this method).
+ ** Any outstanding transmit or receive buffers that are complete will be
+ ** returned via the normal reply messages before the requested resource
+ ** buffers are returned.
+ ** Note: The IOP status is not affected by a LAN shutdown.
+ */
+RC_RETURN
+RCShutdownLANCard(U16 AdapterID, U16 ResourceFlags, PU32 ReturnAddr, PFNCALLBACK CallbackFunction);
+
+ /*
+ ** RCResetIOP();
+ ** Initializes IOPState to I2O_IOP_STATE_RESET.
+ ** Stops access to outbound message Q.
+ ** Discards any outstanding transmit or posted receive buffers.
+ ** Clears outbound message Q.
+ */
+RC_RETURN
+RCResetIOP(U16 AdapterID);
+
+#endif /* RCLANMTL_H */
diff -u --recursive --new-file v2.0.36/linux/drivers/net/rcmtl.c linux/drivers/net/rcmtl.c
--- v2.0.36/linux/drivers/net/rcmtl.c Sun Nov 15 21:51:46 1998
+++ linux/drivers/net/rcmtl.c Wed Dec 31 16:00:00 1969
@@ -1,2058 +0,0 @@


-/*
-** *************************************************************************
-**
-**

-** R C M T L . C $Revision: 1.1 $
-**
-**
-** RedCreek Message Transport Layer program module.


-**
-** ---------------------------------------------------------------------
-** --- Copyright (c) 1997-1998, RedCreek Communications Inc. ---
-** --- All rights reserved. ---
-** ---------------------------------------------------------------------
-**
-** File Description:
-**

-** Host side message transport layer.
-**
-** This program is free software; you can redistribute it and/or modify
-** it under the terms of the GNU General Public License as published by
-** the Free Software Foundation; either version 2 of the License, or
-** (at your option) any later version.
-
-** This program is distributed in the hope that it will be useful,
-** but WITHOUT ANY WARRANTY; without even the implied warranty of
-** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-** GNU General Public License for more details.
-
-** You should have received a copy of the GNU General Public License
-** along with this program; if not, write to the Free Software
-** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-**
-***************************************************************************/
-
-#undef DEBUG
-
-#define RC_LINUX_MODULE
-#include "rcmtl.h"
-
-#define dprintf kprintf
-
-extern int printk(const char * fmt, ...);
-
- /* RedCreek LAN device Target ID */
-#define LAN_TARGET_ID 0x10
- /* RedCreek's OSM default LAN receive Initiator */
-#define DEFAULT_RECV_INIT_CONTEXT 0xA17
-
-
-/*
-** message structures
-*/
-
-#define TID_SZ 12
-#define FUNCTION_SZ 8
-
-/* Transaction Reply Lists (TRL) Control Word structure */
-
-#define TRL_SINGLE_FIXED_LENGTH 0x00
-#define TRL_SINGLE_VARIABLE_LENGTH 0x40
-#define TRL_MULTIPLE_FIXED_LENGTH 0x80
-
-/* LAN Class specific functions */
-
-#define LAN_PACKET_SEND 0x3B
-#define LAN_SDU_SEND 0x3D
-#define LAN_RECEIVE_POST 0x3E
-#define LAN_RESET 0x35
-#define LAN_SHUTDOWN 0x37
-
-/* Private Class specfic function */
-#define RC_PRIVATE 0xFF
-
-/* RC Executive Function Codes. */
-
-#define RC_CMD_ADAPTER_ASSIGN 0xB3
-#define RC_CMD_ADAPTER_READ 0xB2
-#define RC_CMD_ADAPTER_RELEASE 0xB5
-#define RC_CMD_BIOS_INFO_SET 0xA5
-#define RC_CMD_BOOT_DEVICE_SET 0xA7
-#define RC_CMD_CONFIG_VALIDATE 0xBB
-#define RC_CMD_CONN_SETUP 0xCA
-#define RC_CMD_DEVICE_ASSIGN 0xB7
-#define RC_CMD_DEVICE_RELEASE 0xB9
-#define RC_CMD_HRT_GET 0xA8
-#define RC_CMD_ADAPTER_CLEAR 0xBE
-#define RC_CMD_ADAPTER_CONNECT 0xC9
-#define RC_CMD_ADAPTER_RESET 0xBD
-#define RC_CMD_LCT_NOTIFY 0xA2
-#define RC_CMD_OUTBOUND_INIT 0xA1
-#define RC_CMD_PATH_ENABLE 0xD3
-#define RC_CMD_PATH_QUIESCE 0xC5
-#define RC_CMD_PATH_RESET 0xD7
-#define RC_CMD_STATIC_MF_CREATE 0xDD
-#define RC_CMD_STATIC_MF_RELEASE 0xDF
-#define RC_CMD_STATUS_GET 0xA0
-#define RC_CMD_SW_DOWNLOAD 0xA9
-#define RC_CMD_SW_UPLOAD 0xAB
-#define RC_CMD_SW_REMOVE 0xAD
-#define RC_CMD_SYS_ENABLE 0xD1
-#define RC_CMD_SYS_MODIFY 0xC1
-#define RC_CMD_SYS_QUIESCE 0xC3
-#define RC_CMD_SYS_TAB_SET 0xA3
-
-
- /* Init Outbound Q status */
-#define RC_CMD_OUTBOUND_INIT_IN_PROGRESS 0x01
-#define RC_CMD_OUTBOUND_INIT_REJECTED 0x02
-#define RC_CMD_OUTBOUND_INIT_FAILED 0x03
-#define RC_CMD_OUTBOUND_INIT_COMPLETE 0x04
-
-
-#define UTIL_NOP 0x00
-
-
-/* RC Get Status State values */
-
-#define ADAPTER_STATE_INITIALIZING 0x01
-#define ADAPTER_STATE_RESET 0x02
-#define ADAPTER_STATE_HOLD 0x04
-#define ADAPTER_STATE_READY 0x05
-#define ADAPTER_STATE_OPERATIONAL 0x08
-#define ADAPTER_STATE_FAILED 0x10
-#define ADAPTER_STATE_FAULTED 0x11
-
-
-/* Defines for Request Status Codes: Table 3-1 Reply Status Codes. */
-
-#define RC_REPLY_STATUS_SUCCESS 0x00
-#define RC_REPLY_STATUS_ABORT_DIRTY 0x01
-#define RC_REPLY_STATUS_ABORT_NO_DATA_TRANSFER 0x02
-#define RC_REPLY_STATUS_ABORT_PARTIAL_TRANSFER 0x03
-#define RC_REPLY_STATUS_ERROR_DIRTY 0x04
-#define RC_REPLY_STATUS_ERROR_NO_DATA_TRANSFER 0x05
-#define RC_REPLY_STATUS_ERROR_PARTIAL_TRANSFER 0x06
-#define RC_REPLY_STATUS_PROCESS_ABORT_DIRTY 0x07
-#define RC_REPLY_STATUS_PROCESS_ABORT_NO_DATA_TRANSFER 0x08
-#define RC_REPLY_STATUS_PROCESS_ABORT_PARTIAL_TRANSFER 0x09
-#define RC_REPLY_STATUS_TRANSACTION_ERROR 0x0A
-#define RC_REPLY_STATUS_PROGRESS_REPORT 0x80
-
-
-/* DetailedStatusCode defines for ALL messages: Table 3-2 Detailed Status Codes.*/
-
-#define RC_DS_SUCCESS 0x0000
-#define RC_DS_BAD_KEY 0x0001
-#define RC_DS_CHAIN_BUFFER_TOO_LARGE 0x0002
-#define RC_DS_DEVICE_BUSY 0x0003
-#define RC_DS_DEVICE_LOCKED 0x0004
-#define RC_DS_DEVICE_NOT_AVAILABLE 0x0005
-#define RC_DS_DEVICE_RESET 0x0006
-#define RC_DS_INAPPROPRIATE_FUNCTION 0x0007
-#define RC_DS_INSUFFICIENT_RESOURCE_HARD 0x0008
-#define RC_DS_INSUFFICIENT_RESOURCE_SOFT 0x0009
-#define RC_DS_INVALID_INITIATOR_ADDRESS 0x000A
-#define RC_DS_INVALID_MESSAGE_FLAGS 0x000B
-#define RC_DS_INVALID_OFFSET 0x000C
-#define RC_DS_INVALID_PARAMETER 0x000D
-#define RC_DS_INVALID_REQUEST 0x000E
-#define RC_DS_INVALID_TARGET_ADDRESS 0x000F
-#define RC_DS_MESSAGE_TOO_LARGE 0x0010
-#define RC_DS_MESSAGE_TOO_SMALL 0x0011
-#define RC_DS_MISSING_PARAMETER 0x0012
-#define RC_DS_NO_SUCH_PAGE 0x0013
-#define RC_DS_REPLY_BUFFER_FULL 0x0014
-#define RC_DS_TCL_ERROR 0x0015
-#define RC_DS_TIMEOUT 0x0016
-#define RC_DS_UNKNOWN_ERROR 0x0017
-#define RC_DS_UNKNOWN_FUNCTION 0x0018
-#define RC_DS_UNSUPPORTED_FUNCTION 0x0019
-#define RC_DS_UNSUPPORTED_VERSION 0x001A
-
- /* msg header defines for VersionOffset */
-#define RCMSGVER_1 0x0001
-#define SGL_OFFSET_0 RCMSGVER_1
-#define SGL_OFFSET_4 (0x0040 | RCMSGVER_1)
-#define TRL_OFFSET_5 (0x0050 | RCMSGVER_1)
-#define TRL_OFFSET_6 (0x0060 | RCMSGVER_1)
-
- /* msg header defines for MsgFlags */
-#define MSG_STATIC 0x0100
-#define MSG_64BIT_CNTXT 0x0200
-#define MSG_MULTI_TRANS 0x1000
-#define MSG_FAIL 0x2000
-#define MSG_LAST 0x4000
-#define MSG_REPLY 0x8000
-
- /* normal LAN request message MsgFlags and VersionOffset (0x1041) */
-#define LAN_MSG_REQST (MSG_MULTI_TRANS | SGL_OFFSET_4)
-
- /* minimum size msg */
-#define THREE_WORD_MSG_SIZE 0x00030000
-#define FOUR_WORD_MSG_SIZE 0x00040000
-#define FIVE_WORD_MSG_SIZE 0x00050000
-#define SIX_WORD_MSG_SIZE 0x00060000
-#define SEVEN_WORD_MSG_SIZE 0x00070000
-#define EIGHT_WORD_MSG_SIZE 0x00080000
-#define NINE_WORD_MSG_SIZE 0x00090000
-
-/* Special TID Assignments */
-
-#define ADAPTER_TID 0
-#define HOST_TID 1
-
- /* RedCreek private message codes */
-#define RC_PRIVATE_GET_MAC_ADDR 0x0001/**/ /* OBSOLETE */


SHAR_EOF
true || echo 'restore of patch-2.0.37 failed'
fi

echo 'End of part 13'
echo 'File patch-2.0.37 is continued in part 14'
echo 14 > _shar_seq_.tmp

Thomas...@ciw.uni-karlsruhe.de

unread,
Jun 16, 1999, 3:00:00 AM6/16/99
to
Archive-name: v2.0/patch-2.0.37/part16

#!/bin/sh
# this is part 16 of a 45 - part archive


# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.0.37 continued
if test ! -r _shar_seq_.tmp; then
echo 'Please unpack part 1 first!'
exit 1
fi
(read Scheck

if test "$Scheck" != 16; then


echo Please unpack part "$Scheck" next!
exit 1
else
exit 0
fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.0.37'
else
echo 'x - continuing with patch-2.0.37'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.0.37' &&

+ * schedule a timer callback routine to execute 3 seconds
+ * later; this routine will reinitialize the adapter at that time.
+ */
+ RCResetLANCard(pDpa->id,
+ RC_RESOURCE_RETURN_POSTED_RX_BUCKETS |
+ RC_RESOURCE_RETURN_PEND_TX_BUFFERS,0,
+ (PFNCALLBACK)RCreset_callback);
X }
X
X
@@ -699,7 +738,7 @@
X * RCrecv_callback()
X *
X * The receive packet callback routine. This is called by
- * RCProcMsgQ() after the adapter posts buffers which have been
+ * RCProcI2OMsgQ() after the adapter posts buffers which have been
X * filled (one ethernet packet per buffer).


X */
X static void

@@ -710,134 +749,149 @@
X U16 AdapterID)
X {
X
- U32 len, count;
- PDPA pDpa;
- struct sk_buff *skb;
- struct device *dev;
- singleTCB tcb;
- psingleTCB ptcb = &tcb;
+ U32 len, count;
+ PDPA pDpa;
+ struct sk_buff *skb;
+ struct device *dev;
+ singleTCB tcb;
+ psingleTCB ptcb = &tcb;
X
X
- pDpa = PCIAdapters[AdapterID];
- dev = pDpa->dev;
+ pDpa = PCIAdapters[AdapterID];
+ dev = pDpa->dev;
X
- ptcb->bcount = 1;
+ ptcb->bcount = 1;
X
X #ifdef RCDEBUG
- printk("rc: RCrecv_callback: 0x%x, 0x%x, 0x%x\n",
- (uint)PktCount, (uint)BucketsRemain, (uint)PacketDescBlock);
+ printk("rc: RCrecv_callback: 0x%x, 0x%x, 0x%x\n",
+ (uint)PktCount, (uint)BucketsRemain, (uint)PacketDescBlock);
X #endif
X
X #ifdef RCDEBUG
- if ((pDpa->shutdown || pDpa->reboot) && !Status)
- printk("shutdown||reboot && !Status: PktCount = %d\n",PktCount);
+ if ((pDpa->shutdown || pDpa->reboot) && !Status)
+ printk("shutdown||reboot && !Status: PktCount = %d\n",PktCount);
X #endif
X
- if ( (Status != RC_REPLY_STATUS_SUCCESS) || pDpa->shutdown)
- {
- /*
- * Free whatever buffers the adapter returned, but don't
- * pass them to the kernel.
- */
+ if ( (Status != I2O_REPLY_STATUS_SUCCESS) || pDpa->shutdown)
+ {
+ /*
+ * Free whatever buffers the adapter returned, but don't
+ * pass them to the kernel.
+ */
X
- if (!pDpa->shutdown && !pDpa->reboot)
- printk("rc: RCrecv error: status = 0x%x\n", (uint)Status);
- else
- printk("rc: Returning %d buffers, status = 0x%x\n",
- PktCount, (uint)Status);
- /*
- * TO DO: check the nature of the failure and put the adapter in
- * failed mode if it's a hard failure. Send a reset to the adapter
- * and free all outstanding memory.
- */
- if (Status == RC_REPLY_STATUS_ABORT_NO_DATA_TRANSFER)
- {
-#ifdef RCDEBUG
- printk("RCrecv status ABORT NO DATA TRANSFER\n");
-#endif
- }
- /* check for reset status: RC_REPLY_STATUS_ABORT_NO_DATA_TRANSFER */
- if (PacketDescBlock)
- {
- while(PktCount--)
- {
- skb = (struct sk_buff *)PacketDescBlock[0];
- skb->free = 1;
- skb->lock = 0;
-#ifdef RCDEBUG
- printk("free skb 0x%p\n", skb);
-#endif
- dev_kfree_skb(skb, FREE_READ);
- pDpa->numOutRcvBuffers--;
- PacketDescBlock += BD_SIZE; /* point to next context field */
- }
- }
- return;
- }
- else
- {
- while(PktCount--)
- {
+ if (!pDpa->shutdown && !pDpa->reboot)
+ printk("rc: RCrecv error: status = 0x%x\n", (uint)Status);
+#ifdef RCDEBUG
+ else
+ printk("rc: Returning %d buffers, status = 0x%x\n",
+ PktCount, (uint)Status);
+#endif
+ /*
+ * TO DO: check the nature of the failure and put the adapter in
+ * failed mode if it's a hard failure. Send a reset to the adapter
+ * and free all outstanding memory.
+ */
+ if (Status == I2O_REPLY_STATUS_ABORT_NO_DATA_TRANSFER)
+ {
+#ifdef RCDEBUG
+ printk("RCrecv status ABORT NO DATA TRANSFER\n");
+#endif
+ }
+ /* check for reset status: I2O_REPLY_STATUS_ABORT_NO_DATA_TRANSFER */
+ if (PacketDescBlock)
+ {
+ while(PktCount--)
+ {
X skb = (struct sk_buff *)PacketDescBlock[0];
+#ifndef LINUX_2_1
+ skb->free = 1;
+ skb->lock = 0;
+#endif
X #ifdef RCDEBUG
- if (pDpa->shutdown)
- printk("shutdown: skb=0x%x\n", (uint)skb);
-
- printk("skb = 0x%x: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", (uint)skb,
- (uint)skb->data[0], (uint)skb->data[1], (uint)skb->data[2],
- (uint)skb->data[3], (uint)skb->data[4], (uint)skb->data[5]);
+ printk("free skb 0x%p\n", skb);
+#endif
+#ifdef LINUX_2_1
+ dev_kfree_skb (skb);
+#else
+ dev_kfree_skb(skb, FREE_READ);
X #endif
- if ( (memcmp(dev->dev_addr, skb->data, 6)) &&
- (!broadcast_packet(skb->data)))
+ pDpa->numOutRcvBuffers--;
+ PacketDescBlock += BD_SIZE; /* point to next context field */
+ }
+ }
+ return;
+ }
+ else
+ {
+ while(PktCount--)
+ {
+ skb = (struct sk_buff *)PacketDescBlock[0];
+#ifdef RCDEBUG
+ if (pDpa->shutdown)
+ printk("shutdown: skb=0x%x\n", (uint)skb);
+
+ printk("skb = 0x%x: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", (uint)skb,
+ (uint)skb->data[0], (uint)skb->data[1], (uint)skb->data[2],
+ (uint)skb->data[3], (uint)skb->data[4], (uint)skb->data[5]);
+#endif
+
+#ifdef PROMISCUOUS_BY_DEFAULT /* early 2.x firmware */
+ if ( (memcmp(dev->dev_addr, skb->data, 6)) &&
+ (!broadcast_packet(skb->data)))
+ {
+ /*
+ * Re-post the buffer to the adapter. Since the adapter usually
+ * return 1 to 2 receive buffers at a time, it's not too inefficient
+ * post one buffer at a time but ... may be that should be
+ * optimized at some point.
+ */
+ ptcb->b.context = (U32)skb;
+ ptcb->b.scount = 1;
+ ptcb->b.size = MAX_ETHER_SIZE;
+ ptcb->b.addr = virt_to_bus((void *)skb->data);
+
+ if ( RCPostRecvBuffers(pDpa->id, (PRCTCB)ptcb ) != RC_RTN_NO_ERROR)
X {
- /*
- * Re-post the buffer to the adapter. Since the adapter usually
- * return 1 to 2 receive buffers at a time, it's not too inefficient
- * post one buffer at a time but ... may be that should be
- * optimized at some point.
- */
- ptcb->b.context = (U32)skb;
- ptcb->b.scount = 1;
- ptcb->b.size = MAX_ETHER_SIZE;
- ptcb->b.addr = (U32)skb->data;
-
- if ( RCPostRecvBuffers(pDpa->id, (PRCTCB)ptcb ) != RC_RTN_NO_ERROR)
- {
- printk("rc: RCrecv_callback: post buffer failed!\n");
- skb->free = 1;
- dev_kfree_skb(skb, FREE_READ);
- }
- else
- {
- pDpa->numOutRcvBuffers++;
- }
+ printk("rc: RCrecv_callback: post buffer failed!\n");
+#ifdef LINUX_2_1
+ dev_kfree_skb (skb);
+#else
+ skb->free = 1;
+ dev_kfree_skb(skb, FREE_READ);
+#endif
X }
X else
X {
- len = PacketDescBlock[2];


- skb->dev = dev;

- skb_put( skb, len ); /* adjust length and tail */
- skb->protocol = eth_type_trans(skb, dev);
- netif_rx(skb); /* send the packet to the kernel */
- dev->last_rx = jiffies;
+ pDpa->numOutRcvBuffers++;
X }
- pDpa->numOutRcvBuffers--;
- PacketDescBlock += BD_SIZE; /* point to next context field */
- }
- }
+ }
+ else
+#endif /* PROMISCUOUS_BY_DEFAULT */
+ {
+ len = PacketDescBlock[2];


+ skb->dev = dev;

+ skb_put( skb, len ); /* adjust length and tail */
+ skb->protocol = eth_type_trans(skb, dev);
+ netif_rx(skb); /* send the packet to the kernel */
+ dev->last_rx = jiffies;
+ }
+ pDpa->numOutRcvBuffers--;
+ PacketDescBlock += BD_SIZE; /* point to next context field */
+ }
+ }
X
- /*
- * Replenish the posted receive buffers.
- * DO NOT replenish buffers if the driver has already
- * initiated a reboot or shutdown!
- */
-
- if (!pDpa->shutdown && !pDpa->reboot)
- {
- count = RC_allocate_and_post_buffers(dev,
- MAX_NMBR_RCV_BUFFERS-pDpa->numOutRcvBuffers);
- pDpa->numOutRcvBuffers += count;
- }
+ /*
+ * Replenish the posted receive buffers.
+ * DO NOT replenish buffers if the driver has already
+ * initiated a reboot or shutdown!
+ */
+
+ if (!pDpa->shutdown && !pDpa->reboot)
+ {
+ count = RC_allocate_and_post_buffers(dev,
+ MAX_NMBR_RCV_BUFFERS-pDpa->numOutRcvBuffers);
+ pDpa->numOutRcvBuffers += count;
+ }
X
X }
X
@@ -846,156 +900,159 @@
X *
X * Interrupt handler.
X * This routine sets up a couple of pointers and calls
- * RCProcMsgQ(), which in turn process the message and
+ * RCProcI2OMsgQ(), which in turn process the message and
X * calls one of our callback functions.


X */
X static void

X RCinterrupt(int irq, void *dev_id, struct pt_regs *regs)
X {
X
- PDPA pDpa;
- struct device *dev = (struct device *)(dev_id);
+ PDPA pDpa;
+ struct device *dev = (struct device *)(dev_id);
X
- pDpa = (PDPA) (dev->priv);
+ pDpa = (PDPA) (dev->priv);
X
- if (pDpa->shutdown)
- printk("rc: shutdown: service irq\n");
-
X #ifdef RCDEBUG
- printk("RC irq: pDpa = 0x%x, dev = 0x%x, id = %d\n",
- (uint)pDpa, (uint)dev, (uint)pDpa->id);
- printk("dev = 0x%x\n", (uint)dev);
+ if (pDpa->shutdown)
+ printk("rc: shutdown: service irq\n");
+
+ printk("RC irq: pDpa = 0x%x, dev = 0x%x, id = %d\n",
+ (uint)pDpa, (uint)dev, (uint)pDpa->id);
+ printk("dev = 0x%x\n", (uint)dev);
X #endif
- if (dev->interrupt)
- printk("%s: Re-entering the interrupt handler.\n", dev->name);
- dev->interrupt = 1;
+ if (dev->interrupt)
+ printk("%s: Re-entering the interrupt handler.\n", dev->name);
+ dev->interrupt = 1;
X
- RCProcMsgQ(pDpa->id);
- dev->interrupt = 0;
+ RCProcI2OMsgQ(pDpa->id);


+ dev->interrupt = 0;

X
- return;
+ return;
X }
X
-#define REBOOT_REINIT_RETRY_LIMIT 10
+
+#define REBOOT_REINIT_RETRY_LIMIT 4
X static void rc_timer(unsigned long data)
X {
- struct device *dev = (struct device *)data;
- PDPA pDpa = (PDPA) (dev->priv);
- int init_status;
- static int retry = 0;
- int post_buffers = MAX_NMBR_RCV_BUFFERS;
- int count = 0;
- int requested = 0;
-
- if (pDpa->reboot)
- {
-
- init_status = InitRCApiMsgLayer(pDpa->id, dev->base_addr,
- pDpa->PLanApiPA, pDpa->PLanApiPA,
- (PFNTXCALLBACK)RCxmit_callback,
- (PFNRXCALLBACK)RCrecv_callback,
- (PFNCALLBACK)RCreboot_callback);
-
- switch(init_status)
- {
- case RC_RTN_NO_ERROR:
+ struct device *dev = (struct device *)data;
+ PDPA pDpa = (PDPA) (dev->priv);
+ int init_status;
+ static int retry = 0;
+ int post_buffers = MAX_NMBR_RCV_BUFFERS;
+ int count = 0;
+ int requested = 0;
+
+ if (pDpa->reboot)
+ {
+ init_status = RCInitI2OMsgLayer(pDpa->id, dev->base_addr,
+ pDpa->PLanApiPA,
+ (PU8)virt_to_bus((void *)pDpa->PLanApiPA),
+ (PFNTXCALLBACK)RCxmit_callback,
+ (PFNRXCALLBACK)RCrecv_callback,
+ (PFNCALLBACK)RCreboot_callback);
+
+ switch(init_status)
+ {
+ case RC_RTN_NO_ERROR:
X
- pDpa->reboot = 0;
- pDpa->shutdown = 0; /* just in case */
- RCReportDriverCapability(pDpa->id, DriverControlWord);
- RCEnableAdapterInterrupts(pDpa->id);
-
- if (dev->flags & IFF_UP)
- {
- while(post_buffers)
- {
- if (post_buffers > MAX_NMBR_POST_BUFFERS_PER_MSG)
- requested = MAX_NMBR_POST_BUFFERS_PER_MSG;
- else
- requested = post_buffers;
- count = RC_allocate_and_post_buffers(dev, requested);
- post_buffers -= count;
- if ( count < requested )
- break;
- }
- pDpa->numOutRcvBuffers =
- MAX_NMBR_RCV_BUFFERS - post_buffers;
- printk("rc: posted %d buffers \r\n",
- (uint)pDpa->numOutRcvBuffers);
- }
- printk("rc: Initialization done.\n");
- return;
- case RC_RTN_FREE_Q_EMPTY:
- retry++;
- printk("rc: inbound free q emtpy\n");
- break;
- default:
- retry++;
- printk("rc: unexpected bad status after reboot\n");
- break;
- }
-
- if (retry > REBOOT_REINIT_RETRY_LIMIT)
- {
- printk("rc: unable to reinitialize adapter after reboot\n");
- printk("rc: decrementing driver and closing interface\n");
- RCDisableAdapterInterrupts(pDpa->id);
- dev->flags &= ~IFF_UP;
- MOD_DEC_USE_COUNT;
- }
- else
- {
- printk("rc: rescheduling timer...\n");
- init_timer(&pDpa->timer);
- pDpa->timer.expires = RUN_AT((30*HZ)/10); /* 3 sec. */
- pDpa->timer.data = (unsigned long)dev;
- pDpa->timer.function = &rc_timer; /* timer handler */
- add_timer(&pDpa->timer);
- }
- }
- else
- {
- printk("rc: timer??\n");
- }
+ pDpa->reboot = 0;
+ pDpa->shutdown = 0; /* just in case */
+ RCReportDriverCapability(pDpa->id, DriverControlWord);
+ RCEnableI2OInterrupts(pDpa->id);
+
+ if (dev->flags & IFF_UP)
+ {
+ while(post_buffers)
+ {
+ if (post_buffers > MAX_NMBR_POST_BUFFERS_PER_MSG)
+ requested = MAX_NMBR_POST_BUFFERS_PER_MSG;
+ else
+ requested = post_buffers;
+ count = RC_allocate_and_post_buffers(dev, requested);
+ post_buffers -= count;
+ if ( count < requested )
+ break;
+ }
+ pDpa->numOutRcvBuffers =
+ MAX_NMBR_RCV_BUFFERS - post_buffers;
+ printk("rc: posted %d buffers \r\n",
+ (uint)pDpa->numOutRcvBuffers);
+ }
+ printk("rc: Initialization done.\n");
+ dev->tbusy=0;
+ retry=0;
+ return;
+ case RC_RTN_FREE_Q_EMPTY:
+ retry++;
+ printk("rc: inbound free q empty\n");
+ break;
+ default:
+ retry++;
+ printk("rc: bad status after reboot: %d\n", init_status);
+ break;
+ }
+
+ if (retry > REBOOT_REINIT_RETRY_LIMIT)
+ {
+ printk("rc: unable to reinitialize adapter after reboot\n");
+ printk("rc: decrementing driver and closing interface\n");
+ RCDisableI2OInterrupts(pDpa->id);
+ dev->flags &= ~IFF_UP;
+ MOD_DEC_USE_COUNT;
+ }
+ else
+ {
+ printk("rc: rescheduling timer...\n");
+ init_timer(&pDpa->timer);
+ pDpa->timer.expires = RUN_AT((40*HZ)/10); /* 3 sec. */
+ pDpa->timer.data = (unsigned long)dev;
+ pDpa->timer.function = &rc_timer; /* timer handler */
+ add_timer(&pDpa->timer);
+ }
+ }
+ else
+ {
+ printk("rc: timer??\n");
+ }


X }
X
X static int

X RCclose(struct device *dev)
X {
X
- PDPA pDpa = (PDPA) dev->priv;
+ PDPA pDpa = (PDPA) dev->priv;
X
X #ifdef RCDEBUG
- printk("rc: RCclose\r\n");
+ printk("rc: RCclose\r\n");
X #endif
- if (pDpa->reboot)
- {
- printk("rc: skipping reset -- adapter already in reboot mode\n");
- dev->flags &= ~IFF_UP;
- pDpa->shutdown = 1;
- return 0;
- }
+ if (pDpa->reboot)
+ {
+ printk("rc: skipping reset -- adapter already in reboot mode\n");
+ dev->flags &= ~IFF_UP;
+ pDpa->shutdown = 1;
+ return 0;
+ }
X #ifdef RCDEBUG
- printk("rc: receive buffers outstanding: %d\n",
- (uint)pDpa->numOutRcvBuffers);
+ printk("rc: receive buffers outstanding: %d\n",
+ (uint)pDpa->numOutRcvBuffers);
X #endif
X
- pDpa->shutdown = 1;
+ pDpa->shutdown = 1;
X
- /*
- * We can't allow the driver to be unloaded until the adapter returns
- * all posted receive buffers. It doesn't hurt to tell the adapter
- * to return all posted receive buffers and outstanding xmit buffers,
- * even if there are none.
- */
+ /*
+ * We can't allow the driver to be unloaded until the adapter returns
+ * all posted receive buffers. It doesn't hurt to tell the adapter
+ * to return all posted receive buffers and outstanding xmit buffers,
+ * even if there are none.
+ */
X
- RCShutdownLANCard(pDpa->id,
- RC_RESOURCE_RETURN_POSTED_RX_BUCKETS |
- RC_RESOURCE_RETURN_PEND_TX_BUFFERS,0,
- (PFNCALLBACK)RCreset_callback);
+ RCShutdownLANCard(pDpa->id,
+ RC_RESOURCE_RETURN_POSTED_RX_BUCKETS |
+ RC_RESOURCE_RETURN_PEND_TX_BUFFERS,0,
+ (PFNCALLBACK)RCreset_callback);
X
- dev->flags &= ~IFF_UP;
- return 0;
+ dev->flags &= ~IFF_UP;
+ return 0;
X }
X
X static struct enet_statistics *
@@ -1097,140 +1154,200 @@
X
X switch (cmd) {
X
- case RCU_PROTOCOL_REV:
- /*
- * Assign user protocol revision, to tell user-level
- * controller program whether or not it's in sync.
- */
- rq->ifr_ifru.ifru_data = (caddr_t) USER_PROTOCOL_REV;
- break;
+ case RCU_PROTOCOL_REV:
+ /*
+ * Assign user protocol revision, to tell user-level
+ * controller program whether or not it's in sync.
+ */
+ rq->ifr_ifru.ifru_data = (caddr_t) USER_PROTOCOL_REV;
+ break;
X
X
- case RCU_COMMAND:
- {
- int error;
-
- error=verify_area(VERIFY_WRITE, rq->ifr_data, sizeof(RCuser));
- if (error) {
- return error;
- }
- memcpy_fromfs(&RCuser, rq->ifr_data, sizeof(RCuser));
+ case RCU_COMMAND:
+ {
+#ifdef LINUX_2_1
+ if(copy_from_user(&RCuser, rq->ifr_data, sizeof(RCuser)))
+ return -EFAULT;
+#else
+ int error;
+ error=verify_area(VERIFY_WRITE, rq->ifr_data, sizeof(RCuser));
+ if (error) {
+ return error;
+ }
+ memcpy_fromfs(&RCuser, rq->ifr_data, sizeof(RCuser));
+#endif
X
X #ifdef RCDEBUG
- printk("RCioctl: RCuser_cmd = 0x%x\n", RCuser.cmd);
+ printk("RCioctl: RCuser_cmd = 0x%x\n", RCuser.cmd);
X #endif
X
- switch(RCuser.cmd)
+ switch(RCuser.cmd)
+ {
+ case RCUC_GETFWVER:
+ printk("RC GETFWVER\n");
+ RCUD_GETFWVER = &RCuser.RCUS_GETFWVER;
+ RCGetFirmwareVer(pDpa->id, (PU8) &RCUD_GETFWVER->FirmString, NULL);
+ break;
+ case RCUC_GETINFO:
+ printk("RC GETINFO\n");
+ RCUD_GETINFO = &RCuser.RCUS_GETINFO;
+ RCUD_GETINFO -> mem_start = dev->base_addr;
+ RCUD_GETINFO -> mem_end = dev->base_addr + 2*32768;
+ RCUD_GETINFO -> base_addr = pDpa->pci_addr;
+ RCUD_GETINFO -> irq = dev->irq;
+ break;
+ case RCUC_GETIPANDMASK:
+ printk("RC GETIPANDMASK\n");
+ RCUD_GETIPANDMASK = &RCuser.RCUS_GETIPANDMASK;
+ RCGetRavlinIPandMask(pDpa->id, (PU32) &RCUD_GETIPANDMASK->IpAddr,
+ (PU32) &RCUD_GETIPANDMASK->NetMask, NULL);
+ break;
+ case RCUC_GETLINKSTATISTICS:
+ printk("RC GETLINKSTATISTICS\n");
+ RCUD_GETLINKSTATISTICS = &RCuser.RCUS_GETLINKSTATISTICS;
+ RCGetLinkStatistics(pDpa->id, (P_RCLINKSTATS) &RCUD_GETLINKSTATISTICS->StatsReturn, NULL);
+ break;
+ case RCUC_GETLINKSTATUS:
+ printk("RC GETLINKSTATUS\n");
+ RCUD_GETLINKSTATUS = &RCuser.RCUS_GETLINKSTATUS;
+ RCGetLinkStatus(pDpa->id, (PU32) &RCUD_GETLINKSTATUS->ReturnStatus, NULL);
+ break;
+ case RCUC_GETMAC:
+ printk("RC GETMAC\n");
+ RCUD_GETMAC = &RCuser.RCUS_GETMAC;
+ RCGetMAC(pDpa->id, (PU8) &RCUD_GETMAC->mac, NULL);
+ break;
+ case RCUC_GETPROM:
+ printk("RC GETPROM\n");
+ RCUD_GETPROM = &RCuser.RCUS_GETPROM;
+ RCGetPromiscuousMode(pDpa->id, (PU32) &RCUD_GETPROM->PromMode, NULL);
+ break;
+ case RCUC_GETBROADCAST:
+ printk("RC GETBROADCAST\n");
+ RCUD_GETBROADCAST = &RCuser.RCUS_GETBROADCAST;
+ RCGetBroadcastMode(pDpa->id, (PU32) &RCUD_GETBROADCAST->BroadcastMode, NULL);
+ break;
+ case RCUC_GETSPEED:
+ printk("RC GETSPEED\n");
+ if (!(dev->flags & IFF_UP))
X {
- case RCUC_GETFWVER:
- printk("RC GETFWVER\n");
- RCUD_GETFWVER = &RCuser.RCUS_GETFWVER;
- RCGetFirmwareVer(pDpa->id, (PU8) &RCUD_GETFWVER->FirmString, NULL);
- break;
- case RCUC_GETINFO:
- printk("RC GETINFO\n");
- RCUD_GETINFO = &RCuser.RCUS_GETINFO;
- RCUD_GETINFO -> mem_start = dev->base_addr;
- RCUD_GETINFO -> mem_end = dev->base_addr + 32768;
- RCUD_GETINFO -> base_addr = pDpa->pci_addr;
- RCUD_GETINFO -> irq = dev->irq;
- break;
- case RCUC_GETIPANDMASK:
- printk("RC GETIPANDMASK\n");
- RCUD_GETIPANDMASK = &RCuser.RCUS_GETIPANDMASK;
- RCGetRavlinIPandMask(pDpa->id, (PU32) &RCUD_GETIPANDMASK->IpAddr,
- (PU32) &RCUD_GETIPANDMASK->NetMask, NULL);
- break;
- case RCUC_GETLINKSTATISTICS:
- printk("RC GETLINKSTATISTICS\n");
- RCUD_GETLINKSTATISTICS = &RCuser.RCUS_GETLINKSTATISTICS;
- RCGetLinkStatistics(pDpa->id, (P_RCLINKSTATS) &RCUD_GETLINKSTATISTICS->StatsReturn, NULL);
- break;
- case RCUC_GETLINKSTATUS:
- printk("RC GETLINKSTATUS\n");
- RCUD_GETLINKSTATUS = &RCuser.RCUS_GETLINKSTATUS;
- RCGetLinkStatus(pDpa->id, (PU32) &RCUD_GETLINKSTATUS->ReturnStatus, NULL);
- break;
- case RCUC_GETMAC:
- printk("RC GETMAC\n");
- RCUD_GETMAC = &RCuser.RCUS_GETMAC;
- RCGetMAC(pDpa->id, (PU8) &RCUD_GETMAC->mac, NULL);
- break;
- case RCUC_GETSPEED:
- printk("RC GETSPEED\n");
- if (!(dev->flags & IFF_UP))
- {
- printk("RCioctl, GETSPEED error: interface down\n");
- return -ENODATA;
- }
- RCUD_GETSPEED = &RCuser.RCUS_GETSPEED;
- RCGetLinkSpeed(pDpa->id, (PU32) &RCUD_GETSPEED->LinkSpeedCode, NULL);
- printk("RC speed = 0x%ld\n", RCUD_GETSPEED->LinkSpeedCode);
- break;
- default:
- printk("RC command default\n");
- RCUD_DEFAULT = &RCuser.RCUS_DEFAULT;
- RCUD_DEFAULT -> rc = 0x11223344;
- break;
+ printk("RCioctl, GETSPEED error: interface down\n");
+ return -ENODATA;
X }
- memcpy_tofs(rq->ifr_data, &RCuser, sizeof(RCuser));
+ RCUD_GETSPEED = &RCuser.RCUS_GETSPEED;
+ RCGetLinkSpeed(pDpa->id, (PU32) &RCUD_GETSPEED->LinkSpeedCode, NULL);
+ printk("RC speed = 0x%ld\n", RCUD_GETSPEED->LinkSpeedCode);
+ break;
+ case RCUC_SETIPANDMASK:
+ printk("RC SETIPANDMASK\n");
+ RCUD_SETIPANDMASK = &RCuser.RCUS_SETIPANDMASK;
+ printk ("RC New IP Addr = %d.%d.%d.%d, ", (U8) ((RCUD_SETIPANDMASK->IpAddr) & 0xff),
+ (U8) ((RCUD_SETIPANDMASK->IpAddr >> 8) & 0xff),
+ (U8) ((RCUD_SETIPANDMASK->IpAddr >> 16) & 0xff),
+ (U8) ((RCUD_SETIPANDMASK->IpAddr >> 24) & 0xff));
+ printk ("RC New Mask = %d.%d.%d.%d\n", (U8) ((RCUD_SETIPANDMASK->NetMask) & 0xff),
+ (U8) ((RCUD_SETIPANDMASK->NetMask >> 8) & 0xff),
+ (U8) ((RCUD_SETIPANDMASK->NetMask >> 16) & 0xff),
+ (U8) ((RCUD_SETIPANDMASK->NetMask >> 24) & 0xff));
+ RCSetRavlinIPandMask(pDpa->id, (U32) RCUD_SETIPANDMASK->IpAddr,
+ (U32) RCUD_SETIPANDMASK->NetMask);
+ break;
+ case RCUC_SETMAC:
+ printk("RC SETMAC\n");
+ RCUD_SETMAC = &RCuser.RCUS_SETMAC;
+ printk ("RC New MAC addr = %02X:%02X:%02X:%02X:%02X:%02X\n",
+ (U8) (RCUD_SETMAC->mac[0]), (U8) (RCUD_SETMAC->mac[1]), (U8) (RCUD_SETMAC->mac[2]),
+ (U8) (RCUD_SETMAC->mac[3]), (U8) (RCUD_SETMAC->mac[4]), (U8) (RCUD_SETMAC->mac[5]));
+ RCSetMAC(pDpa->id, (PU8) &RCUD_SETMAC->mac);
+ break;
+ case RCUC_SETSPEED:
+ printk("RC SETSPEED\n");
+ RCUD_SETSPEED = &RCuser.RCUS_SETSPEED;
+ RCSetLinkSpeed(pDpa->id, (U16) RCUD_SETSPEED->LinkSpeedCode);
+ printk("RC New speed = 0x%d\n", RCUD_SETSPEED->LinkSpeedCode);
+ break;
+ case RCUC_SETPROM:
+ printk("RC SETPROM\n");
+ RCUD_SETPROM = &RCuser.RCUS_SETPROM;
+ RCSetPromiscuousMode(pDpa->id,(U16)RCUD_SETPROM->PromMode);
+ printk("RC New prom mode = 0x%d\n", RCUD_SETPROM->PromMode);
+ break;
+ case RCUC_SETBROADCAST:
+ printk("RC SETBROADCAST\n");
+ RCUD_SETBROADCAST = &RCuser.RCUS_SETBROADCAST;
+ RCSetBroadcastMode(pDpa->id,(U16)RCUD_SETBROADCAST->BroadcastMode);
+ printk("RC New broadcast mode = 0x%d\n", RCUD_SETBROADCAST->BroadcastMode);
X break;
- } /* RCU_COMMAND */
-
X default:
- printk("RC default\n");
- rq->ifr_ifru.ifru_data = (caddr_t) 0x12345678;
+ printk("RC command default\n");
+ RCUD_DEFAULT = &RCuser.RCUS_DEFAULT;
+ RCUD_DEFAULT -> rc = 0x11223344;
X break;
+ }
+#ifdef LINUX_2_1
+ copy_to_user(rq->ifr_data, &RCuser, sizeof(RCuser));
+#else
+ memcpy_tofs(rq->ifr_data, &RCuser, sizeof(RCuser));
+#endif
+ break;
+ } /* RCU_COMMAND */
+
+ default:
+ printk("RC default\n");
+ rq->ifr_ifru.ifru_data = (caddr_t) 0x12345678;
+ break;


X }
X return 0;
X }

X
X static int RCconfig(struct device *dev, struct ifmap *map)
X {
- /*
- * To be completed ...
+ /*
+ * To be completed ...
X */
- printk("rc: RCconfig\n");
- return 0;
- if (dev->flags & IFF_UP) /* can't act on a running interface */
- return -EBUSY;
+ printk("rc: RCconfig\n");
+ return 0;
+ if (dev->flags & IFF_UP) /* can't act on a running interface */
+ return -EBUSY;
X
X /* Don't allow changing the I/O address */
- if (map->base_addr != dev->base_addr) {
- printk(KERN_WARNING "RC pci45: Change I/O address not implemented\n");
- return -EOPNOTSUPP;
- }
- return 0;
+ if (map->base_addr != dev->base_addr) {
+ printk(KERN_WARNING "RC pci45: Change I/O address not implemented\n");
+ return -EOPNOTSUPP;
+ }
+ return 0;
X }
X
+
X #ifdef MODULE
-void cleanup_module(void)
+void
+cleanup_module(void)
X {
- PDPA pDpa;
- struct device *next;
+ PDPA pDpa;
+ struct device *next;
X
X
X #ifdef RCDEBUG
- printk("rc: RC cleanup_module\n");
- printk("rc: root_RCdev = 0x%x\n", (uint)root_RCdev);
+ printk("rc: RC cleanup_module\n");
+ printk("rc: root_RCdev = 0x%x\n", (uint)root_RCdev);
X #endif
X
X
- while (root_RCdev)
- {
- pDpa = (PDPA) root_RCdev->priv;
+ while (root_RCdev)
+ {
+ pDpa = (PDPA) root_RCdev->priv;
X #ifdef RCDEBUG
- printk("rc: cleanup 0x%08X\n", (uint)root_RCdev);
+ printk("rc: cleanup 0x%08X\n", (uint)root_RCdev);
X #endif
- printk("Adapter reset: 0x%x\n", RCResetAdapter(pDpa->id));
- unregister_netdev(root_RCdev);
- next = pDpa->next;
-
- vfree((unsigned long *)root_RCdev->base_addr);
- free_irq( root_RCdev->irq, root_RCdev );
- kfree(root_RCdev);
- root_RCdev = next;
- }
+ printk("IOP reset: 0x%x\n", RCResetIOP(pDpa->id));
+ unregister_netdev(root_RCdev);
+ next = pDpa->next;
+
+ iounmap((unsigned long *)root_RCdev->base_addr);
+ free_irq( root_RCdev->irq, root_RCdev );
+ kfree(root_RCdev);
+ root_RCdev = next;
+ }
X }
X #endif
X
@@ -1239,94 +1356,100 @@
X RC_allocate_and_post_buffers(struct device *dev, int numBuffers)
X {
X
- int i;
- PDPA pDpa = (PDPA)dev->priv;
- PU32 p;
- psingleB pB;
- struct sk_buff *skb;
- RC_RETURN status;
-
- if (!numBuffers)
- return 0;
- else if (numBuffers > MAX_NMBR_POST_BUFFERS_PER_MSG)
- {
+ int i;
+ PDPA pDpa = (PDPA)dev->priv;
+ PU32 p;
+ psingleB pB;
+ struct sk_buff *skb;
+ RC_RETURN status;
+
+ if (!numBuffers)
+ return 0;
+ else if (numBuffers > MAX_NMBR_POST_BUFFERS_PER_MSG)
+ {
X #ifdef RCDEBUG
- printk("rc: Too many buffers requested!\n");
- printk("rc: attempting to allocate only 32 buffers\n");
+ printk("rc: Too many buffers requested!\n");
+ printk("rc: attempting to allocate only 32 buffers\n");
X #endif
- numBuffers = 32;
- }
+ numBuffers = 32;
+ }
X
- p = (PU32) kmalloc(sizeof(U32) + numBuffers*sizeof(singleB), GFP_ATOMIC);
+ p = (PU32) kmalloc(sizeof(U32) + numBuffers*sizeof(singleB), GFP_ATOMIC);
X
X #ifdef RCDEBUG
- printk("rc: TCB = 0x%x\n", (uint)p);
+ printk("rc: TCB = 0x%x\n", (uint)p);
X #endif
X
- if (!p)
- {
- printk("rc: RCopen: unable to allocate TCB\n");
- return 0;
- }
-
- p[0] = 0; /* Buffer Count */
- pB = (psingleB)((U32)p + sizeof(U32)); /* point to the first buffer */
-
-#ifdef RCDEBUG
- printk("rc: p[0] = 0x%x, p = 0x%x, pB = 0x%x\n", (uint)p[0], (uint)p, (uint)pB);
- printk("rc: pB = 0x%x\n", (uint)pB);
-#endif
-
- for (i=0; i<numBuffers; i++)
- {
- skb = dev_alloc_skb(MAX_ETHER_SIZE+2);
- if (!skb)
- {
- printk("rc: Doh! RCopen: unable to allocate enough skbs!\n");
- if (*p != 0) /* did we allocate any buffers at all? */
- {
-#ifdef RCDEBUG
- printk("rc: will post only %d buffers \n", (uint)(*p));
-#endif
- break;
- }
- else
- {
- kfree(p); /* Free the TCB */
- return 0;
- }
- }
-#ifdef RCDEBUG
- printk("post 0x%x\n", (uint)skb);
-#endif
- skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
- pB->context = (U32)skb;
- pB->scount = 1; /* segment count */
- pB->size = MAX_ETHER_SIZE;
- pB->addr = (U32)skb->data;
- p[0]++;
- pB++;
- }
-
- if ( (status = RCPostRecvBuffers(pDpa->id, (PRCTCB)p )) != RC_RTN_NO_ERROR)
- {
- printk("rc: Post buffer failed with error code 0x%x!\n", status);
- pB = (psingleB)((U32)p + sizeof(U32)); /* point to the first buffer */
- while(p[0])
- {
- skb = (struct sk_buff *)pB->context;
- skb->free = 1;
-#ifdef RCDEBUG
- printk("rc: freeing 0x%x\n", (uint)skb);
-#endif
- dev_kfree_skb(skb, FREE_READ);
- p[0]--;
- pB++;
- }
-#ifdef RCDEBUG
- printk("rc: freed all buffers, p[0] = %ld\n", p[0]);
-#endif
- }
- kfree(p);
- return(p[0]); /* return the number of posted buffers */
+ if (!p)
+ {
+ printk("rc: RCopen: unable to allocate TCB\n");


+ return 0;
+ }
+

+ p[0] = 0; /* Buffer Count */
+ pB = (psingleB)((U32)p + sizeof(U32)); /* point to the first buffer */
+
+#ifdef RCDEBUG
+ printk("rc: p[0] = 0x%x, p = 0x%x, pB = 0x%x\n", (uint)p[0], (uint)p, (uint)pB);
+ printk("rc: pB = 0x%x\n", (uint)pB);
+#endif
+
+ for (i=0; i<numBuffers; i++)
+ {
+ skb = dev_alloc_skb(MAX_ETHER_SIZE+2);
+ if (!skb)
+ {
+ printk("rc: Doh! RCopen: unable to allocate enough skbs!\n");
+ if (*p != 0) /* did we allocate any buffers at all? */
+ {
+#ifdef RCDEBUG
+ printk("rc: will post only %d buffers \n", (uint)(*p));
+#endif
+ break;
+ }
+ else
+ {
+ kfree(p); /* Free the TCB */
+ return 0;
+ }
+ }
+#ifdef RCDEBUG
+ printk("post 0x%x\n", (uint)skb);
+#endif


+ skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */

+ pB->context = (U32)skb;
+ pB->scount = 1; /* segment count */
+ pB->size = MAX_ETHER_SIZE;
+ pB->addr = virt_to_bus((void *)skb->data);
+ p[0]++;
+ pB++;
+ }
+
+ if ( (status = RCPostRecvBuffers(pDpa->id, (PRCTCB)p )) != RC_RTN_NO_ERROR)
+ {
+ printk("rc: Post buffer failed with error code 0x%x!\n", status);
+ pB = (psingleB)((U32)p + sizeof(U32)); /* point to the first buffer */
+ while(p[0])
+ {
+ skb = (struct sk_buff *)pB->context;
+#ifndef LINUX_2_1
+ skb->free = 1;
+#endif
+#ifdef RCDEBUG
+ printk("rc: freeing 0x%x\n", (uint)skb);
+#endif
+#ifdef LINUX_2_1
+ dev_kfree_skb (skb);
+#else
+ dev_kfree_skb(skb, FREE_READ);
+#endif
+ p[0]--;
+ pB++;
+ }
+#ifdef RCDEBUG
+ printk("rc: freed all buffers, p[0] = %ld\n", p[0]);
+#endif
+ }
+ kfree(p);
+ return(p[0]); /* return the number of posted buffers */
X }
diff -u --recursive --new-file v2.0.36/linux/drivers/net/rtl8139.c linux/drivers/net/rtl8139.c
--- v2.0.36/linux/drivers/net/rtl8139.c Sun Nov 15 21:51:46 1998
+++ linux/drivers/net/rtl8139.c Sun Jun 13 10:21:01 1999
@@ -20,11 +20,22 @@


X */
X
X static const char *version =

-"rtl8139.c:v0.99B 4/7/98 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/rtl8139.html\n";
+"rtl8139.c:v1.04 9/22/98 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/rtl8139.html\n";


X
X /* A few user-configurable values. */

X /* Maximum events (Rx packets, etc.) to handle at each interrupt. */

-static int max_interrupt_work = 10;
+static int max_interrupt_work = 20;
+#define rtl8129_debug debug
+static int rtl8129_debug = 1;
+
+/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast).
+ The RTL chips use a 64 element hash table based on the Ethernet CRC. */
+static int multicast_filter_limit = 32;
+
+/* Used to pass the full-duplex flag, etc. */
+#define MAX_UNITS 8 /* More are supported, limit only on options */
+static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};


+static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
X

X /* Size of the in-memory receive ring. */
X #define RX_BUF_LEN_IDX 3 /* 0==8K, 1==16K, 2==32K, 3==64K */
@@ -39,12 +50,13 @@
X /* The following settings are log_2(bytes)-4: 0 == 16 bytes .. 6==1024. */
X #define RX_FIFO_THRESH 4 /* Rx buffer level before first PCI xfer. */
X #define RX_DMA_BURST 4 /* Maximum PCI burst, '4' is 256 bytes */
-#define TX_DMA_BURST 4
+#define TX_DMA_BURST 4 /* Calculate as 16<<val. */
X
X /* Operational parameters that usually are not changed. */


X /* Time in jiffies before concluding the transmitter is hung. */

-#define TX_TIMEOUT ((4000*HZ)/1000)
+#define TX_TIMEOUT (4*HZ)


X
+#include <linux/config.h>
X #ifdef MODULE
X #ifdef MODVERSIONS
X #include <linux/modversions.h>

@@ -60,40 +72,49 @@
X #include <linux/sched.h>


X #include <linux/string.h>
X #include <linux/timer.h>
-#include <linux/ptrace.h>
X #include <linux/errno.h>
X #include <linux/ioport.h>
X #include <linux/malloc.h>
X #include <linux/interrupt.h>
X #include <linux/pci.h>
-#include <linux/bios32.h>

+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>

X #include <asm/processor.h> /* Processor type for cache alignment. */


X #include <asm/bitops.h>
X #include <asm/io.h>
-#include <asm/dma.h>
X

-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>

+/* Kernel compatibility defines, some common to David Hind's PCMCIA package.
+ This is only in the support-all-kernels source code. */
X
X #define RUN_AT(x) (jiffies + (x))
X
X #include <linux/delay.h>
X
-#if (LINUX_VERSION_CODE < 0x20123)
+#if LINUX_VERSION_CODE < 0x20123


X #define test_and_set_bit(val, addr) set_bit(val, addr)
X #endif

+#if LINUX_VERSION_CODE <= 0x20139
+#define net_device_stats enet_statistics

+#else
+#define NETSTATS_VER2
+#endif
+#if LINUX_VERSION_CODE < 0x20155 || defined(CARDBUS)
+/* Grrrr, the PCI code changed, but did not consider CardBus... */
+#include <linux/bios32.h>


+#define PCI_SUPPORT_VER1
+#else
+#define PCI_SUPPORT_VER2
+#endif

+#if LINUX_VERSION_CODE < 0x20159
+#define dev_free_skb(skb) dev_kfree_skb(skb, FREE_WRITE);
+#else
+#define dev_free_skb(skb) dev_kfree_skb(skb);
+#endif
X

X /* The I/O extent. */

X #define RTL8129_TOTAL_SIZE 0x80
X
-#ifdef HAVE_DEVLIST
-struct netdev_entry rtl8139_drv =
-{"RTL8139", rtl8139_probe, RTL8129_TOTAL_SIZE, NULL};
-#endif
-
-static int rtl8129_debug = 1;
-
X /*
X Theory of Operation
X
@@ -139,16 +160,45 @@
X IVc. Errata
X
X */
+
+


+/* This table drives the PCI probe routines. It's mostly boilerplate in all
+ of the drivers, and will likely be provided by some future kernel.

+ Note the matching code -- the first table entry matchs all 56** cards but
+ second only the 1234 card.


+*/
+enum pci_flags_bit {
+ PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
+ PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3,
+};
+struct pci_id_info {
+ const char *name;
+ u16 vendor_id, device_id, device_id_mask, flags;

+ int io_size;
+ struct device *(*probe1)(int pci_bus, int pci_devfn, struct device *dev,


+ long ioaddr, int irq, int chip_idx, int fnd_cnt);

+};
+
+static struct device * rtl8129_probe1(int pci_bus, int pci_devfn,


+ struct device *dev, long ioaddr,

+ int irq, int chp_idx, int fnd_cnt);
+


+static struct pci_id_info pci_tbl[] =

+{{ "RealTek RTL8129 Fast Ethernet",
+ 0x10ec, 0x8129, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 0x80, rtl8129_probe1},
+ { "RealTek RTL8139 Fast Ethernet",
+ 0x10ec, 0x8139, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 0x80, rtl8129_probe1},
+ { "RealTek RTL8139 Fast Ethernet (mislabeled)",
+ 0x1113, 0x1211, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 0x80, rtl8129_probe1},


+ {0,}, /* 0 terminated list. */
+};

+
+/* The capability table matches the chip table above. */
+enum {HAS_MII_XCVR=0x01, HAS_CHIP_XCVR=0x02, HAS_LNK_CHNG=0x04};
+static int rtl_cap_tbl[] = {
+ HAS_MII_XCVR, HAS_CHIP_XCVR|HAS_LNK_CHNG, HAS_CHIP_XCVR|HAS_LNK_CHNG,
+};
X
-#ifndef PCI_VENDOR_ID_REALTEK
-#define PCI_VENDOR_ID_REALTEK 0x10ec
-#endif
-#ifndef PCI_DEVICE_ID_REALTEK_8129
-#define PCI_DEVICE_ID_REALTEK_8129 0x8129
-#endif
-#ifndef PCI_DEVICE_ID_REALTEK_8139
-#define PCI_DEVICE_ID_REALTEK_8139 0x8139
-#endif
X

X /* The rest of these values should never change. */

X #define NUM_TX_DESC 4 /* Number of Tx descriptor registers. */
@@ -157,7 +207,7 @@
X enum RTL8129_registers {
X MAC0=0, /* Ethernet hardware address. */
X MAR0=8, /* Multicast filter. */
- TxStat0=0x10, /* Transmit status (Four 32bit registers). */
+ TxStatus0=0x10, /* Transmit status (Four 32bit registers). */
X TxAddr0=0x20, /* Tx descriptors (also four 32bit). */
X RxBuf=0x30, RxEarlyCnt=0x34, RxEarlyStatus=0x36,
X ChipCmd=0x37, RxBufPtr=0x38, RxBufAddr=0x3A,
@@ -168,7 +218,8 @@
X Cfg9346=0x50, Config0=0x51, Config1=0x52,
X FlashReg=0x54, GPPinData=0x58, GPPinDir=0x59, MII_SMI=0x5A, HltClk=0x5B,
X MultiIntr=0x5C, TxSummary=0x60,
- BMCR=0x62, BMSR=0x64, NWayAdvert=0x66, NWayLPAR=0x68, NWayExpansion=0x6A,
+ MII_BMCR=0x62, MII_BMSR=0x64, NWayAdvert=0x66, NWayLPAR=0x68,
+ NWayExpansion=0x6A,
X /* Undocumented registers, but required for proper operation. */
X FIFOTMS=0x70, /* FIFO Test Mode Select */
X CSCR=0x74, /* Chip Status and Configuration Register. */
@@ -214,24 +265,24 @@
X struct device *next_module;
X int chip_id;
X int chip_revision;
+ unsigned char pci_bus, pci_devfn;
X #if LINUX_VERSION_CODE > 0x20139
X struct net_device_stats stats;
X #else
X struct enet_statistics stats;
X #endif


X struct timer_list timer; /* Media selection timer. */

- unsigned int cur_rx, cur_tx; /* The next free and used entries */
- unsigned int dirty_rx, dirty_tx;
+ unsigned int cur_rx; /* Index into the Rx buffer of next Rx pkt. */
+ unsigned int cur_tx, dirty_tx, tx_flag;
X /* The saved address of a sent-in-place packet/buffer, for skfree(). */
X struct sk_buff* tx_skbuff[NUM_TX_DESC];
X unsigned char *tx_buf[NUM_TX_DESC]; /* Tx bounce buffers */
X unsigned char *rx_ring;
X unsigned char *tx_bufs; /* Tx bounce buffer region. */
- unsigned char mc_filter[8]; /* Current multicast filter. */
X char phys[4]; /* MII device addresses. */
- int in_interrupt; /* Alpha needs word-wide lock. */


X unsigned int tx_full:1; /* The Tx queue is full. */

X unsigned int full_duplex:1; /* Full-duplex operation requested. */
+ unsigned int duplex_lock:1; /* Full-duplex operation requested. */
X unsigned int default_port:4; /* Last dev->if_port value. */
X unsigned int media2:4; /* Secondary monitored media port. */
X unsigned int medialock:1; /* Don't sense media type. */
@@ -239,24 +290,21 @@


X };
X
X #ifdef MODULE

-/* Used to pass the full-duplex flag, etc. */
-static int options[] = {-1, -1, -1, -1, -1, -1, -1, -1};
-static int full_duplex[] = {-1, -1, -1, -1, -1, -1, -1, -1};
-#if LINUX_VERSION_CODE > 0x20118
+#if LINUX_VERSION_CODE > 0x20115


X MODULE_AUTHOR("Donald Becker <bec...@cesdis.gsfc.nasa.gov>");

X MODULE_DESCRIPTION("RealTek RTL8129/8139 Fast Ethernet driver");
-MODULE_PARM(debug, "i");
-MODULE_PARM(options, "1-" __MODULE_STRING(8) "i");
-MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i");
+MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
+MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
+MODULE_PARM(multicast_filter_limit, "i");
X MODULE_PARM(max_interrupt_work, "i");
+MODULE_PARM(debug, "i");
X #endif
X #endif
X
-static struct device *rtl8129_probe1(struct device *dev, int ioaddr, int irq,
- int chip_id, int options, int card_idx);
X static int rtl8129_open(struct device *dev);


-static int read_eeprom(int ioaddr, int location);
-static int mdio_read(int ioaddr, int phy_id, int location);

+static int read_eeprom(long ioaddr, int location);
+static int mdio_read(struct device *dev, int phy_id, int location);
+static void mdio_write(struct device *dev, int phy_id, int location, int val);
X static void rtl8129_timer(unsigned long data);
X static void rtl8129_tx_timeout(struct device *dev);
X static void rtl8129_init_ring(struct device *dev);
@@ -264,145 +312,138 @@
X static int rtl8129_rx(struct device *dev);
X static void rtl8129_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
X static int rtl8129_close(struct device *dev);
+static int mii_ioctl(struct device *dev, struct ifreq *rq, int cmd);
X static struct enet_statistics *rtl8129_get_stats(struct device *dev);
+static inline u32 ether_crc(int length, unsigned char *data);
X static void set_rx_mode(struct device *dev);
X
X
-#ifdef MODULE
X /* A list of all installed RTL8129 devices, for removing the driver module. */
X static struct device *root_rtl8129_dev = NULL;
-#endif
+
+/* Ideally we would detect all network cards in slot order. That would
+ be best done a central PCI probe dispatch, which wouldn't work
+ well when dynamically adding drivers. So instead we detect just the
+ Rtl81*9 cards in slot order. */
X
X int rtl8139_probe(struct device *dev)


X {
X int cards_found = 0;

- static int pci_index = 0; /* Static, for multiple probe calls. */
+ int pci_index = 0;
+ unsigned char pci_bus, pci_device_fn;
X
- /* Ideally we would detect all network cards in slot order. That would
- be best done a central PCI probe dispatch, which wouldn't work
- well with the current structure. So instead we detect just the
- Rtl81*9 cards in slot order. */
-
- if (pcibios_present()) {
- unsigned char pci_bus, pci_device_fn;
-
- for (;pci_index < 0xff; pci_index++) {
- u8 pci_irq_line, pci_latency;


- u16 pci_command, new_command, vendor, device;

- u32 pci_ioaddr;
+ if ( ! pcibios_present())
+ return -ENODEV;


X
- if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8,

-#ifdef REVERSE_PROBE_ORDER
- 0xff - pci_index,
-#else
- pci_index,
-#endif
- &pci_bus, &pci_device_fn)
- != PCIBIOS_SUCCESSFUL)


+ for (;pci_index < 0xff; pci_index++) {

+ u16 vendor, device, pci_command, new_command;
+ int chip_idx, irq;
+ long ioaddr;
+


+ if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8, pci_index,
+ &pci_bus, &pci_device_fn)

+ != PCIBIOS_SUCCESSFUL)
+ break;
+ pcibios_read_config_word(pci_bus, pci_device_fn,
+ PCI_VENDOR_ID, &vendor);
+ pcibios_read_config_word(pci_bus, pci_device_fn,
+ PCI_DEVICE_ID, &device);
+


+ for (chip_idx = 0; pci_tbl[chip_idx].vendor_id; chip_idx++)
+ if (vendor == pci_tbl[chip_idx].vendor_id
+ && (device & pci_tbl[chip_idx].device_id_mask) ==
+ pci_tbl[chip_idx].device_id)

X break;
- pcibios_read_config_word(pci_bus, pci_device_fn,
- PCI_VENDOR_ID, &vendor);
- if (vendor != PCI_VENDOR_ID_REALTEK)
- continue;


+ if (pci_tbl[chip_idx].vendor_id == 0) /* Compiled out! */
+ continue;

X
- pcibios_read_config_word(pci_bus, pci_device_fn,
- PCI_DEVICE_ID, &device);
+ {
+#if defined(PCI_SUPPORT_VER2)


+ struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn);

+ ioaddr = pdev->base_address[0] & ~3;


+ irq = pdev->irq;

+#else


+ u32 pci_ioaddr;
+ u8 pci_irq_line;
X pcibios_read_config_byte(pci_bus, pci_device_fn,
X PCI_INTERRUPT_LINE, &pci_irq_line);

X pcibios_read_config_dword(pci_bus, pci_device_fn,
X PCI_BASE_ADDRESS_0, &pci_ioaddr);

- /* Remove I/O space marker in bit 0. */
- pci_ioaddr &= ~3;
-

- if (device != PCI_DEVICE_ID_REALTEK_8129
- && device != PCI_DEVICE_ID_REALTEK_8139) {
- printk(KERN_NOTICE "Unknown RealTek PCI ethernet chip type "
- "%4.4x detected: not configured.\n", device);
- continue;
- }
- if (check_region(pci_ioaddr, RTL8129_TOTAL_SIZE))
- continue;
+ ioaddr = pci_ioaddr & ~3;
+ irq = pci_irq_line;
+#endif
+ }
X
- /* Activate the card: fix for brain-damaged Win98 BIOSes. */


- pcibios_read_config_word(pci_bus, pci_device_fn,
- PCI_COMMAND, &pci_command);
- new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO;
- if (pci_command != new_command) {
- printk(KERN_INFO " The PCI BIOS has not enabled this"

- " device! Updating PCI config %4.4x->%4.4x.\n",


- pci_command, new_command);
- pcibios_write_config_word(pci_bus, pci_device_fn,
- PCI_COMMAND, new_command);
- }

+ if ((pci_tbl[chip_idx].flags & PCI_USES_IO) &&
+ check_region(ioaddr, pci_tbl[chip_idx].io_size))
+ continue;
+
+ /* Activate the card: fix for brain-damaged Win98 BIOSes. */


+ pcibios_read_config_word(pci_bus, pci_device_fn,
+ PCI_COMMAND, &pci_command);

+ new_command = pci_command | (pci_tbl[chip_idx].flags & 7);


+ if (pci_command != new_command) {

+ printk(KERN_INFO " The PCI BIOS has not enabled the"
+ " device at %d/%d! Updating PCI command %4.4x->%4.4x.\n",
+ pci_bus, pci_device_fn, pci_command, new_command);


+ pcibios_write_config_word(pci_bus, pci_device_fn,
+ PCI_COMMAND, new_command);

+ }
X
-#ifdef MODULE
- dev = rtl8129_probe1(dev, pci_ioaddr, pci_irq_line, device,


- options[cards_found], cards_found);

-#else
- dev = rtl8129_probe1(dev, pci_ioaddr, pci_irq_line, device,
- dev ? dev->mem_start : 0, -1);
-#endif
+ dev = pci_tbl[chip_idx].probe1(pci_bus, pci_device_fn, dev, ioaddr,


+ irq, chip_idx, cards_found);
X

- if (dev) {


- pcibios_read_config_byte(pci_bus, pci_device_fn,
- PCI_LATENCY_TIMER, &pci_latency);
- if (pci_latency < 32) {

- printk(KERN_NOTICE" PCI latency timer (CFLT) is "
- "unreasonably low at %d. Setting to 64 clocks.\n",
- pci_latency);
- pcibios_write_config_byte(pci_bus, pci_device_fn,
- PCI_LATENCY_TIMER, 64);
- } else if (rtl8129_debug > 1)
- printk(KERN_INFO" PCI latency timer (CFLT) is %#x.\n",
- pci_latency);
- dev = 0;
- cards_found++;
+ if (dev && (pci_tbl[chip_idx].flags & PCI_COMMAND_MASTER)) {
+ u8 pci_latency;


+ pcibios_read_config_byte(pci_bus, pci_device_fn,
+ PCI_LATENCY_TIMER, &pci_latency);
+ if (pci_latency < 32) {

+ printk(KERN_NOTICE " PCI latency timer (CFLT) is "
+ "unreasonably low at %d. Setting to 64 clocks.\n",
+ pci_latency);
+ pcibios_write_config_byte(pci_bus, pci_device_fn,
+ PCI_LATENCY_TIMER, 64);
X }
X }
+ dev = 0;
+ cards_found++;
X }
X
-#if defined (MODULE)
- return cards_found;
-#else
X return cards_found ? 0 : -ENODEV;
-#endif
X }
X
-static struct device *rtl8129_probe1(struct device *dev, int ioaddr, int irq,
- int chip_id, int options, int card_idx)
+static struct device * rtl8129_probe1(int pci_bus, int pci_devfn,


+ struct device *dev, long ioaddr,

+ int irq, int chip_idx, int found_cnt)


X {
X static int did_version = 0; /* Already printed version info. */

X struct rtl8129_private *tp;
- int i;
+ int i, option = found_cnt < MAX_UNITS ? options[found_cnt] : 0;
X
X if (rtl8129_debug > 0 && did_version++ == 0)
X printk(KERN_INFO "%s", version);
X

X dev = init_etherdev(dev, 0);
X

- printk(KERN_INFO "%s: RealTek RTL%x at %#3x, IRQ %d, ",
- dev->name, chip_id, ioaddr, irq);
+ printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ",
+ dev->name, pci_tbl[chip_idx].name, ioaddr, irq);


X
X /* Bring the chip out of low-power mode. */

X outb(0x00, ioaddr + Config1);
X
- /* Perhaps this should be read from the EEPROM? */
- for (i = 0; i < 6; i++)
- dev->dev_addr[i] = inb(ioaddr + MAC0 + i);
+ if (read_eeprom(ioaddr, 0) != 0xffff)
+ for (i = 0; i < 3; i++)
+ ((u16 *)(dev->dev_addr))[i] = read_eeprom(ioaddr, i + 7);
+ else
+ for (i = 0; i < 6; i++)
+ dev->dev_addr[i] = inb(ioaddr + MAC0 + i);
X
X for (i = 0; i < 5; i++)
X printk("%2.2x:", dev->dev_addr[i]);
X printk("%2.2x.\n", dev->dev_addr[i]);
X
- if (rtl8129_debug > 1) {
- printk(KERN_INFO "%s: EEPROM contents\n", dev->name);
- for (i = 0; i < 64; i++)
- printk(" %4.4x%s", read_eeprom(ioaddr, i),
- i%16 == 15 ? "\n"KERN_INFO : "");
- }
-


X /* We do a request_region() to register /proc/ioports info. */

- request_region(ioaddr, RTL8129_TOTAL_SIZE, "RealTek RTL8129/39 Fast Ethernet");


+ request_region(ioaddr, pci_tbl[chip_idx].io_size, dev->name);
X

X dev->base_addr = ioaddr;

X dev->irq = irq;

@@ -412,22 +453,21 @@
X memset(tp, 0, sizeof(*tp));
X dev->priv = tp;
X
-#ifdef MODULE
X tp->next_module = root_rtl8129_dev;
X root_rtl8129_dev = dev;
-#endif
X
- tp->chip_id = chip_id;
+ tp->chip_id = chip_idx;
+ tp->pci_bus = pci_bus;
+ tp->pci_devfn = pci_devfn;


X
X /* Find the connected MII xcvrs.
X Doing this in open() would allow detecting external xcvrs later, but

X takes too much time. */
- if (chip_id == 0x8129) {
+ if (rtl_cap_tbl[chip_idx] & HAS_MII_XCVR) {
X int phy, phy_idx;
X for (phy = 0, phy_idx = 0; phy < 32 && phy_idx < sizeof(tp->phys);
X phy++) {
- int mii_status = mdio_read(ioaddr, phy, 1);
-
+ int mii_status = mdio_read(dev, phy, 1);
X if (mii_status != 0xffff && mii_status != 0x0000) {
X tp->phys[phy_idx++] = phy;
X printk(KERN_INFO "%s: MII transceiver found at address %d.\n",
@@ -441,7 +481,7 @@
X tp->phys[0] = -1;
X }
X } else {
- tp->phys[0] = -1;
+ tp->phys[0] = 32;
X }
X
X /* Put the chip into low-power mode. */
@@ -450,18 +490,21 @@
X outb('H', ioaddr + HltClk); /* 'R' would leave the clock running. */
X
X /* The lower four bits are the media type. */
- if (options > 0) {
- tp->full_duplex = (options & 16) ? 1 : 0;
- tp->default_port = options & 15;
+ if (option > 0) {
+ tp->full_duplex = (option & 0x200) ? 1 : 0;
+ tp->default_port = option & 15;
X if (tp->default_port)
X tp->medialock = 1;
X }
-#ifdef MODULE


- if (card_idx >= 0) {
- if (full_duplex[card_idx] >= 0)

- tp->full_duplex = full_duplex[card_idx];
+
+ if (found_cnt < MAX_UNITS && full_duplex[found_cnt] > 0)
+ tp->full_duplex = full_duplex[found_cnt];
+
+ if (tp->full_duplex) {
+ printk(KERN_INFO "%s: Media type forced to Full Duplex.\n", dev->name);
+ mdio_write(dev, tp->phys[0], 4, 0x141);
+ tp->duplex_lock = 1;
X }
-#endif
X
X /* The Rtl8129-specific entries in the device structure. */
X dev->open = &rtl8129_open;
@@ -469,6 +512,7 @@
X dev->stop = &rtl8129_close;
X dev->get_stats = &rtl8129_get_stats;


X dev->set_multicast_list = &set_rx_mode;

+ dev->do_ioctl = &mii_ioctl;
X
X return dev;
X }
@@ -485,25 +529,21 @@
X #define EE_ENB (0x80 | EE_CS)
X
X /* Delay between EEPROM clock transitions.
- No extra delay is needed with 33Mhz PCI, but 66Mhz is untested.
+ No extra delay is needed with 33Mhz PCI, but 66Mhz may change this.
X */
X
-#ifdef _LINUX_DELAY_H
-#define eeprom_delay(nanosec) udelay(1)
-#else
-#define eeprom_delay(nanosec) do { ; } while (0)
-#endif
+#define eeprom_delay() inl(ee_addr)


X
X /* The EEPROM commands include the alway-set leading bit. */

X #define EE_WRITE_CMD (5 << 6)
X #define EE_READ_CMD (6 << 6)
X #define EE_ERASE_CMD (7 << 6)


X
-static int read_eeprom(int ioaddr, int location)

+static int read_eeprom(long ioaddr, int location)
X {
X int i;
X unsigned retval = 0;
- int ee_addr = ioaddr + Cfg9346;
+ long ee_addr = ioaddr + Cfg9346;


X int read_cmd = location | EE_READ_CMD;

X
X outb(EE_ENB & ~EE_CS, ee_addr);
@@ -513,20 +553,19 @@
X for (i = 10; i >= 0; i--) {


SHAR_EOF
true || echo 'restore of patch-2.0.37 failed'
fi

echo 'End of part 16'
echo 'File patch-2.0.37 is continued in part 17'
echo 17 > _shar_seq_.tmp
exit 0

Thomas...@ciw.uni-karlsruhe.de

unread,
Jun 16, 1999, 3:00:00 AM6/16/99
to
Archive-name: v2.0/patch-2.0.37/part17

#!/bin/sh
# this is part 17 of a 45 - part archive


# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.0.37 continued
if test ! -r _shar_seq_.tmp; then
echo 'Please unpack part 1 first!'
exit 1
fi
(read Scheck

if test "$Scheck" != 17; then


echo Please unpack part "$Scheck" next!
exit 1
else
exit 0
fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.0.37'
else
echo 'x - continuing with patch-2.0.37'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.0.37' &&

X int dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
X outb(EE_ENB | dataval, ee_addr);
- eeprom_delay(100);
+ eeprom_delay();
X outb(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);
- eeprom_delay(150);
- outb(EE_ENB | dataval, ee_addr); /* Finish EEPROM a clock tick. */
- eeprom_delay(250);
+ eeprom_delay();
X }
X outb(EE_ENB, ee_addr);
+ eeprom_delay();
X
X for (i = 16; i > 0; i--) {
X outb(EE_ENB | EE_SHIFT_CLK, ee_addr);
- eeprom_delay(100);
+ eeprom_delay();
X retval = (retval << 1) | ((inb(ee_addr) & EE_DATA_READ) ? 1 : 0);
X outb(EE_ENB, ee_addr);
- eeprom_delay(100);
+ eeprom_delay();
X }
X
X /* Terminate the EEPROM access. */
@@ -544,38 +583,42 @@
X #define MDIO_DATA_OUT 0x04
X #define MDIO_DATA_IN 0x02
X #define MDIO_CLK 0x01
-#ifdef _LINUX_DELAY_H
-#define mdio_delay() udelay(1) /* Really 400ns. */
-#else
-#define mdio_delay() do { ; } while (0)
-#endif
+#define MDIO_WRITE0 (MDIO_DIR)
+#define MDIO_WRITE1 (MDIO_DIR | MDIO_DATA_OUT)
+
+#define mdio_delay() inb(mdio_addr)
+
+static char mii_2_8139_map[8] = {MII_BMCR, MII_BMSR, 0, 0, NWayAdvert,
+ NWayLPAR, NWayExpansion, 0 };
X
X /* Syncronize the MII management interface by shifting 32 one bits out. */
-static void mdio_sync(int ioaddr)
+static void mdio_sync(long mdio_addr)
X {
X int i;
- int mdio_addr = ioaddr + MII_SMI;
X
X for (i = 32; i >= 0; i--) {
- outb(MDIO_DIR | MDIO_DATA_OUT, mdio_addr);
+ outb(MDIO_WRITE1, mdio_addr);
X mdio_delay();
- outb(MDIO_DIR | MDIO_DATA_OUT | MDIO_CLK, mdio_addr);
+ outb(MDIO_WRITE1 | MDIO_CLK, mdio_addr);
X mdio_delay();
X }
X return;
X }


-static int mdio_read(int ioaddr, int phy_id, int location)

+static int mdio_read(struct device *dev, int phy_id, int location)

X {
- int i;
- int read_cmd = (0xf6 << 10) | (phy_id << 5) | location;
+ long mdio_addr = dev->base_addr + MII_SMI;
+ int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location;
X int retval = 0;
- int mdio_addr = ioaddr + MII_SMI;
+ int i;
X
- mdio_sync(ioaddr);
+ if ((phy_id & 0x1f) == 0) { /* Really a 8139. Use internal registers. */
+ return location < 8 && mii_2_8139_map[location] ?
+ inw(dev->base_addr + mii_2_8139_map[location]) : 0;
+ }
+ mdio_sync(mdio_addr);


X /* Shift the read command bits out. */

X for (i = 15; i >= 0; i--) {
- int dataval =
- (read_cmd & (1 << i)) ? MDIO_DATA_OUT : 0;
+ int dataval = (mii_cmd & (1 << i)) ? MDIO_DATA_OUT : 0;
X
X outb(MDIO_DIR | dataval, mdio_addr);
X mdio_delay();
@@ -593,14 +636,45 @@
X }
X return (retval>>1) & 0xffff;
X }
+
+static void mdio_write(struct device *dev, int phy_id, int location, int value)
+{
+ long mdio_addr = dev->base_addr + MII_SMI;
+ int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value;
+ int i;
+
+ if (phy_id == 32) { /* Really a 8139. Use internal registers. */
+ if (location < 8 && mii_2_8139_map[location])
+ outw(value, dev->base_addr + mii_2_8139_map[location]);
+ return;
+ }
+ mdio_sync(mdio_addr);
+
+ /* Shift the command bits out. */
+ for (i = 31; i >= 0; i--) {
+ int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;
+ outb(dataval, mdio_addr);
+ mdio_delay();
+ outb(dataval | MDIO_CLK, mdio_addr);
+ mdio_delay();
+ }
+ /* Clear out extra bits. */
+ for (i = 2; i > 0; i--) {
+ outb(0, mdio_addr);
+ mdio_delay();
+ outb(MDIO_CLK, mdio_addr);
+ mdio_delay();


+ }
+ return;
+}
+

X
X static int
X rtl8129_open(struct device *dev)
X {
X struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;


- int ioaddr = dev->base_addr;
+ long ioaddr = dev->base_addr;

X int i;
- int full_duplex = 0;
X
X /* Soft reset the chip. */
X outb(CmdReset, ioaddr + ChipCmd);
@@ -636,29 +710,26 @@
X outl((RX_FIFO_THRESH << 13) | (RX_BUF_LEN_IDX << 11) | (RX_DMA_BURST<<8),
X ioaddr + RxConfig);
X outl((TX_DMA_BURST<<8)|0x03000000, ioaddr + TxConfig);
+ tp->tx_flag = (TX_FIFO_THRESH<<11) & 0x003f0000;
X
- full_duplex = tp->full_duplex;
- if (tp->phys[0] >= 0 || tp->chip_id == 0x8139) {
- u16 mii_reg5;
- if (tp->chip_id == 0x8139)
- mii_reg5 = inw(ioaddr + NWayLPAR);
- else
- mii_reg5 = mdio_read(ioaddr, tp->phys[0], 5);
+ tp->full_duplex = tp->duplex_lock;
+ if (tp->phys[0] >= 0 || (rtl_cap_tbl[tp->chip_id] & HAS_MII_XCVR)) {
+ u16 mii_reg5 = mdio_read(dev, tp->phys[0], 5);
X if (mii_reg5 == 0xffff)
X ; /* Not there */
X else if ((mii_reg5 & 0x0100) == 0x0100
X || (mii_reg5 & 0x00C0) == 0x0040)
- full_duplex = 1;
+ tp->full_duplex = 1;
X if (rtl8129_debug > 1)
X printk(KERN_INFO"%s: Setting %s%s-duplex based on"
X " auto-negotiated partner ability %4.4x.\n", dev->name,
X mii_reg5 == 0 ? "" :
X (mii_reg5 & 0x0180) ? "100mbps " : "10mbps ",
- full_duplex ? "full" : "half", mii_reg5);
+ tp->full_duplex ? "full" : "half", mii_reg5);
X }
X
X outb(0xC0, ioaddr + Cfg9346);
- outb(full_duplex ? 0x60 : 0x20, ioaddr + Config1);
+ outb(tp->full_duplex ? 0x60 : 0x20, ioaddr + Config1);
X outb(0x00, ioaddr + Cfg9346);
X
X outl(virt_to_bus(tp->rx_ring), ioaddr + RxBuf);
@@ -678,10 +749,10 @@
X | TxErr | TxOK | RxErr | RxOK, ioaddr + IntrMask);
X
X if (rtl8129_debug > 1)
- printk(KERN_DEBUG"%s: rtl8129_open() ioaddr %4.4x IRQ %d"
+ printk(KERN_DEBUG"%s: rtl8129_open() ioaddr %#lx IRQ %d"
X " GP Pins %2.2x %s-duplex.\n",
X dev->name, ioaddr, dev->irq, inb(ioaddr + GPPinData),
- full_duplex ? "full" : "half");
+ tp->full_duplex ? "full" : "half");
X
X /* Set the timer to switch to check for link beat and perhaps switch
X to an alternate media type. */
@@ -698,26 +769,26 @@
X {
X struct device *dev = (struct device *)data;
X struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;


- int ioaddr = dev->base_addr;
+ long ioaddr = dev->base_addr;

X int next_tick = 0;
+ int mii_reg5 = mdio_read(dev, tp->phys[0], 5);
X
- if (tp->chip_id == 0x8139) {
- u16 mii_reg5 = inw(ioaddr + NWayLPAR);
- if ((mii_reg5 & 0x0100) == 0x0100
- || (mii_reg5 & 0x00C0) == 0x0040)
- if ( ! tp->full_duplex) {
- tp->full_duplex = 1;
- if (rtl8129_debug > 0)
- printk(KERN_INFO "%s: Switching to full-duplex based on "
- "link partner ability of %4.4x.\n",
- dev->name, mii_reg5);
- outb(0xC0, ioaddr + Cfg9346);
- outb(tp->full_duplex ? 0x60 : 0x20, ioaddr + Config1);
- outb(0x00, ioaddr + Cfg9346);
- }
+ if (! tp->duplex_lock && mii_reg5 != 0xffff) {
+ int duplex = (mii_reg5&0x0100) || (mii_reg5 & 0x01C0) == 0x0040;
+ if (tp->full_duplex != duplex) {
+ tp->full_duplex = duplex;
+ printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d link"
+ " partner ability of %4.4x.\n", dev->name,
+ tp->full_duplex ? "full" : "half", tp->phys[0], mii_reg5);
+ outb(0xC0, ioaddr + Cfg9346);
+ outb(tp->full_duplex ? 0x60 : 0x20, ioaddr + Config1);
+ outb(0x00, ioaddr + Cfg9346);


+ }
+ next_tick = 60*HZ;

X }
+
X if (rtl8129_debug > 2) {
- if (tp->chip_id == 0x8129)
+ if (rtl_cap_tbl[tp->chip_id] & HAS_MII_XCVR)
X printk(KERN_DEBUG"%s: Media selection tick, GP pins %2.2x.\n",
X dev->name, inb(ioaddr + GPPinData));
X else
@@ -740,41 +811,51 @@


X static void rtl8129_tx_timeout(struct device *dev)

X {
X struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;


- int ioaddr = dev->base_addr;

- int i;


+ long ioaddr = dev->base_addr;

+ int mii_reg, i;
+
+ if (rtl8129_debug > 0)
+ printk(KERN_WARNING "%s: Transmit timeout, status %2.2x %4.4x "
+ "media %2.2x.\n",
+ dev->name, inb(ioaddr + ChipCmd), inw(ioaddr + IntrStatus),
+ inb(ioaddr + GPPinData));
X
X /* Disable interrupts by clearing the interrupt mask. */
X outw(0x0000, ioaddr + IntrMask);
-
- if (rtl8129_debug > 0)
- printk(KERN_WARNING "%s: Transmit timeout, status %2.2x %4.4x.\n",
- dev->name, inb(ioaddr + ChipCmd), inw(ioaddr + IntrStatus));
X /* Emit info to figure out what went wrong. */
+ printk("%s: Tx queue start entry %d dirty entry %d.\n",
+ dev->name, tp->cur_tx, tp->dirty_tx);
X for (i = 0; i < NUM_TX_DESC; i++)
X printk(KERN_DEBUG"%s: Tx descriptor %d is %8.8x.%s\n",
- dev->name, i, inl(ioaddr + TxStat0 + i*4),
+ dev->name, i, inl(ioaddr + TxStatus0 + i*4),
X i == tp->dirty_tx % NUM_TX_DESC ? " (queue head)" : "");
- if (tp->chip_id == 0x8129) {
- int mii_reg;
- printk(KERN_DEBUG"%s: MII #%d registers are:", dev->name, tp->phys[0]);
- for (mii_reg = 0; mii_reg < 8; mii_reg++)
- printk(" %4.4x", mdio_read(ioaddr, tp->phys[0], mii_reg));


- printk(".\n");

- } else {
- printk(KERN_DEBUG"%s: MII status register is %4.4x.\n",
- dev->name, inw(ioaddr + BMSR));
- }
+ printk(KERN_DEBUG"%s: MII #%d registers are:", dev->name, tp->phys[0]);
+ for (mii_reg = 0; mii_reg < 8; mii_reg++)
+ printk(" %4.4x", mdio_read(dev, tp->phys[0], mii_reg));
+ printk(".\n");
X
X /* Soft reset the chip. */
X outb(CmdReset, ioaddr + ChipCmd);
+ /* Check that the chip has finished the reset. */
+ for (i = 1000; i > 0; i--)
+ if ((inb(ioaddr + ChipCmd) & CmdReset) == 0)
+ break;
X for (i = 0; i < 6; i++)
X outb(dev->dev_addr[i], ioaddr + MAC0 + i);
X
+ outb(0x00, ioaddr + Cfg9346);
+ tp->cur_rx = 0;
+ /* Must enable Tx/Rx before setting transfer thresholds! */
+ outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd);
+ outl((RX_FIFO_THRESH << 13) | (RX_BUF_LEN_IDX << 11) | (RX_DMA_BURST<<8),
+ ioaddr + RxConfig);
+ outl((TX_DMA_BURST<<8), ioaddr + TxConfig);
+ set_rx_mode(dev);
X { /* Save the unsent Tx packets. */
X struct sk_buff *saved_skb[NUM_TX_DESC], *skb;
- int j = 0;
- for (; tp->cur_tx - tp->dirty_tx > 0 ; tp->dirty_tx++)
- saved_skb[j++] = tp->tx_skbuff[tp->dirty_tx % NUM_TX_DESC];
+ int j;
+ for (j = 0; tp->cur_tx - tp->dirty_tx > 0 ; j++, tp->dirty_tx++)
+ saved_skb[j] = tp->tx_skbuff[tp->dirty_tx % NUM_TX_DESC];
X tp->dirty_tx = tp->cur_tx = 0;
X
X for (i = 0; i < j; i++) {
@@ -785,27 +866,20 @@
X } else
X outl(virt_to_bus(skb->data), ioaddr + TxAddr0 + i*4);
X /* Note: the chip doesn't have auto-pad! */
- outl(((TX_FIFO_THRESH<<11) & 0x003f0000) |
- (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN),
- ioaddr + TxStat0 + i*4);
+ outl(tp->tx_flag | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN),
+ ioaddr + TxStatus0 + i*4);
X }
X tp->cur_tx = i;
X while (i < NUM_TX_DESC)
X tp->tx_skbuff[i] = 0;
X if (tp->cur_tx - tp->dirty_tx < NUM_TX_DESC) {/* Typical path */
X dev->tbusy = 0;
+ tp->tx_full = 0;
X } else {
X tp->tx_full = 1;
X }
X }
X
- /* Must enable Tx/Rx before setting transfer thresholds! */
- set_rx_mode(dev);
- outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd);
- outl((RX_FIFO_THRESH << 13) | (RX_BUF_LEN_IDX << 11) | (RX_DMA_BURST<<8),
- ioaddr + RxConfig);
- outl((TX_DMA_BURST<<8), ioaddr + TxConfig);
-


X dev->trans_start = jiffies;

X tp->stats.tx_errors++;
X /* Enable all known interrupts by setting the interrupt mask. */
@@ -823,8 +897,8 @@
X int i;
X
X tp->tx_full = 0;
- tp->cur_rx = tp->cur_tx = 0;
- tp->dirty_rx = tp->dirty_tx = 0;
+ tp->cur_rx = 0;
+ tp->dirty_tx = tp->cur_tx = 0;
X
X for (i = 0; i < NUM_TX_DESC; i++) {
X tp->tx_skbuff[i] = 0;
@@ -836,7 +910,7 @@
X rtl8129_start_xmit(struct sk_buff *skb, struct device *dev)
X {
X struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;


- int ioaddr = dev->base_addr;
+ long ioaddr = dev->base_addr;
X int entry;
X
X /* Block a timer-based transmit from overlapping. This could better be

@@ -858,20 +932,19 @@
X } else
X outl(virt_to_bus(skb->data), ioaddr + TxAddr0 + entry*4);
X /* Note: the chip doesn't have auto-pad! */
- outl(((TX_FIFO_THRESH<<11) & 0x003f0000) |
- (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN),
- ioaddr + TxStat0 + entry*4);
+ outl(tp->tx_flag | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN),
+ ioaddr + TxStatus0 + entry*4);
X
X if (++tp->cur_tx - tp->dirty_tx < NUM_TX_DESC) {/* Typical path */


- dev->tbusy = 0;

+ clear_bit(0, (void*)&dev->tbusy);
X } else {
X tp->tx_full = 1;
X }
X

X dev->trans_start = jiffies;

X if (rtl8129_debug > 4)
- printk(KERN_DEBUG"%s: Queued Tx packet at %p size %ld to slot %d.\n",
- dev->name, skb->data, skb->len, entry);
+ printk(KERN_DEBUG"%s: Queued Tx packet at %p size %d to slot %d.\n",
+ dev->name, skb->data, (int)skb->len, entry);


X
X return 0;
X }

@@ -881,23 +954,26 @@


X static void rtl8129_interrupt(int irq, void *dev_instance, struct pt_regs *regs)

X {
X struct device *dev = (struct device *)dev_instance;
- struct rtl8129_private *tp;


- int ioaddr, boguscnt = max_interrupt_work;

+ struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
+ int boguscnt = max_interrupt_work;
X int status;
+ long ioaddr = dev->base_addr;
X
- if (dev == NULL) {
- printk (KERN_ERR"rtl8139_interrupt(): IRQ %d for unknown device.\n",
- irq);


+#if defined(__i386__)
+ /* A lock to prevent simultaneous entry bug on Intel SMP machines. */
+ if (test_and_set_bit(0, (void*)&dev->interrupt)) {

+ printk(KERN_ERR"%s: SMP simultaneous entry of an interrupt handler.\n",
+ dev->name);
+ dev->interrupt = 0; /* Avoid halting machine. */
X return;
X }


-
- ioaddr = dev->base_addr;

- tp = (struct rtl8129_private *)dev->priv;
- if (test_and_set_bit(0, (void*)&tp->in_interrupt)) {


+#else
+ if (dev->interrupt) {

X printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name);


X return;
X }
X dev->interrupt = 1;

+#endif
X
X do {
X status = inw(ioaddr + IntrStatus);
@@ -920,9 +996,9 @@
X
X for (dirty_tx = tp->dirty_tx; dirty_tx < tp->cur_tx; dirty_tx++) {
X int entry = dirty_tx % NUM_TX_DESC;
- int txstatus = inl(ioaddr + TxStat0 + entry*4);
+ int txstatus = inl(ioaddr + TxStatus0 + entry*4);
X
- if ( ! (txstatus & TxHostOwns))
+ if ( ! (txstatus & (TxStatOK | TxUnderrun | TxAborted)))
X break; /* It still hasn't been Txed */
X
X /* Note: TxCarrierLost is always asserted at 100mbps. */
@@ -949,7 +1025,9 @@
X /* No count for tp->stats.tx_deferred */
X #endif
X if (txstatus & TxUnderrun) {
- /* Todo: increase the Tx FIFO threshold. */
+ /* Add 64 to the Tx FIFO threshold. */
+ if (tp->tx_flag < 0x00300000)
+ tp->tx_flag += 0x00020000;
X tp->stats.tx_fifo_errors++;
X }
X tp->stats.collisions += (txstatus >> 24) & 15;
@@ -960,7 +1038,7 @@
X }
X

X /* Free the original skb. */

- dev_kfree_skb(tp->tx_skbuff[entry], FREE_WRITE);
+ dev_free_skb(tp->tx_skbuff[entry]);
X tp->tx_skbuff[entry] = 0;
X }
X
@@ -972,8 +1050,7 @@
X }
X #endif
X
- if (tp->tx_full && dev->tbusy
- && dirty_tx > tp->cur_tx - NUM_TX_DESC) {
+ if (tp->tx_full && dirty_tx > tp->cur_tx - NUM_TX_DESC) {
X /* The ring is no longer full, clear tbusy. */
X tp->tx_full = 0;
X dev->tbusy = 0;
@@ -986,10 +1063,29 @@
X /* Check uncommon events with one test. */
X if (status & (PCIErr|PCSTimeout |RxUnderrun|RxOverflow|RxFIFOOver
X |TxErr|RxErr)) {
+ if (rtl8129_debug > 2)
+ printk(KERN_NOTICE"%s: Abnormal interrupt, status %8.8x.\n",


+ dev->name, status);
+

+ if (status == 0xffffffff)
+ break;
X /* Update the error count. */
X tp->stats.rx_missed_errors += inl(ioaddr + RxMissed);
X outl(0, ioaddr + RxMissed);
X
+ if ((status & RxUnderrun) &&
+ (rtl_cap_tbl[tp->chip_id] & HAS_LNK_CHNG)) {
+ /* Really link-change on new chips. */
+ int lpar = inw(ioaddr + NWayLPAR);
+ int duplex = (lpar&0x0100)||(lpar & 0x01C0) == 0x0040;
+ if (tp->full_duplex != duplex) {
+ tp->full_duplex = duplex;
+ outb(0xC0, ioaddr + Cfg9346);
+ outb(tp->full_duplex ? 0x60 : 0x20, ioaddr + Config1);
+ outb(0x00, ioaddr + Cfg9346);
+ }
+ status &= ~RxUnderrun;
+ }
X if (status & (RxUnderrun | RxOverflow | RxErr | RxFIFOOver))
X tp->stats.rx_errors++;
X
@@ -1000,7 +1096,14 @@
X tp->cur_rx = inw(ioaddr + RxBufAddr) % RX_BUF_LEN;
X outw(tp->cur_rx - 16, ioaddr + RxBufPtr);
X }
- /* Error sources cleared above. */
+ if (status & PCIErr) {
+ u32 pci_cmd_status;
+ pcibios_read_config_dword(tp->pci_bus, tp->pci_devfn,
+ PCI_COMMAND, &pci_cmd_status);
+
+ printk(KERN_ERR "%s: PCI Bus error %4.4x.\n",
+ dev->name, pci_cmd_status);
+ }
X }
X if (--boguscnt < 0) {
X printk(KERN_WARNING"%s: Too much work at interrupt, "
@@ -1016,18 +1119,20 @@
X printk(KERN_DEBUG"%s: exiting interrupt, intr_status=%#4.4x.\n",
X dev->name, inl(ioaddr + IntrStatus));


X
+#if defined(__i386__)
+ clear_bit(0, (void*)&dev->interrupt);
+#else
X dev->interrupt = 0;

- clear_bit(0, (void*)&tp->in_interrupt);
+#endif
X return;
X }
X
X /* The data sheet doesn't describe the Rx ring at all, so I'm guessing at the
X field alignments and semantics. */
-static int
-rtl8129_rx(struct device *dev)
+static int rtl8129_rx(struct device *dev)
X {
X struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;


- int ioaddr = dev->base_addr;
+ long ioaddr = dev->base_addr;

X unsigned char *rx_ring = tp->rx_ring;
X u16 cur_rx = tp->cur_rx;
X
@@ -1103,9 +1208,16 @@
X printk(".\n");
X memset(rx_ring, 0xcc, 16);
X }
- } else
+ } else {
+#if 1 /* USE_IP_COPYSUM */
+ eth_copy_and_sum(skb, &rx_ring[ring_offset + 4],
+ rx_size, 0);
+ skb_put(skb, rx_size);
+#else
X memcpy(skb_put(skb, rx_size), &rx_ring[ring_offset + 4],
X rx_size);
+#endif
+ }
X skb->protocol = eth_type_trans(skb, dev);
X netif_rx(skb);
X #if LINUX_VERSION_CODE > 0x20119
@@ -1114,8 +1226,7 @@
X tp->stats.rx_packets++;
X }
X
- cur_rx += rx_size + 4;
- cur_rx = (cur_rx + 3) & ~3;
+ cur_rx = (cur_rx + rx_size + 4 + 3) & ~3;
X outw(cur_rx - 16, ioaddr + RxBufPtr);
X }
X if (rtl8129_debug > 4)
@@ -1130,7 +1241,7 @@
X static int
X rtl8129_close(struct device *dev)


X {
- int ioaddr = dev->base_addr;
+ long ioaddr = dev->base_addr;

X struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
X int i;
X
@@ -1157,7 +1268,7 @@
X
X for (i = 0; i < NUM_TX_DESC; i++) {
X if (tp->tx_skbuff[i])
- dev_kfree_skb(tp->tx_skbuff[i], FREE_WRITE);
+ dev_free_skb(tp->tx_skbuff[i]);
X tp->tx_skbuff[i] = 0;
X }
X kfree(tp->rx_ring);
@@ -1173,11 +1284,33 @@


X return 0;
X }
X

+static int mii_ioctl(struct device *dev, struct ifreq *rq, int cmd)

+{
+ struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
+ u16 *data = (u16 *)&rq->ifr_data;
+
+ switch(cmd) {
+ case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */
+ data[0] = tp->phys[0] & 0x3f;
+ /* Fall Through */
+ case SIOCDEVPRIVATE+1: /* Read the specified MII register. */
+ data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f);
+ return 0;
+ case SIOCDEVPRIVATE+2: /* Write the specified MII register */
+ if (!suser())
+ return -EPERM;
+ mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]);
+ return 0;
+ default:


+ return -EOPNOTSUPP;
+ }
+}

+


X static struct enet_statistics *

X rtl8129_get_stats(struct device *dev)
X {
X struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;


- int ioaddr = dev->base_addr;
+ long ioaddr = dev->base_addr;
X

X if (dev->start) {
X tp->stats.rx_missed_errors += inl(ioaddr + RxMissed);
@@ -1188,88 +1321,69 @@
X }
X
X /* Set or clear the multicast filter for this adaptor.
- Note that we only use exclusion around actually queueing the
- new frame, not around filling tp->setup_frame. This is non-deterministic
- when re-entered but still correct. */
-
-/* The little-endian AUTODIN II ethernet CRC calculation.
- N.B. Do not use for bulk data, use a table-based routine instead.
- This is common code and should be moved to net/core/crc.c */
-static unsigned const ethernet_polynomial_le = 0xedb88320U;
-static inline unsigned ether_crc_le(int length, unsigned char *data)
+ This routine is not state sensitive and need not be SMP locked. */
+
+static unsigned const ethernet_polynomial = 0x04c11db7U;


+static inline u32 ether_crc(int length, unsigned char *data)

X {
- unsigned int crc = 0xffffffff; /* Initial value. */
- while(--length >= 0) {
+ int crc = -1;
+
+ while(--length >= 0) {
X unsigned char current_octet = *data++;
X int bit;
- for (bit = 8; --bit >= 0; current_octet >>= 1) {
- if ((crc ^ current_octet) & 1) {
- crc >>= 1;
- crc ^= ethernet_polynomial_le;
- } else
- crc >>= 1;
- }
- }
- return crc;
+ for (bit = 0; bit < 8; bit++, current_octet >>= 1)
+ crc = (crc << 1) ^
+ ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0);
+ }
+ return crc;
X }
X
+/* Bits in RxConfig. */
+enum rx_mode_bits {
+ AcceptErr=0x20, AcceptRunt=0x10, AcceptBroadcast=0x08,
+ AcceptMulticast=0x04, AcceptMyPhys=0x02, AcceptAllPhys=0x01,
+};
+


X static void set_rx_mode(struct device *dev)

X {


- int ioaddr = dev->base_addr;

- struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
- unsigned char mc_filter[8]; /* Multicast hash filter */
- int i;


+ long ioaddr = dev->base_addr;

+ u32 mc_filter[2]; /* Multicast hash filter */
+ int i, rx_mode;
X
- if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
+ if (rtl8129_debug > 3)
+ printk(KERN_DEBUG"%s: set_rx_mode(%4.4x) done -- Rx config %8.8x.\n",
+ dev->name, dev->flags, inl(ioaddr + RxConfig));
+
+ /* Note: do not reorder, GCC is clever about common statements. */
+ if (dev->flags & IFF_PROMISC) {
X /* Unconditionally log net taps. */
X printk(KERN_NOTICE"%s: Promiscuous mode enabled.\n", dev->name);
- memset(mc_filter, 0xff, sizeof(mc_filter));
- outb(0x0F, ioaddr + RxConfig);
- } else if ((dev->mc_count > 1000) || (dev->flags & IFF_ALLMULTI)) {
+ rx_mode = AcceptBroadcast|AcceptMulticast|AcceptMyPhys|AcceptAllPhys;
+ mc_filter[1] = mc_filter[0] = 0xffffffff;
+ } else if ((dev->mc_count > multicast_filter_limit)
+ || (dev->flags & IFF_ALLMULTI)) {
X /* Too many to filter perfectly -- accept all multicasts. */
- memset(mc_filter, 0xff, sizeof(mc_filter));
- outb(0x0E, ioaddr + RxConfig);
- } else if (dev->mc_count == 0) {
- outb(0x0A, ioaddr + RxConfig);
- return;
+ rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
+ mc_filter[1] = mc_filter[0] = 0xffffffff;
X } else {


X struct dev_mc_list *mclist;
-

- memset(mc_filter, 0, sizeof(mc_filter));
+ rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
+ mc_filter[1] = mc_filter[0] = 0;
X for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
X i++, mclist = mclist->next)
- set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x3f,
- mc_filter);
+ set_bit(ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26, mc_filter);
X }
- /* ToDo: perhaps we need to stop the Tx and Rx process here? */
- if (memcmp(mc_filter, tp->mc_filter, sizeof(mc_filter))) {
- for (i = 0; i < 2; i++)
- outl(((u32 *)mc_filter)[i], ioaddr + MAR0 + i*4);
- memcpy(tp->mc_filter, mc_filter, sizeof(mc_filter));
- }
- if (rtl8129_debug > 3)
- printk(KERN_DEBUG"%s: set_rx_mode(%4.4x) done -- Rx config %8.8x.\n",
- dev->name, dev->flags, inl(ioaddr + RxConfig));
+ /* We can safely update without stopping the chip. */
+ outb(rx_mode, ioaddr + RxConfig);
+ outl(mc_filter[0], ioaddr + MAR0 + 0);
+ outl(mc_filter[1], ioaddr + MAR0 + 4);
X return;


X }
X
X #ifdef MODULE
-

-/* An additional parameter that may be passed in... */
-static int debug = -1;
-
-int
-init_module(void)
+int init_module(void)
X {

- int cards_found;
-


- if (debug >= 0)

- rtl8129_debug = debug;
-
- root_rtl8129_dev = NULL;
- cards_found = rtl8139_probe(0);
-
- return cards_found ? 0 : -ENODEV;
+ return rtl8139_probe(0);
X }
X
X void
@@ -1279,9 +1393,13 @@


X
X /* No need to check MOD_IN_USE, as sys_delete_module() checks. */

X while (root_rtl8129_dev) {
- next_dev = ((struct rtl8129_private *)root_rtl8129_dev->priv)->next_module;
+ struct rtl8129_private *tp =
+ (struct rtl8129_private *)root_rtl8129_dev->priv;
+ next_dev = tp->next_module;
X unregister_netdev(root_rtl8129_dev);
- release_region(root_rtl8129_dev->base_addr, RTL8129_TOTAL_SIZE);
+ release_region(root_rtl8129_dev->base_addr,
+ pci_tbl[tp->chip_id].io_size);
+ kfree(tp);
X kfree(root_rtl8129_dev);
X root_rtl8129_dev = next_dev;
X }
diff -u --recursive --new-file v2.0.36/linux/drivers/net/sdla.c linux/drivers/net/sdla.c
--- v2.0.36/linux/drivers/net/sdla.c Mon Jul 13 13:46:30 1998
+++ linux/drivers/net/sdla.c Sun Jun 13 10:21:01 1999
@@ -452,7 +452,7 @@
X save_flags(pflags);
X cli();
X SDLA_WINDOW(dev, window);
- waiting = ((volatile)(cmd_buf->opp_flag));
+ waiting = ((volatile int)(cmd_buf->opp_flag));
X restore_flags(pflags);
X }
X }
@@ -566,11 +566,12 @@
X flp->dlci[i] = -*(short *)(master->dev_addr);
X master->mtu = slave->mtu;
X
- if (slave->start)
+ if (slave->start) {
X if (flp->config.station == FRAD_STATION_CPE)
X sdla_reconfig(slave);
X else
X sdla_cmd(slave, SDLA_ADD_DLCI, 0, 0, master->dev_addr, sizeof(short), NULL, NULL);
+ }
X
X return(0);
X }
@@ -594,11 +595,12 @@
X
X MOD_DEC_USE_COUNT;
X
- if (slave->start)
+ if (slave->start) {
X if (flp->config.station == FRAD_STATION_CPE)
X sdla_reconfig(slave);
X else
X sdla_cmd(slave, SDLA_DELETE_DLCI, 0, 0, master->dev_addr, sizeof(short), NULL, NULL);
+ }
X
X return(0);
X }
@@ -623,13 +625,14 @@
X
X ret = SDLA_RET_OK;
X len = sizeof(struct dlci_conf);
- if (slave->start)
+ if (slave->start) {
X if (get)
X ret = sdla_cmd(slave, SDLA_READ_DLCI_CONFIGURATION, abs(flp->dlci[i]), 0,
X NULL, 0, &dlp->config, &len);
X else
X ret = sdla_cmd(slave, SDLA_SET_DLCI_CONFIGURATION, abs(flp->dlci[i]), 0,
X &dlp->config, sizeof(struct dlci_conf) - 4 * sizeof(short), NULL, NULL);
+ }
X
X return(ret == SDLA_RET_OK ? 0 : -EIO);
X }
diff -u --recursive --new-file v2.0.36/linux/drivers/net/skeleton.c linux/drivers/net/skeleton.c
--- v2.0.36/linux/drivers/net/skeleton.c Thu Feb 29 21:50:45 1996
+++ linux/drivers/net/skeleton.c Sun Jun 13 10:21:01 1999
@@ -362,15 +362,6 @@


X dev->trans_start = jiffies;

X }
X /*
- * If some higher layer thinks we've missed an tx-done interrupt
- * we are passed NULL. Caution: dev_tint() handles the cli()/sti()
- * itself.
- */


- if (skb == NULL) {

- dev_tint(dev);
- return 0;
- }
- /*
X * Block a timer-based transmit from overlapping. This could better be
X * done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
X */
diff -u --recursive --new-file v2.0.36/linux/drivers/net/tulip.c linux/drivers/net/tulip.c
--- v2.0.36/linux/drivers/net/tulip.c Sun Nov 15 21:51:46 1998
+++ linux/drivers/net/tulip.c Sun Jun 13 10:21:02 1999
@@ -5,9 +5,9 @@


X This software may be used and distributed according to the terms
X of the GNU Public License, incorporated herein by reference.

X
- This driver is for the Digital "Tulip" ethernet adapter interface.
+ This driver is for the Digital "Tulip" Ethernet adapter interface.
X It should work with most DEC 21*4*-based chips/ethercards, as well as
- PNIC and MXIC chips.
+ with work-alike chips from Lite-On (PNIC) and Macronix (MXIC) and ASIX.


X
X The author may be reached as bec...@CESDIS.gsfc.nasa.gov, or C/O

X Center of Excellence in Space Data and Information Sciences

@@ -18,7 +18,7 @@
X */
X
X #define SMP_CHECK
-static const char version[] = "tulip.c:v0.89H 5/23/98 bec...@cesdis.gsfc.nasa.gov\n";
+static const char version[] = "tulip.c:v0.90 10/20/98 bec...@cesdis.gsfc.nasa.gov\n";


X
X /* A few user-configurable values. */
X

@@ -63,14 +63,20 @@


X /* Operational parameters that usually are not changed. */
X /* Time in jiffies before concluding the transmitter is hung. */

X #define TX_TIMEOUT (4*HZ)
+#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/
+/* This is a mysterious value that can be written to CSR11 in the 21040 (only)
+ to support a pre-NWay full-duplex signaling mechanism using short frames.
+ No one knows what it should be, but if left at its default value some
+ 10base2(!) packets trigger a full-duplex-request interrupt. */
+#define FULL_DUPLEX_MAGIC 0x6969


X
X #include <linux/config.h>
+#include <linux/version.h>

X #ifdef MODULE
X #ifdef MODVERSIONS
X #include <linux/modversions.h>

X #endif
X #include <linux/module.h>
-#include <linux/version.h>
X #else
X #define MOD_INC_USE_COUNT
X #define MOD_DEC_USE_COUNT

@@ -80,87 +86,65 @@


X #include <linux/sched.h>
X #include <linux/string.h>
X #include <linux/timer.h>
-#include <linux/ptrace.h>
X #include <linux/errno.h>
X #include <linux/ioport.h>
X #include <linux/malloc.h>
X #include <linux/interrupt.h>
X #include <linux/pci.h>
-#include <linux/bios32.h>

-#include <asm/processor.h> /* Processor type for cache alignment. */
-#include <asm/bitops.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-


X #include <linux/netdevice.h>
X #include <linux/etherdevice.h>

X #include <linux/skbuff.h>
+#include <asm/processor.h> /* Processor type for cache alignment. */
+#include <asm/bitops.h>
+#include <asm/io.h>
X
-/* Kernel compatibility defines, common to David Hind's PCMCIA package.


+/* Kernel compatibility defines, some common to David Hind's PCMCIA package.

X This is only in the support-all-kernels source code. */
-#include <linux/version.h> /* Evil, but neccessary */
-
-#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x10300


-#define RUN_AT(x) (x) /* What to put in timer->expires. */
-#define DEV_ALLOC_SKB(len) alloc_skb(len, GFP_ATOMIC)

-#define virt_to_bus(addr) ((unsigned long)addr)
-#define bus_to_virt(addr) ((void*)addr)

X

-#else /* 1.3.0 and later */
-#define RUN_AT(x) (jiffies + (x))

-#define DEV_ALLOC_SKB(len) dev_alloc_skb(len + 2)


+#if defined(MODULE) && LINUX_VERSION_CODE > 0x20115

+MODULE_AUTHOR("Donald Becker <bec...@cesdis.gsfc.nasa.gov>");
+MODULE_DESCRIPTION("Digital 21*4* Tulip ethernet driver");
+MODULE_PARM(debug, "i");
+MODULE_PARM(max_interrupt_work, "i");
+MODULE_PARM(reverse_probe, "i");
+MODULE_PARM(rx_copybreak, "i");


+MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
+MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");

X #endif
X
-#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x10338
-#ifdef MODULE
-#if !defined(CONFIG_MODVERSIONS) && !defined(__NO_VERSION__)
-char kernel_version[] = UTS_RELEASE;
-#endif
-#else
-#undef MOD_INC_USE_COUNT
-#define MOD_INC_USE_COUNT
-#undef MOD_DEC_USE_COUNT
-#define MOD_DEC_USE_COUNT
-#endif
-#endif /* 1.3.38 */
+#define RUN_AT(x) (jiffies + (x))
X

-#if (LINUX_VERSION_CODE >= 0x10344)
-#define NEW_MULTICAST

-#include <linux/delay.h>
-#endif
X #if (LINUX_VERSION_CODE >= 0x20100)
X char kernel_version[] = UTS_RELEASE;
X #endif
-#ifdef SA_SHIRQ


-#define IRQ(irq, dev_id, pt_regs) (irq, dev_id, pt_regs)
-#else

-#define IRQ(irq, dev_id, pt_regs) (irq, pt_regs)
-#endif

X
-#if (LINUX_VERSION_CODE < 0x20123)
+#if LINUX_VERSION_CODE < 0x20123

X #define hard_smp_processor_id() smp_processor_id()


X #define test_and_set_bit(val, addr) set_bit(val, addr)
X #endif

-
-/* This my implementation of shared IRQs, now only used for 1.2.13. */
-#ifdef HAVE_SHARED_IRQ
-#define USE_SHARED_IRQ
-#include <linux/shared_irq.h>


+#if LINUX_VERSION_CODE <= 0x20139
+#define net_device_stats enet_statistics
+#else
+#define NETSTATS_VER2

X #endif
-
-/* The total size is unusually large: The 21040 aligns each of its 16
- longword-wide registers on a quadword boundary. */
-#define TULIP_TOTAL_SIZE 0x80
-
-#ifdef HAVE_DEVLIST
-struct netdev_entry tulip_drv =
-{"Tulip", tulip_pci_probe, TULIP_TOTAL_SIZE, NULL};


+#if LINUX_VERSION_CODE < 0x20155 || defined(CARDBUS)
+/* Grrrr, the PCI code changed, but did not consider CardBus... */
+#include <linux/bios32.h>
+#define PCI_SUPPORT_VER1
+#else
+#define PCI_SUPPORT_VER2
+#endif
+#if LINUX_VERSION_CODE < 0x20159
+#define dev_free_skb(skb) dev_kfree_skb(skb, FREE_WRITE);
+#else
+#define dev_free_skb(skb) dev_kfree_skb(skb);

X #endif
X
+#define tulip_debug debug
X #ifdef TULIP_DEBUG
-int tulip_debug = TULIP_DEBUG;
+static int tulip_debug = TULIP_DEBUG;
X #else
-int tulip_debug = 1;
+static int tulip_debug = 1;


X #endif
X
X /*

@@ -170,17 +154,27 @@
X
X This device driver is designed for the DECchip "Tulip", Digital's
X single-chip ethernet controllers for PCI. Supported members of the family
-are the 21040, 21041, 21140, 21140A, 21142, and 21143. These chips are used on
-many PCI boards including the SMC EtherPower series.
-
+are the 21040, 21041, 21140, 21140A, 21142, and 21143. Similar work-alike
+chips from Lite-On, Macronics, ASIX, Compex and other listed below are also
+supported.
+
+These chips are used on at least 140 unique PCI board designs. The great
+number of chips and board designs supported is the reason for the
+driver size and complexity. Almost of the increasing complexity is in the
+board configuration and media selection code. There is very little
+increasing in the operational critical path length.


X
X II. Board-specific settings
X
X PCI bus devices are configured by the system at boot time, so no jumpers

X need to be set on the board. The system BIOS preferably should assign the
X PCI INTA signal to an otherwise unused system IRQ line.
-Note: Kernel versions earlier than 1.3.73 do not support shared PCI
-interrupt lines.
+
+Some boards have EEPROMs tables with default media entry. The factory default
+is usually "autoselect". This should only be overridden when using
+transceiver connections without link beat e.g. 10base2 or AUI, or (rarely!)
+for forcing full-duplex when used with old link partners that do not do
+autonegotiation.

X
X III. Driver operation
X

@@ -228,7 +222,9 @@
X
X IV. Notes
X
-Thanks to Duke Kamstra of SMC for providing an EtherPower board.
+Thanks to Duke Kamstra of SMC for long ago providing an EtherPower board.
+Greg LaPolla at Linksys provided PNIC and other Linksys boards.
+Znyx provided a four-port card for testing.
X
X IVb. References
X
@@ -238,88 +234,105 @@
X
X IVc. Errata
X
-The DEC databook doesn't document which Rx filter settings accept broadcast
-packets. Nor does it document how to configure the part to configure the
-serial subsystem for normal (vs. loopback) operation or how to have it
-autoswitch between internal 10baseT, SIA and AUI transceivers.
-
+The old DEC databooks were light on details.
X The 21040 databook claims that CSR13, CSR14, and CSR15 should each be the last
-register of the set CSR12-15 written. Hmmm, now how is that possible? */
+register of the set CSR12-15 written. Hmmm, now how is that possible?
X
+The DEC SROM format is very badly designed not precisely defined, leading to
+part of the media selection junkheap below. Some boards do not have EEPROM
+media tables and need to be patched up. Worse, other boards use the DEC
+design kit media table when it isn't correct for their board.
X
-/* A few values that may be tweaked. */
-#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/
+We cannot use MII interrupts because there is no defined GPIO pin to attach
+them.
X
-/* This is a mysterious value that can be written to CSR11 in the 21040 (only)
- to support a pre-NWay full-duplex signaling mechanism using short frames.
- No one knows what it should be, but if left at its default value some
- 10base2(!) packets trigger a full-duplex-request interrupt. */
-#define FULL_DUPLEX_MAGIC 0x6969
+*/
X
X #ifndef PCI_VENDOR_ID_DEC /* Now defined in linux/pci.h */
X #define PCI_VENDOR_ID_DEC 0x1011
-#define PCI_DEVICE_ID_TULIP 0x0002 /* 21040. */
-#define PCI_DEVICE_ID_TULIP_FAST 0x0009 /* 21140. */
-#endif
-
-#ifndef PCI_DEVICE_ID_DEC_TULIP_PLUS
-#define PCI_DEVICE_ID_DEC_TULIP_PLUS 0x0014 /* 21041. */
-#endif
-#ifndef PCI_DEVICE_ID_DEC_TULIP_21142
-#define PCI_DEVICE_ID_DEC_TULIP_21142 0x0019
X #endif
X
-#ifndef PCI_VENDOR_ID_LITEON
-#define PCI_VENDOR_ID_LITEON 0x11AD
-#endif
+static struct device *
+tulip_probe1(int pci_bus, int pci_devfn, struct device *dev, long ioaddr,
+ int irq, int chip_idx, int board_idx);


+
+/* This table drives the PCI probe routines. It's mostly boilerplate in all
+ of the drivers, and will likely be provided by some future kernel.
+ Note the matching code -- the first table entry matchs all 56** cards but
+ second only the 1234 card.
+*/
+enum pci_flags_bit {
+ PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
+ PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3,
+};

+#define PCI_ADDR0_IO (PCI_USES_IO|PCI_ADDR0)
X
-#ifndef PCI_VENDOR_ID_MXIC
-#define PCI_VENDOR_ID_MXIC 0x10d9
-#define PCI_DEVICE_ID_MX98713 0x0512
-#define PCI_DEVICE_ID_MX98715 0x0531
-#define PCI_DEVICE_ID_MX98725 0x0531
-#endif


+struct pci_id_info {
+ const char *name;
+ u16 vendor_id, device_id, device_id_mask, flags;

+ int io_size, min_latency;


+ struct device *(*probe1)(int pci_bus, int pci_devfn, struct device *dev,
+ long ioaddr, int irq, int chip_idx, int fnd_cnt);
+};

+#ifndef CARDBUS


+static struct pci_id_info pci_tbl[] = {

+ { "Digital DC21040 Tulip",
+ 0x1011, 0x0002, 0xffff, PCI_ADDR0_IO, 128, 32, tulip_probe1 },
+ { "Digital DC21041 Tulip",
+ 0x1011, 0x0014, 0xffff, PCI_ADDR0_IO, 128, 32, tulip_probe1 },
+ { "Digital DS21140 Tulip",
+ 0x1011, 0x0009, 0xffff, PCI_ADDR0_IO, 128, 32, tulip_probe1 },
+ { "Digital DS21143 Tulip",
+ 0x1011, 0x0019, 0xffff, PCI_ADDR0_IO, 128, 32, tulip_probe1 },
+ { "Lite-On 82c168 PNIC",
+ 0x11AD, 0x0002, 0xffff, PCI_ADDR0_IO, 256, 32, tulip_probe1 },
+ { "Macronix 98713 PMAC",
+ 0x10d9, 0x0512, 0xffff, PCI_ADDR0_IO, 256, 32, tulip_probe1 },
+ { "Macronix 98715 PMAC",
+ 0x10d9, 0x0531, 0xffff, PCI_ADDR0_IO, 256, 32, tulip_probe1 },
+ { "Macronix 98725 PMAC",
+ 0x10d9, 0x0531, 0xffff, PCI_ADDR0_IO, 256, 32, tulip_probe1 },
+ { "ASIX AX88140",
+ 0x125B, 0x1400, 0xffff, PCI_ADDR0_IO, 128, 32, tulip_probe1 },
+ {0},
+};
+#endif CARD_BUS
X
-/* The rest of these values should never change. */
+/* This table use during operation for capabilities and media timer. */
X
X static void tulip_timer(unsigned long data);
X static void t21142_timer(unsigned long data);
X static void mxic_timer(unsigned long data);
X static void pnic_timer(unsigned long data);
X
-/* A table describing the chip types. */
-enum tbl_flag { HAS_MII=1, HAS_MEDIA_TABLE = 2, CSR12_IN_SROM = 4,};
+enum tbl_flag {
+ HAS_MII=1, HAS_MEDIA_TABLE=2, CSR12_IN_SROM=4, ALWAYS_CHECK_MII=8,
+ HAS_ACPI=0x10,
+};
X static struct tulip_chip_table {
- int vendor_id, device_id;
X char *chip_name;
X int io_size;
X int valid_intrs; /* CSR7 interrupt enable settings */
X int flags;
X void (*media_timer)(unsigned long data);
X } tulip_tbl[] = {
- { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP,
- "Digital DC21040 Tulip", 128, 0x0001ebef, 0, tulip_timer },
- { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_PLUS,
- "Digital DC21041 Tulip", 128, 0x0001ebef, HAS_MEDIA_TABLE, tulip_timer },
- { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_FAST,
- "Digital DS21140 Tulip", 128, 0x0001ebef,
- HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM,
- tulip_timer },
- { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_21142,
- "Digital DS21142/3 Tulip", 256, 0x0801fbff,
- HAS_MII | HAS_MEDIA_TABLE, t21142_timer },
- { PCI_VENDOR_ID_LITEON, 0x0002,
- "Lite-On 82c168 PNIC", 256, 0x0001ebef, HAS_MII, pnic_timer },
- { PCI_VENDOR_ID_MXIC, PCI_DEVICE_ID_MX98713,
- "Macronix 98713 PMAC", 128, 0x0001ebef,
- HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, tulip_timer /* Tulip-like! */ },
- { PCI_VENDOR_ID_MXIC, PCI_DEVICE_ID_MX98715,
- "Macronix 98715 PMAC", 256, 0x0001ebef, HAS_MEDIA_TABLE, mxic_timer },
- { PCI_VENDOR_ID_MXIC, PCI_DEVICE_ID_MX98725,
- "Macronix 98725 PMAC", 256, 0x0001ebef, HAS_MEDIA_TABLE, mxic_timer },
- { 0x125B, 0x1400, "ASIX AX88140", 128, 0x0001fbff,
+ { "Digital DC21040 Tulip", 128, 0x0001ebef, 0, tulip_timer },
+ { "Digital DC21041 Tulip", 128, 0x0001ebef, HAS_MEDIA_TABLE, tulip_timer },
+ { "Digital DS21140 Tulip", 128, 0x0001ebef,
X HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, tulip_timer },
- {0, 0, 0, 0},
+ { "Digital DS21143 Tulip", 128, 0x0801fbff,
+ HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_ACPI, t21142_timer },
+ { "Lite-On 82c168 PNIC", 256, 0x0001ebef,
+ HAS_MII, pnic_timer },
+ { "Macronix 98713 PMAC", 128, 0x0001ebef,
+ HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, mxic_timer },
+ { "Macronix 98715 PMAC", 256, 0x0001ebef,
+ HAS_MEDIA_TABLE, mxic_timer },
+ { "Macronix 98725 PMAC", 256, 0x0001ebef,
+ HAS_MEDIA_TABLE, mxic_timer },
+ { "ASIX AX88140", 128, 0x0001fbff,
+ HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, tulip_timer },
+ {0},
X };
X /* This matches the table above. */
X enum chips { DC21040=0, DC21041=1, DC21140=2, DC21142=3, DC21143=3,
@@ -367,6 +380,13 @@
X u32 buffer1, buffer2; /* We use only buffer 1. */
X };
X
+/* Ring-wrap flag in length field, use for last ring entry.
+ 0x01000000 means chain on buffer2 address,
+ 0x02000000 means use the ring start address in CSR2/3.
+ Note: Some work-alike chips do not function correctly in chained mode.
+*/
+#define DESC_RING_WRAP 0x02000000
+
X struct medialeaf {
X u8 type;
X u8 media;
@@ -401,11 +421,7 @@
X u32 setup_frame[48]; /* Pseudo-Tx frame to init address table. */
X int chip_id;
X int revision;
-#if LINUX_VERSION_CODE > 0x20139
X struct net_device_stats stats;
-#else
- struct enet_statistics stats;
-#endif


X struct timer_list timer; /* Media selection timer. */

X int interrupt; /* In-interrupt flag. */
X #ifdef SMP_CHECK
@@ -428,13 +444,11 @@
X signed char phys[4], mii_cnt; /* MII device addresses. */
X struct mediatable *mtable;
X int cur_index; /* Current media index. */
- unsigned char pci_bus, pci_dev_fn;
+ int saved_if_port;


+ unsigned char pci_bus, pci_devfn;

X int pad0, pad1; /* Used for 8-byte alignment */
X };
X
-static struct device *tulip_probe1(int pci_bus, int pci_devfn,
- struct device *dev,
- int chip_id, int options);
X static void parse_eeprom(struct device *dev);
X static int read_eeprom(long ioaddr, int location);
X static int mdio_read(struct device *dev, int phy_id, int location);
@@ -446,51 +460,34 @@
X static void tulip_init_ring(struct device *dev);
X static int tulip_start_xmit(struct sk_buff *skb, struct device *dev);
X static int tulip_rx(struct device *dev);
-static void tulip_interrupt IRQ(int irq, void *dev_instance, struct pt_regs *regs);
+static void tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
X static int tulip_close(struct device *dev);
-static struct enet_statistics *tulip_get_stats(struct device *dev);
+static struct net_device_stats *tulip_get_stats(struct device *dev);
X #ifdef HAVE_PRIVATE_IOCTL
X static int private_ioctl(struct device *dev, struct ifreq *rq, int cmd);
X #endif
-#ifdef NEW_MULTICAST


X static void set_rx_mode(struct device *dev);

-#else
-static void set_rx_mode(struct device *dev, int num_addrs, void *addrs);
-#endif
X
X
X
-/* A list of all installed Tulip devices, for removing the driver module. */
+/* A list of all installed Tulip devices. */
X static struct device *root_tulip_dev = NULL;
X
-/* This 21040 probe no longer uses a large fixed contiguous Rx buffer region,
- but now receives directly into full-sized skbuffs that are allocated
- at open() time.
- This allows the probe routine to use the old driver initialization
- interface. */
-
+#ifndef CARDBUS
X int tulip_probe(struct device *dev)


X {
X int cards_found = 0;
- static int pci_index = 0; /* Static, for multiple probe calls. */
+ int pci_index = 0;

X unsigned char pci_bus, pci_device_fn;


X
- /* Ideally we would detect all network cards in slot order. That would
- be best done a central PCI probe dispatch, which wouldn't work
- well with the current structure. So instead we detect just the

- Tulip cards in slot order. */
-
-#if LINUX_VERSION_CODE >= 0x20155
- if (! pci_present())
- return -ENODEV;
-#else
- if (! pcibios_present())


+ if ( ! pcibios_present())

X return -ENODEV;
-#endif
+
X for (;pci_index < 0xff; pci_index++) {
X u16 vendor, device, pci_command, new_command;
- u32 pci_ioaddr;
- int chip_idx = 0;
+ int chip_idx;
+ int irq;
+ long ioaddr;
X
X if (pcibios_find_class
X (PCI_CLASS_NETWORK_ETHERNET << 8,
@@ -505,50 +502,55 @@


X pcibios_read_config_word(pci_bus, pci_device_fn,
X PCI_DEVICE_ID, &device);

X
- for (chip_idx = 0; tulip_tbl[chip_idx].chip_name; chip_idx++)
- if (vendor == tulip_tbl[chip_idx].vendor_id &&
- device == tulip_tbl[chip_idx].device_id)


+ for (chip_idx = 0; pci_tbl[chip_idx].vendor_id; chip_idx++)
+ if (vendor == pci_tbl[chip_idx].vendor_id
+ && (device & pci_tbl[chip_idx].device_id_mask) ==
+ pci_tbl[chip_idx].device_id)
X break;

- if (tulip_tbl[chip_idx].chip_name == 0) {
- if (vendor == PCI_VENDOR_ID_DEC ||
- vendor == PCI_VENDOR_ID_LITEON)
- printk(KERN_INFO "Unknown Tulip-style PCI ethernet chip type"
- " %4.4x %4.4x"" detected: not configured.\n",
- vendor, device);


+ if (pci_tbl[chip_idx].vendor_id == 0)

X continue;
- }
-#if LINUX_VERSION_CODE >= 0x20155
- pci_ioaddr = pci_find_slot(pci_bus, pci_device_fn)->base_address[0];
-#else
- pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_0,
- &pci_ioaddr);
+


+ {
+#if defined(PCI_SUPPORT_VER2)
+ struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn);
+ ioaddr = pdev->base_address[0] & ~3;
+ irq = pdev->irq;
+#else
+ u32 pci_ioaddr;
+ u8 pci_irq_line;

+ pcibios_read_config_dword(pci_bus, pci_device_fn,
+ PCI_BASE_ADDRESS_0, &pci_ioaddr);


+ pcibios_read_config_byte(pci_bus, pci_device_fn,
+ PCI_INTERRUPT_LINE, &pci_irq_line);

+ ioaddr = pci_ioaddr & ~3;
+ irq = pci_irq_line;

X #endif


- /* Remove I/O space marker in bit 0. */
- pci_ioaddr &= ~3;

+ }
X
- if (tulip_debug > 2)
- printk(KERN_DEBUG "Found %s at I/O %#x.\n",
- tulip_tbl[chip_idx].chip_name, pci_ioaddr);
+ if (debug > 2)
+ printk(KERN_INFO "Found %s at PCI I/O address %#lx.\n",
+ pci_tbl[chip_idx].name, ioaddr);
X
- if (check_region(pci_ioaddr, tulip_tbl[chip_idx].io_size))


+ if (check_region(ioaddr, pci_tbl[chip_idx].io_size))
X continue;
X

X pcibios_read_config_word(pci_bus, pci_device_fn,
X PCI_COMMAND, &pci_command);
X new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO;
X if (pci_command != new_command) {


- printk(KERN_INFO " The PCI BIOS has not enabled this"

- " device! Updating PCI command %4.4x->%4.4x.\n",
- pci_command, new_command);


+ printk(KERN_INFO " The PCI BIOS has not enabled the"
+ " device at %d/%d! Updating PCI command %4.4x->%4.4x.\n",
+ pci_bus, pci_device_fn, pci_command, new_command);

X pcibios_write_config_word(pci_bus, pci_device_fn,


X PCI_COMMAND, new_command);
X }
X

- dev = tulip_probe1(pci_bus, pci_device_fn, dev, chip_idx, cards_found);


+ dev = pci_tbl[chip_idx].probe1(pci_bus, pci_device_fn, dev, ioaddr,
+ irq, chip_idx, cards_found);
X

X /* Get and check the bus-master and latency values. */
X if (dev) {
- unsigned char pci_latency;
+ u8 pci_latency;


X pcibios_read_config_byte(pci_bus, pci_device_fn,
X PCI_LATENCY_TIMER, &pci_latency);

X if (pci_latency < 10) {
@@ -557,30 +559,22 @@
X pci_latency);
X pcibios_write_config_byte(pci_bus, pci_device_fn,
X PCI_LATENCY_TIMER, 64);
- } else if (tulip_debug > 1)
- printk(KERN_INFO " PCI latency timer (CFLT) is %#x, "
- " PCI command is %4.4x.\n",
- pci_latency, new_command);
- /* Bring the 21143 out power-down mode. */
- if (device == PCI_DEVICE_ID_DEC_TULIP_21142)
- pcibios_write_config_dword(pci_bus, pci_device_fn,
- 0x40, 0x40000000);


- dev = 0;
- cards_found++;
+ }

X }
+ dev = 0;
+ cards_found++;
X }
X

X return cards_found ? 0 : -ENODEV;

X }
+#endif /* not CARDBUS */
X
-static struct device *tulip_probe1(int pci_bus, int pci_device_fn,
- struct device *dev,
- int chip_id, int board_idx)
+static struct device *tulip_probe1(int pci_bus, int pci_devfn,


+ struct device *dev, long ioaddr, int irq,

+ int chip_idx, int board_idx)


X {
X static int did_version = 0; /* Already printed version info. */

X struct tulip_private *tp;
- long ioaddr;
- int irq;
X /* See note below on the multiport cards. */
X static unsigned char last_phys_addr[6] = {0x00, 'L', 'i', 'n', 'u', 'x'};
X static int last_irq = 0;
@@ -593,36 +587,23 @@


X
X dev = init_etherdev(dev, 0);
X

-#if LINUX_VERSION_CODE >= 0x20155
- irq = pci_find_slot(pci_bus, pci_device_fn)->irq;
- ioaddr = pci_find_slot(pci_bus, pci_device_fn)->base_address[0];
-#else
- {
- u8 pci_irq_line;
- u32 pci_ioaddr;
- pcibios_read_config_byte(pci_bus, pci_device_fn,
- PCI_INTERRUPT_LINE, &pci_irq_line);
- pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_0,
- &pci_ioaddr);
- irq = pci_irq_line;
- ioaddr = pci_ioaddr;
- }
-#endif


- /* Remove I/O space marker in bit 0. */

- ioaddr &= ~3;
+ /* Bring the 21143 out of sleep mode.
+ Caution: Snooze mode does not work with some boards! */
+ if (tulip_tbl[chip_idx].flags & HAS_ACPI)
+ pcibios_write_config_dword(pci_bus, pci_devfn, 0x40, 0x00000000);
X
X printk(KERN_INFO "%s: %s at %#3lx,",
- dev->name, tulip_tbl[chip_id].chip_name, ioaddr);
+ dev->name, tulip_tbl[chip_idx].chip_name, ioaddr);
X
X /* Stop the chip's Tx and Rx processes. */
X outl(inl(ioaddr + CSR6) & ~0x2002, ioaddr + CSR6);
X /* Clear the missed-packet counter. */
X (volatile int)inl(ioaddr + CSR8);
X
- if (chip_id == DC21041) {
+ if (chip_idx == DC21041) {
X if (inl(ioaddr + CSR9) & 0x8000) {
X printk(" 21040 compatible mode,");
- chip_id = DC21040;
+ chip_idx = DC21040;
X } else {
X printk(" 21041 mode,");
X }
@@ -633,7 +614,7 @@
X EEPROM.
X */
X sum = 0;
- if (chip_id == DC21040) {
+ if (chip_idx == DC21040) {
X outl(0, ioaddr + CSR9); /* Reset the pointer with a dummy write. */
X for (i = 0; i < 6; i++) {
X int value, boguscnt = 100000;
@@ -643,7 +624,7 @@
X dev->dev_addr[i] = value;
X sum += value & 0xff;
X }
- } else if (chip_id == LC82C168) {
+ } else if (chip_idx == LC82C168) {
X for (i = 0; i < 3; i++) {
X int value, boguscnt = 100000;
X outl(0x600 | i, ioaddr + 0x98);
@@ -705,8 +686,8 @@
X last_irq = irq;
X
X /* We do a request_region() only to register /proc/ioports info. */
- /* Note that proper size is tulip_tbl[chip_id].chip_name, but... */
- request_region(ioaddr, TULIP_TOTAL_SIZE, dev->name);
+ /* Note that proper size is tulip_tbl[chip_idx].chip_name, but... */
+ request_region(ioaddr, tulip_tbl[chip_idx].io_size, dev->name);


X
X dev->base_addr = ioaddr;
X dev->irq = irq;

@@ -720,8 +701,8 @@
X root_tulip_dev = dev;
X
X tp->pci_bus = pci_bus;
- tp->pci_dev_fn = pci_device_fn;


- tp->chip_id = chip_id;

+ tp->pci_devfn = pci_devfn;


+ tp->chip_id = chip_idx;

X
X #ifdef TULIP_FULL_DUPLEX
X tp->full_duplex = 1;
@@ -753,7 +734,7 @@
X tp->full_duplex_lock = 1;
X
X /* This is logically part of probe1(), but too complex to write inline. */
- if (tulip_tbl[chip_id].flags & HAS_MEDIA_TABLE)
+ if (tulip_tbl[chip_idx].flags & HAS_MEDIA_TABLE)
X parse_eeprom(dev);
X
X if (media_cap[tp->default_port] & MediaIsMII) {
@@ -762,9 +743,13 @@
X } else
X tp->to_advertise = 0x03e1;
X
- if ((tp->mtable && tp->mtable->has_mii) ||
- ( ! tp->mtable && (tulip_tbl[tp->chip_id].flags & HAS_MII))) {
+ if ((tulip_tbl[chip_idx].flags & ALWAYS_CHECK_MII) ||
+ (tp->mtable && tp->mtable->has_mii) ||
+ ( ! tp->mtable && (tulip_tbl[chip_idx].flags & HAS_MII))) {
X int phy, phy_idx;
+ /* Clear undefined bits that confuse the MII interface. */
+ if (tp->chip_id == DC21142)
+ outl(inl(ioaddr+CSR15) & ~(0x800037c0), ioaddr+CSR15);


X /* Find the connected MII xcvrs.
X Doing this in open() would allow detecting external xcvrs later,

X but takes much time. */
@@ -773,16 +758,18 @@
X int mii_status = mdio_read(dev, phy, 1);


X if (mii_status != 0xffff && mii_status != 0x0000) {

X int mii_reg0 = mdio_read(dev, phy, 0);
+ int mii_advert = mdio_read(dev, phy, 4);
X int reg4 = ((mii_status>>6) & tp->to_advertise) | 1;
X tp->phys[phy_idx] = phy;
X tp->advertising[phy_idx++] = reg4;
- printk(KERN_INFO "%s: MII transceiver found at MDIO address "
- "%d, config %4.4x status %4.4x.\n",
- dev->name, phy, mii_reg0, mii_status);
- if (1 || (media_cap[tp->default_port] & MediaIsMII)) {
+ printk(KERN_INFO "%s: MII transceiver #%d "
+ "config %4.4x status %4.4x advertising %4.4x.\n",
+ dev->name, phy, mii_reg0, mii_status, mii_advert);
+ /* Fixup for DLink with miswired PHY. */
+ if (mii_advert != reg4) {
X printk(KERN_DEBUG "%s: Advertising %4.4x on PHY %d,"
X " previously advertising %4.4x.\n",
- dev->name, reg4, phy, mdio_read(dev, phy, 4));
+ dev->name, reg4, phy, mii_advert);
X mdio_write(dev, phy, 4, reg4);
X }
X /* Enable autonegotiation: some boards default to off. */
@@ -812,7 +799,7 @@
X #endif
X
X /* Reset the xcvr interface and turn on heartbeat. */
- switch (chip_id) {
+ switch (chip_idx) {
X case DC21041:
X outl(0x00000000, ioaddr + CSR13);
X outl(0xFFFFFFFF, ioaddr + CSR14);
@@ -829,12 +816,19 @@
X outl(tp->mtable->csr12dir | 0x100, ioaddr + CSR12);
X break;
X case DC21142:
- outl(0x82420200, ioaddr + CSR6);
- outl(0x0001, ioaddr + CSR13);
- outl(0x0003FFFF, ioaddr + CSR14);
- outl(0x0008, ioaddr + CSR15);
- outl(0x0001, ioaddr + CSR13);
- outl(0x1301, ioaddr + CSR12); /* Start NWay. */
+ if (tp->mii_cnt) {
+ outl(0x82020000, ioaddr + CSR6);
+ outl(0x0000, ioaddr + CSR13);
+ outl(0x0000, ioaddr + CSR14);
+ outl(0x820E0000, ioaddr + CSR6);
+ } else {
+ outl(0x82420200, ioaddr + CSR6);
+ outl(0x0001, ioaddr + CSR13);
+ outl(0x0003FFFF, ioaddr + CSR14);
+ outl(0x0008, ioaddr + CSR15);
+ outl(0x0001, ioaddr + CSR13);
+ outl(0x1301, ioaddr + CSR12); /* Start NWay. */
+ }
X break;
X case LC82C168:
X if ( ! tp->mii_cnt) {
@@ -882,7 +876,7 @@
X 0x0303, 0x006D, /* 100baseTx, CSR12 0x03 */ }},
X {"Accton EN1207", 0, 0, 0xE8, { 0x1e00, 0x0000, 0x0800, 0x031F,
X 0x1B01, 0x0000, /* 10base2, CSR12 0x1B */
- 0x1B03, 0x006D, /* 100baseTx, CSR12 0x1B */
+ 0x1B03, 0x006D, /* 100baseTx, CSR12 0x1B */
X 0x0B00, 0x009E, /* 10baseT, CSR12 0x0B */
X }},
X {0, 0, 0, 0, {}}};
@@ -961,7 +955,7 @@


X }
X printk("\n");

X }
-
+
X controller_index = 0;
X if (ee_data[19] > 1) { /* Multiport board. */
X last_ee_data = ee_data;
@@ -1024,7 +1018,7 @@
X media & 0x0800 ? "Autosense" : medianame[media & 15]);
X for (i = 0; i < count; i++) {
X struct medialeaf *leaf = &mtable->mleaf[i];
-
+
X if ((p[0] & 0x80) == 0) { /* 21140 Compact block. */
X leaf->type = 0;
X leaf->media = p[0] & 0x3f;
@@ -1070,13 +1064,9 @@
X #define EE_ENB (0x4800 | EE_CS)


X
X /* Delay between EEPROM clock transitions.

- The 1.2 code is a "nasty" timing loop, but PC compatible machines are
- *supposed* to delay an ISA-compatible period for the SLOW_DOWN_IO macro. */
-#ifdef _LINUX_DELAY_H
-#define eeprom_delay(nanosec) udelay((nanosec + 999)/1000)
-#else
-#define eeprom_delay(nanosec) do { int _i = 3; while (--_i > 0) { __SLOW_DOWN_IO; }} while (0)
-#endif
+ Even at 33Mhz current PCI implementations don't overrun the EEPROM clock.
+ We add a bus turn-around to insure that this remains true. */


+#define eeprom_delay() inl(ee_addr)
X
X /* The EEPROM commands include the alway-set leading bit. */
X #define EE_WRITE_CMD (5 << 6)

@@ -1089,28 +1079,26 @@


X unsigned short retval = 0;

X long ee_addr = ioaddr + CSR9;


X int read_cmd = location | EE_READ_CMD;

-
+


X outl(EE_ENB & ~EE_CS, ee_addr);
X outl(EE_ENB, ee_addr);

-
+


X /* Shift the read command bits out. */

X for (i = 10; i >= 0; i--) {

X short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;

X outl(EE_ENB | dataval, ee_addr);
- eeprom_delay(100);
+ eeprom_delay();
X outl(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);
- eeprom_delay(150);
- outl(EE_ENB | dataval, ee_addr); /* Finish EEPROM a clock tick. */
- eeprom_delay(250);
+ eeprom_delay();
X }
X outl(EE_ENB, ee_addr);
-
+
X for (i = 16; i > 0; i--) {
X outl(EE_ENB | EE_SHIFT_CLK, ee_addr);
- eeprom_delay(100);
+ eeprom_delay();
X retval = (retval << 1) | ((inl(ee_addr) & EE_DATA_READ) ? 1 : 0);
X outl(EE_ENB, ee_addr);
- eeprom_delay(100);
+ eeprom_delay();
X }
X
X /* Terminate the EEPROM access. */
@@ -1150,13 +1138,15 @@
X long ioaddr = dev->base_addr;
X int i = 1000;
X outl(0x60020000 + (phy_id<<23) + (location<<18), ioaddr + 0xA0);
+ inl(ioaddr + 0xA0);
+ inl(ioaddr + 0xA0);
X while (--i > 0)
X if ( ! ((retval = inl(ioaddr + 0xA0)) & 0x80000000))
X return retval & 0xffff;
X return 0xffff;
X }


X
- /* Establish sync by sending at least 32 logic ones. */

+ /* Establish sync by sending at least 32 logic ones. */
X for (i = 32; i >= 0; i--) {
X outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr);
X mdio_delay();
@@ -1201,7 +1191,7 @@
X return;
X }
X
- /* Establish sync by sending 32 logic ones. */
+ /* Establish sync by sending 32 logic ones. */
X for (i = 32; i >= 0; i--) {
X outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr);
X mdio_delay();
@@ -1232,7 +1222,7 @@
X {
X struct tulip_private *tp = (struct tulip_private *)dev->priv;
X long ioaddr = dev->base_addr;
- int i = 0;
+ int i;
X
X /* On some chip revs we must set the MII/SYM port before the reset!? */
X if (tp->mii_cnt || (tp->mtable && tp->mtable->has_mii))
@@ -1240,11 +1230,11 @@
X
X /* Reset the chip, holding bit 0 set at least 50 PCI cycles. */
X outl(0x00000001, ioaddr + CSR0);
-#ifdef _LINUX_DELAY_H
- udelay(2);
-#else
- SLOW_DOWN_IO;
-#endif
+
+ if (request_irq(dev->irq, &tulip_interrupt, SA_SHIRQ, dev->name, dev))


SHAR_EOF
true || echo 'restore of patch-2.0.37 failed'
fi

echo 'End of part 17'
echo 'File patch-2.0.37 is continued in part 18'
echo 18 > _shar_seq_.tmp

Thomas...@ciw.uni-karlsruhe.de

unread,
Jun 16, 1999, 3:00:00 AM6/16/99
to
Archive-name: v2.0/patch-2.0.37/part15

#!/bin/sh
# this is part 15 of a 45 - part archive


# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.0.37 continued
if test ! -r _shar_seq_.tmp; then
echo 'Please unpack part 1 first!'
exit 1
fi
(read Scheck

if test "$Scheck" != 15; then


echo Please unpack part "$Scheck" next!
exit 1
else
exit 0
fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.0.37'
else
echo 'x - continuing with patch-2.0.37'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.0.37' &&

-** (at your option) any later version.
-
-** This program is distributed in the hope that it will be useful,
-** but WITHOUT ANY WARRANTY; without even the implied warranty of
-** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-** GNU General Public License for more details.
-
-** You should have received a copy of the GNU General Public License
-** along with this program; if not, write to the Free Software
-** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-**
-** *************************************************************************

-*/
-
-#ifndef RCMTL_H
-#define RCMTL_H
-
-/* Linux specific includes */
-#define kprintf printk
-#ifdef RC_LINUX_MODULE /* linux modules need non-library version of string functions */
-#include <linux/string.h>
-#else
-#include <string.h>
-#endif
-
-/* PCI/45 Configuration space values */
-#define RC_PCI45_VENDOR_ID 0x4916
-#define RC_PCI45_DEVICE_ID 0x1960
-
-
- /* RedCreek API function return values */
-#define RC_RTN_NO_ERROR 0
-#define RC_RTN_NOT_INIT 1
-#define RC_RTN_FREE_Q_EMPTY 2
-#define RC_RTN_TCB_ERROR 3
-#define RC_RTN_TRANSACTION_ERROR 4
-#define RC_RTN_ADAPTER_ALREADY_INIT 5
-#define RC_RTN_MALLOC_ERROR 6
-#define RC_RTN_ADPTR_NOT_REGISTERED 7
-#define RC_RTN_MSG_REPLY_TIMEOUT 8
-#define RC_RTN_NO_STATUS 9
-#define RC_RTN_NO_FIRM_VER 10
-#define RC_RTN_NO_LINK_SPEED 11
-
-/* Driver capability flags */
-#define WARM_REBOOT_CAPABLE 0x01
-
- /* scalar data types */
-typedef unsigned char U8;
-typedef unsigned char* PU8;
-typedef unsigned short U16;
-typedef unsigned short* PU16;
-typedef unsigned long U32;
-typedef unsigned long* PU32;
-typedef unsigned long BF;
-typedef int RC_RETURN;
-
-
- /*
- ** type PFNWAITCALLBACK
- **
- ** pointer to void function - type used for WaitCallback in some functions
- */
-typedef void (*PFNWAITCALLBACK)(void); /* void argument avoids compiler complaint */
-
- /*
- ** type PFNTXCALLBACK
- **
- ** Pointer to user's transmit callback function. This user function is
- ** called from RCProcMsgQ() when packet have been transmitted from buffers
- ** given in the RCSendPacket() function. BufferContext is a pointer to
- ** an array of 32 bit context values. These are the values the user assigned
- ** and passed in the TCB to the RCSendPacket() function. PcktCount
- ** indicates the number of buffer context values in the BufferContext[] array.
- ** The User's TransmitCallbackFunction should recover (put back in free queue)
- ** the packet buffers associated with the buffer context values.
- */
-typedef void (*PFNTXCALLBACK)(U32 Status,
- U16 PcktCount,
- PU32 BufferContext,
- U16 AdaterID);
-
- /*
- ** type PFNRXCALLBACK
- **
- ** Pointer to user's receive callback function. This user function
- ** is called from RCProcMsgQ() when packets have been received into
- ** previously posted packet buffers throught the RCPostRecvBuffers() function.
- ** The received callback function should process the Packet Descriptor Block
- ** pointed to by PacketDescBlock. See Packet Decription Block below.
- */
-typedef void (*PFNRXCALLBACK)(U32 Status,
- U8 PktCount,
- U32 BucketsRemain,
- PU32 PacketDescBlock,
- U16 AdapterID);
-
- /*
- ** type PFNCALLBACK
- **
- ** Pointer to user's generic callback function. This user function
- ** can be passed to LANReset or LANShutdown and is called when the
- ** the reset or shutdown is complete.
- ** Param1 and Param2 are invalid for LANReset and LANShutdown.
- */
-typedef void (*PFNCALLBACK)(U32 Status,
- U32 Param1,
- U32 Param2,
- U16 AdapterID);
-
-/*
-** Status - Transmit and Receive callback status word
-**
-** A 32 bit Status is returned to the TX and RX callback functions. This value
-** contains both the reply status and the detailed status as follows:
-**
-** 32 24 16 0
-** +------+------+------------+
-** | Reply| | Detailed |
-** |Status| 0 | Status |
-** +------+------+------------+
-**
-** Reply Status and Detailed Status of zero indicates No Errors.
-*/
- /* reply message status defines */
-#define RC_REPLY_STATUS_SUCCESS 0x00
-#define RC_REPLY_STATUS_ABORT_NO_DATA_TRANSFER 0x02
-#define RC_REPLY_STATUS_TRANSACTION_ERROR 0x0A
-
-
-/* DetailedStatusCode defines */
-#define RC_DSC_SUCCESS 0x0000
-#define RC_DSC_DEVICE_FAILURE 0x0001
-#define RC_DSC_DESTINATION_NOT_FOUND 0x0002
-#define RC_DSC_TRANSMIT_ERROR 0x0003
-#define RC_DSC_TRANSMIT_ABORTED 0x0004
-#define RC_DSC_RECEIVE_ERROR 0x0005
-#define RC_DSC_RECEIVE_ABORTED 0x0006
-#define RC_DSC_DMA_ERROR 0x0007
-#define RC_DSC_BAD_PACKET_DETECTED 0x0008
-#define RC_DSC_OUT_OF_MEMORY 0x0009
-#define RC_DSC_BUCKET_OVERRUN 0x000A
-#define RC_DSC_IOP_INTERNAL_ERROR 0x000B
-#define RC_DSC_CANCELED 0x000C
-#define RC_DSC_INVALID_TRANSACTION_CONTEXT 0x000D
-#define RC_DSC_DESTINATION_ADDRESS_DETECTED 0x000E
-#define RC_DSC_DESTINATION_ADDRESS_OMITTED 0x000F
-#define RC_DSC_PARTIAL_PACKET_RETURNED 0x0010
-
-
-/*
-** Packet Description Block (Received packets)
-**
-** A pointer to this block structure is returned to the ReceiveCallback
-** function. It contains the list of packet buffers which have either been
-** filled with a packet or returned to host due to a LANReset function.
-** Currently there will only be one packet per receive bucket (buffer) posted.
-**
-** 32 24 0
-** +-----------------------+ -\
-** | Buffer 1 Context | \
-** +-----------------------+ \
-** | 0xC0000000 | / First Bucket Descriptor
-** +-----+-----------------+ /
-** | 0 | packet 1 length | /
-** +-----------------------+ -\
-** | Buffer 2 Context | \
-** +-----------------------+ \
-** | 0xC0000000 | / Second Bucket Descriptor
-** +-----+-----------------+ /
-** | 0 | packet 2 length | /
-** +-----+-----------------+ -
-** | ... | ----- more bucket descriptors
-** +-----------------------+ -\
-** | Buffer n Context | \
-** +-----------------------+ \
-** | 0xC0000000 | / Last Bucket Descriptor
-** +-----+-----------------+ /
-** | 0 | packet n length | /
-** +-----+-----------------+ -
-**
-** Buffer Context values are those given to adapter in the TCB on calls to
-** RCPostRecvBuffers().
-**
-*/
-
-
-
-/*
-** Transaction Control Block (TCB) structure
-**
-** A structure like this is filled in by the user and passed by reference to
-** RCSendPacket() and RCPostRecvBuffers() functions. Minimum size is five
-** 32-bit words for one buffer with one segment descriptor.
-** MAX_NMBR_POST_BUFFERS_PER_MSG defines the maximum single segment buffers
-** that can be described in a given TCB.
-**
-** 32 0
-** +-----------------------+
-** | Buffer Count | Number of buffers in the TCB
-** +-----------------------+
-** | Buffer 1 Context | first buffer reference
-** +-----------------------+
-** | Buffer 1 Seg Count | number of segments in buffer
-** +-----------------------+
-** | Buffer 1 Seg Desc 1 | first segment descriptor (size, physical address)
-** +-----------------------+
-** | ... | more segment descriptors (size, physical address)
-** +-----------------------+
-** | Buffer 1 Seg Desc n | last segment descriptor (size, physical address)
-** +-----------------------+
-** | Buffer 2 Context | second buffer reference
-** +-----------------------+
-** | Buffer 2 Seg Count | number of segments in buffer
-** +-----------------------+
-** | Buffer 2 Seg Desc 1 | segment descriptor (size, physical address)
-** +-----------------------+
-** | ... | more segment descriptors (size, physical address)
-** +-----------------------+
-** | Buffer 2 Seg Desc n |
-** +-----------------------+
-** | ... | more buffer descriptor blocks ...
-** +-----------------------+
-** | Buffer n Context |
-** +-----------------------+
-** | Buffer n Seg Count |
-** +-----------------------+
-** | Buffer n Seg Desc 1 |
-** +-----------------------+
-** | ... |
-** +-----------------------+
-** | Buffer n Seg Desc n |
-** +-----------------------+
-**
-**
-** A TCB for one contigous packet buffer would look like the following:
-**
-** 32 0
-** +-----------------------+
-** | 1 | one buffer in the TCB
-** +-----------------------+
-** | <user's Context> | user's buffer reference
-** +-----------------------+
-** | 1 | one segment buffer
-** +-----------------------+ _
-** | <buffer size> | size \
-** +-----------------------+ \ segment descriptor
-** | <physical address> | physical address of buffer /
-** +-----------------------+ _/
-**
-*/
-
- /* Buffer Segment Descriptor */
-typedef struct
-{
- U32 size;
- U32 phyAddress;
-}
- BSD, *PBSD;
-
-typedef PU32 PRCTCB;
-/*
-** -------------------------------------------------------------------------
-** Exported functions comprising the API to the message transport layer
-** -------------------------------------------------------------------------
-*/
-
-
- /*
- ** InitRCApiMsgLayer()
- **
- ** Called once prior to using the API message transport layer. User
- ** provides both the physical and virual address of a locked page buffer
- ** that is used as a private buffer for the RedCreek API message
- ** transport layer. This buffer must be a contigous memory block of a
- ** minimum of 16K bytes and long word aligned. The user also must provide
- ** the base address of the RedCreek PCI adapter assigned by BIOS or operating
- ** system. The user provided value AdapterID is a zero based index of the
- ** Ravlin 45/PCI adapter. This interface number is used in all subsequent API
- ** calls to identify which adpapter for which the function is intended.
- ** Up to sixteen interfaces are supported with this API.
- **
- ** Inputs: AdapterID - interface number from 0 to 15
- ** pciBaseAddr - virual base address of PCI (set by BIOS)
- ** p_msgbuf - virual address to private message block (min. 16K)
- ** p_phymsgbuf - physical address of private message block
- ** TransmitCallbackFunction - address of user's TX callback function
- ** ReceiveCallbackFunction - address of user's RX callback function
- **
- */
-RC_RETURN InitRCApiMsgLayer(U16 AdapterID, U32 pciBaseAddr,

- PU8 p_msgbuf, PU8 p_phymsgbuf,
- PFNTXCALLBACK TransmitCallbackFunction,
- PFNRXCALLBACK ReceiveCallbackFunction,
- PFNCALLBACK RebootCallbackFunction);
-

- /*
- ** RCSetRavlinIPandMask()
- **
- ** Set the Ravlin 45/PCI cards IP address and network mask.
- **
- ** IP address and mask must be in network byte order.
- ** For example, IP address 1.2.3.4 and mask 255.255.255.0 would be
- ** 0x04030201 and 0x00FFFFFF on a little endian machine.
- **
- */
-RC_RETURN RCSetRavlinIPandMask(U16 AdapterID, U32 ipAddr, U32 netMask);
-
-


-/*
-** =========================================================================
-** RCGetRavlinIPandMask()
-**
-** get the IP address and MASK from the card
-**
-** =========================================================================
-*/
-RC_RETURN
-RCGetRavlinIPandMask(U16 AdapterID, PU32 pIpAddr, PU32 pNetMask,
- PFNWAITCALLBACK WaitCallback);
-

- /*
- ** RCProcMsgQ()
- **
- ** Called from user's polling loop or Interrupt Service Routine for a PCI
- ** interrupt from the RedCreek PCI adapter. User responsible for determining
- ** and hooking the PCI interrupt. This function will call the registered
- ** callback functions, TransmitCallbackFunction or ReceiveCallbackFunction,
- ** if a TX or RX transaction has completed.
- */
-void RCProcMsgQ(U16 AdapterID);
-
-
- /*
- ** Disable and Enable Adapter interrupts. Adapter interrupts are enabled at
- ** Init time but can be disabled and re-enabled through these two function calls.
- ** Packets will still be put into any posted recieved buffers and packets will
- ** be sent through RCSendPacket() functions. Disabling Adapter interrupts
- ** will prevent hardware interrupt to host even though the outbound msg
- ** queue is not emtpy.
- */
-RC_RETURN RCEnableAdapterInterrupts(U16 adapterID);


-RC_RETURN RCDisableAdapterInterrupts(U16 AdapterID);
-
-

- /*
- ** RCPostRecvBuffers()
- **
- ** Post user's page locked buffers for use by the PCI adapter to
- ** return ethernet packets received from the LAN. Transaction Control Block,
- ** provided by user, contains buffer descriptor(s) which includes a buffer
- ** context number along with buffer size and physical address. See TCB above.
- ** The buffer context and actual packet length are returned to the
- ** ReceiveCallbackFunction when packets have been received. Buffers posted
- ** to the RedCreek adapter are considered owned by the adapter until the
- ** context is return to user through the ReceiveCallbackFunction.
- */
-RC_RETURN RCPostRecvBuffers(U16 AdapterID, PRCTCB pTransactionCtrlBlock);
-#define MAX_NMBR_POST_BUFFERS_PER_MSG 32
-
- /*
- ** RCSendPacket()
- **
- ** Send user's ethernet packet from a locked page buffer.
- ** Packet must have full MAC header, however without a CRC.
- ** Initiator context is a user provided value that is returned
- ** to the TransmitCallbackFunction when packet buffer is free.
- ** Transmit buffer are considered owned by the adapter until context's
- ** returned to user through the TransmitCallbackFunction.
- */
-RC_RETURN RCSendPacket(U16 AdapterID,
- U32 context,
- PRCTCB pTransactionCtrlBlock);
-
-
- /* Ethernet Link Statistics structure */
-typedef struct tag_RC_link_stats
-{
- U32 TX_good; /* good transmit frames */
- U32 TX_maxcol; /* frames not TX due to MAX collisions */
- U32 TX_latecol; /* frames not TX due to late collisions */
- U32 TX_urun; /* frames not TX due to DMA underrun */
- U32 TX_crs; /* frames TX with lost carrier sense */
- U32 TX_def; /* frames deferred due to activity on link */
- U32 TX_singlecol; /* frames TX with one and only on collision */
- U32 TX_multcol; /* frames TX with more than one collision */
- U32 TX_totcol; /* total collisions detected during TX */
- U32 Rcv_good; /* good frames received */
- U32 Rcv_CRCerr; /* frames RX and discarded with CRC errors */
- U32 Rcv_alignerr; /* frames RX with alignment and CRC errors */
- U32 Rcv_reserr; /* good frames discarded due to no RX buffer */
- U32 Rcv_orun; /* RX frames lost due to FIFO overrun */
- U32 Rcv_cdt; /* RX frames with collision during RX */
- U32 Rcv_runt; /* RX frames shorter than 64 bytes */
-}
- RCLINKSTATS, *P_RCLINKSTATS;
-
- /*
- ** RCGetLinkStatistics()
- **
- ** Returns link statistics in user's structure at address StatsReturnAddr
- ** If given, not NULL, the function WaitCallback is called during the wait
- ** loop while waiting for the adapter to respond.
- */
-RC_RETURN RCGetLinkStatistics(U16 AdapterID,


- P_RCLINKSTATS StatsReturnAddr,
- PFNWAITCALLBACK WaitCallback);
-

- /*
- ** RCGetLinkStatus()
- **
- ** Return link status, up or down, to user's location addressed by ReturnAddr.
- ** If given, not NULL, the function WaitCallback is called during the wait
- ** loop while waiting for the adapter to respond.
- */
-RC_RETURN RCGetLinkStatus(U16 AdapterID,
- PU32 pReturnStatus,
- PFNWAITCALLBACK WaitCallback);
-
- /* Link Status defines - value returned in pReturnStatus */
-#define LAN_LINK_STATUS_DOWN 0
-#define LAN_LINK_STATUS_UP 1
-
- /*
- ** RCGetMAC()
- **
- ** Get the current MAC address assigned to user. RedCreek Ravlin 45/PCI
- ** has two MAC addresses. One which is private to the PCI Card, and
- ** another MAC which is given to the user as its link layer MAC address. The
- ** adapter runs in promiscous mode because of the dual address requirement.
- ** The MAC address is returned to the unsigned char array pointer to by mac.
- */
-RC_RETURN RCGetMAC(U16 AdapterID, PU8 mac, PFNWAITCALLBACK WaitCallback);
-
- /*
- ** RCSetMAC()
- **
- ** Set a new user port MAC address. This address will be returned on
- ** subsequent RCGetMAC() calls.
- */
-RC_RETURN RCSetMAC(U16 AdapterID, PU8 mac);
-
- /*
- ** RCSetLinkSpeed()
- **
- ** set adapter's link speed based on given input code.
- */
-RC_RETURN RCSetLinkSpeed(U16 AdapterID, U16 LinkSpeedCode);
- /* Set link speed codes */
-#define LNK_SPD_AUTO_NEG_NWAY 0
-#define LNK_SPD_100MB_FULL 1
-#define LNK_SPD_100MB_HALF 2
-#define LNK_SPD_10MB_FULL 3
-#define LNK_SPD_10MB_HALF 4
-


-
-
-
- /*

- ** RCGetLinkSpeed()
- **
- ** Return link speed code.
- */
- /* Return link speed codes */
-#define LNK_SPD_UNKNOWN 0
-#define LNK_SPD_100MB_FULL 1
-#define LNK_SPD_100MB_HALF 2
-#define LNK_SPD_10MB_FULL 3
-#define LNK_SPD_10MB_HALF 4
-


-RC_RETURN
-RCGetLinkSpeed(U16 AdapterID, PU32 pLinkSpeedCode, PFNWAITCALLBACK WaitCallback);
-

-/*
-** =========================================================================
-** RCReportDriverCapability(U16 AdapterID, U32 capability)
-**
-** Currently defined bits:
-** WARM_REBOOT_CAPABLE 0x01
-**
-** =========================================================================
-*/
-RC_RETURN
-RCReportDriverCapability(U16 AdapterID, U32 capability);
-

-/*


-** RCGetFirmwareVer()
-**
-** Return firmware version in the form "SoftwareVersion : Bt BootVersion"
-**

-** WARNING: user's space pointed to by pFirmString should be at least 60 bytes.


-*/
-RC_RETURN
-RCGetFirmwareVer(U16 AdapterID, PU8 pFirmString, PFNWAITCALLBACK WaitCallback);
-

-/*
-** ----------------------------------------------
-** LAN adapter Reset and Shutdown functions
-** ----------------------------------------------
-*/
- /* resource flag bit assignments for RCResetLANCard() & RCShutdownLANCard() */
-#define RC_RESOURCE_RETURN_POSTED_RX_BUCKETS 0x0001
-#define RC_RESOURCE_RETURN_PEND_TX_BUFFERS 0x0002
-
- /*
- ** RCResetLANCard()
- **
- ** Reset LAN card operation. Causes a software reset of the ethernet
- ** controller and restarts the command and receive units. Depending on
- ** the ResourceFlags given, the buffers are either returned to the
- ** host with reply status of RC_REPLY_STATUS_ABORT_NO_DATA_TRANSFER and
- ** detailed status of RC_DSC_CANCELED (new receive buffers must be
- ** posted after issuing this) OR the buffers are kept and reused by
- ** the ethernet controller. If CallbackFunction is not NULL, the function
- ** will be called when the reset is complete. If the CallbackFunction is
- ** NULL,a 1 will be put into the ReturnAddr after waiting for the reset
- ** to complete (please disable adapter interrupts during this method).
- ** Any outstanding transmit or receive buffers that are complete will be
- ** returned via the normal reply messages before the requested resource
- ** buffers are returned.
- ** A call to RCPostRecvBuffers() is needed to return the ethernet to full
- ** operation if the receive buffers were returned during LANReset.
- ** Note: The IOP status is not affected by a LAN reset.
- */
-RC_RETURN RCResetLANCard(U16 AdapterID, U16 ResourceFlags, PU32 ReturnAddr, PFNCALLBACK CallbackFunction);
-
-
- /*
- ** RCShutdownLANCard()
- **
- ** Shutdown LAN card operation and put into an idle (suspended) state.
- ** The LAN card is restarted with RCResetLANCard() function.
- ** Depending on the ResourceFlags given, the buffers are either returned
- ** to the host with reply status of RC_REPLY_STATUS_ABORT_NO_DATA_TRANSFER
- ** and detailed status of RC_DSC_CANCELED (new receive buffers must be
- ** posted after issuing this) OR the buffers are kept and reused by
- ** the ethernet controller. If CallbackFunction is not NULL, the function
- ** will be called when the reset is complete. If the CallbackFunction is
- ** NULL,a 1 will be put into the ReturnAddr after waiting for the reset
- ** to complete (please disable adapter interrupts during this method).
- ** Any outstanding transmit or receive buffers that are complete will be
- ** returned via the normal reply messages before the requested resource
- ** buffers are returned.
- ** Note: The IOP status is not affected by a LAN shutdown.
- */

-RC_RETURN
-RCShutdownLANCard(U16 AdapterID, U16 ResourceFlags, PU32 ReturnAddr, PFNCALLBACK CallbackFunction);
-

- /*
- ** RCResetAdapter();
- ** Initializes ADAPTERState to ADAPTER_STATE_RESET.
- ** Stops access to outbound message Q.
- ** Discards any outstanding transmit or posted receive buffers.
- ** Clears outbound message Q.
- */
-RC_RETURN
-RCResetAdapter(U16 AdapterID);
-
-#endif /* RCMTL_H */
diff -u --recursive --new-file v2.0.36/linux/drivers/net/rcpci45.c linux/drivers/net/rcpci45.c
--- v2.0.36/linux/drivers/net/rcpci45.c Sun Nov 15 21:51:46 1998
+++ linux/drivers/net/rcpci45.c Sun Jun 13 10:21:01 1999
@@ -1,10 +1,11 @@
X /*
+**
X ** RCpci45.c
X **
X **
X **
X ** ---------------------------------------------------------------------
-** --- Copyright (c) 1998, RedCreek Communications Inc. ---
+** --- Copyright (c) 1998, 1999, RedCreek Communications Inc. ---


X ** --- All rights reserved. ---
X ** ---------------------------------------------------------------------
X **

@@ -12,14 +13,13 @@
X **
X ** Known Problems
X **
-** Billions and Billions...
-**
-** ... apparently added by Brian. Pete knows of no bugs.
+** None known at this time.
X **
X ** TODO:
X ** -Get rid of the wait loops in the API and replace them
X ** with system independent delays ...something like
-** "delayms(2)".
+** "delayms(2)". However, under normal circumstances, the
+** delays are very short so they're not a problem.
X **
X ** This program is free software; you can redistribute it and/or modify
X ** it under the terms of the GNU General Public License as published by
@@ -35,20 +35,24 @@
X ** along with this program; if not, write to the Free Software
X ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X **
+**
+** Pete Popov, January 11,99: Fixed a couple of 2.1.x problems
+** (virt_to_bus() not called), tested it under 2.2pre5 (as a module), and
+** added a #define(s) to enable the use of the same file for both, the 2.0.x
+** kernels as well as the 2.1.x.
+**
+** Ported to 2.1.x by Alan Cox 1998/12/9.
+**
+** Sometime in mid 1998, written by Pete Popov and Brian Moyle.
+**
X ***************************************************************************/
X
-#define __NO_VERSION__ /* don't define kernel_verion in module.h */
-


X static char *version =

-"RedCreek Communications PCI linux driver version 1.32 Beta\n";
+"RedCreek Communications PCI linux driver version 2.02\n";
X
X
-#include <linux/config.h>
X #include <linux/module.h>
X #include <linux/version.h>
-
-static char kernel_version [] = UTS_RELEASE;
-
X #include <linux/kernel.h>


X #include <linux/sched.h>
X #include <linux/string.h>

@@ -65,25 +69,34 @@


X #include <asm/bitops.h>
X #include <asm/io.h>

X
+#if LINUX_VERSION_CODE >= 0x020100
+#define LINUX_2_1
+#endif
+
+#ifdef LINUX_2_1
+#include <asm/uaccess.h>
+#endif
+
X #include <linux/if_ether.h>


X #include <linux/netdevice.h>
X #include <linux/etherdevice.h>
X #include <linux/skbuff.h>

X
+
X #define RC_LINUX_MODULE
-#include "rcmtl.h"
+#include "rclanmtl.h"
X #include "rcif.h"
X
X #define RUN_AT(x) (jiffies + (x))


-#define DEV_ALLOC_SKB(len) dev_alloc_skb(len + 2)

-


-#define FREE_IRQ(irqnum, dev) free_irq(irqnum)
-#define REQUEST_IRQ(i,h,f,n, instance) request_irq(i,h,f,n)

-#define IRQ(irq, dev_id, pt_regs) (irq, pt_regs)

X
X #define NEW_MULTICAST
X #include <linux/delay.h>
X
+#ifndef LINUX_2_1
+#define ioremap vremap
+#define iounmap vfree
+#endif
+
X /* PCI/45 Configuration space values */
X #define RC_PCI45_VENDOR_ID 0x4916
X #define RC_PCI45_DEVICE_ID 0x1960
@@ -111,25 +124,25 @@
X typedef struct
X {
X
- /*
- * pointer to the device structure which is part
- * of the interface to the Linux kernel.
- */
- struct device *dev;
+ /*
+ * pointer to the device structure which is part
+ * of the interface to the Linux kernel.
+ */
+ struct device *dev;
X
- char devname[8]; /* "ethN" string */
- U8 id; /* the AdapterID */
- U32 pci_addr; /* the pci address of the adapter */
- U32 bus;
- U32 function;
- struct timer_list timer; /* timer */
- struct enet_statistics stats; /* the statistics structure */
- struct device *next; /* points to the next RC adapter */
- unsigned long numOutRcvBuffers;/* number of outstanding receive buffers*/
- unsigned char shutdown;
- unsigned char reboot;
- unsigned char nexus;
- PU8 PLanApiPA; /* Pointer to Lan Api Private Area */
+ char devname[8]; /* "ethN" string */
+ U8 id; /* the AdapterID */
+ U32 pci_addr; /* the pci address of the adapter */
+ U32 bus;
+ U32 function;
+ struct timer_list timer; /* timer */
+ struct enet_statistics stats; /* the statistics structure */
+ struct device *next; /* points to the next RC adapter */
+ unsigned long numOutRcvBuffers;/* number of outstanding receive buffers*/
+ unsigned char shutdown;
+ unsigned char reboot;
+ unsigned char nexus;
+ PU8 PLanApiPA; /* Pointer to Lan Api Private Area */
X
X }
X DPA, *PDPA;


@@ -138,18 +151,17 @@
X

X static PDPA PCIAdapters[MAX_ADAPTERS] =
X {


- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL

+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
X };
X
X
-static int RCscan(void);
-static struct device
-*RCfound_device(struct device *, int, int, int, int, int, int);
+static int RCinit(struct device *dev);
+static int RCscan(struct device *dev);
+static int RCfound_device(struct device *, int, int, int, int, int, int);
X
-static int RCprobe1(struct device *);
X static int RCopen(struct device *);
X static int RC_xmit_packet(struct sk_buff *, struct device *);
X static void RCinterrupt(int, void *, struct pt_regs *);
@@ -170,261 +182,282 @@
X #ifdef MODULE
X int init_module(void)
X #else
-int rcpci_probe(struct netdevice *dev)
+int rcpci_probe(struct device *dev)
X #endif
X {
- int cards_found;
+ int cards_found;
X
- printk(version);
-
- root_RCdev = NULL;
- cards_found = RCscan();
-#ifdef MODULE

- return cards_found ? 0 : -ENODEV;

+#ifdef MODULE
+ cards_found = RCscan(NULL);
X #else
- return -1;
-#endif
+ cards_found = RCscan(dev);
+#endif
+ if (cards_found)
+ printk(version);
+ return cards_found ? 0 : -ENODEV;
X }
X
-static int RCscan(void)
+static int RCscan(struct device *dev)
X {
- int cards_found = 0;
- struct device *dev = 0;
+ int cards_found = 0;


+ static int pci_index = 0;
X
- if (pcibios_present())

- {


- static int pci_index = 0;

- unsigned char pci_bus, pci_device_fn;

- int scan_status;


- int board_index = 0;

-
- for (;pci_index < 0xff; pci_index++)
- {
- unsigned char pci_irq_line;
- unsigned short pci_command, vendor, device, class;
- unsigned int pci_ioaddr;
-
-
- scan_status =
- (pcibios_find_device (RC_PCI45_VENDOR_ID,
- RC_PCI45_DEVICE_ID,
- pci_index,
- &pci_bus,
- &pci_device_fn));
-#ifdef RCDEBUG
- printk("rc scan_status = 0x%X\n", scan_status);
-#endif
- if (scan_status != PCIBIOS_SUCCESSFUL)
- break;
- pcibios_read_config_word(pci_bus,
- pci_device_fn,
- PCI_VENDOR_ID, &vendor);
- pcibios_read_config_word(pci_bus,
- pci_device_fn,
- PCI_DEVICE_ID, &device);
- pcibios_read_config_byte(pci_bus,
- pci_device_fn,


- PCI_INTERRUPT_LINE, &pci_irq_line);
- pcibios_read_config_dword(pci_bus,

- pci_device_fn,
- PCI_BASE_ADDRESS_0, &pci_ioaddr);
- pcibios_read_config_word(pci_bus,
- pci_device_fn,
- PCI_CLASS_DEVICE, &class);
-
- pci_ioaddr &= ~0xf;
-
-#ifdef RCDEBUG
- printk("rc: Found RedCreek PCI adapter\n");
- printk("rc: pci class = 0x%x 0x%x \n", class, class>>8);
- printk("rc: pci_bus = %d, pci_device_fn = %d\n", pci_bus, pci_device_fn);
- printk("rc: pci_irq_line = 0x%x \n", pci_irq_line);
- printk("rc: pci_ioaddr = 0x%x\n", pci_ioaddr);
-#endif
-
-#if 0
- if (check_region(pci_ioaddr, 32768))
- {
- printk("rc: check_region failed\n");
- continue;
- }
- else
- {
- printk("rc: check_region passed\n");
- }
-#endif
-
- /*
- * Get and check the bus-master and latency values.
- * Some PCI BIOSes fail to set the master-enable bit.
- */
-
- pcibios_read_config_word(pci_bus,
- pci_device_fn,
- PCI_COMMAND,
- &pci_command);
- if ( ! (pci_command & PCI_COMMAND_MASTER)) {
- printk("rc: PCI Master Bit has not been set!\n");
-
- pci_command |= PCI_COMMAND_MASTER;
- pcibios_write_config_word(pci_bus,
- pci_device_fn,
- PCI_COMMAND,
- pci_command);
- }
- if ( ! (pci_command & PCI_COMMAND_MEMORY)) {
- /*
- * If the BIOS did not set the memory enable bit, what else
- * did it not initialize? Skip this adapter.
- */
- printk("rc: Adapter %d, PCI Memory Bit has not been set!\n",
- cards_found);
- printk("rc: Bios problem? \n");
- continue;
- }
-
- dev = RCfound_device(dev, pci_ioaddr, pci_irq_line,
- pci_bus, pci_device_fn,
- board_index++, cards_found);
-
- if (dev) {


- dev = 0;
- cards_found++;

- }
- }
- }
- printk("rc: found %d cards \n", cards_found);
- return cards_found;
+ if (!pcibios_present())
+ return cards_found;
+
+ for (;pci_index < 0x8; pci_index++)
+ {


+ unsigned char pci_bus, pci_device_fn;

+ int scan_status;
+ int board_index = 0;
+ unsigned char pci_irq_line;
+ unsigned short pci_command, vendor, device, class;
+ unsigned int pci_ioaddr;
+
+
+ scan_status =
+ (pcibios_find_device (RC_PCI45_VENDOR_ID,
+ RC_PCI45_DEVICE_ID,
+ pci_index,
+ &pci_bus,
+ &pci_device_fn));
+#ifdef RCDEBUG
+ printk("rc scan_status = 0x%X\n", scan_status);
+#endif
+ if (scan_status != PCIBIOS_SUCCESSFUL)
+ break;
+ pcibios_read_config_word(pci_bus,
+ pci_device_fn,

+ PCI_VENDOR_ID, &vendor);
+ pcibios_read_config_word(pci_bus,

+ pci_device_fn,
+ PCI_DEVICE_ID, &device);
+ pcibios_read_config_byte(pci_bus,
+ pci_device_fn,
+ PCI_INTERRUPT_LINE, &pci_irq_line);
+ pcibios_read_config_dword(pci_bus,
+ pci_device_fn,
+ PCI_BASE_ADDRESS_0, &pci_ioaddr);
+ pcibios_read_config_word(pci_bus,
+ pci_device_fn,
+ PCI_CLASS_DEVICE, &class);
+
+ pci_ioaddr &= ~0xf;
+
+#ifdef RCDEBUG
+ printk("rc: Found RedCreek PCI adapter\n");
+ printk("rc: pci class = 0x%x 0x%x \n", class, class>>8);
+ printk("rc: pci_bus = %d, pci_device_fn = %d\n", pci_bus, pci_device_fn);
+ printk("rc: pci_irq_line = 0x%x \n", pci_irq_line);
+ printk("rc: pci_ioaddr = 0x%x\n", pci_ioaddr);
+#endif
+
+ if (check_region(pci_ioaddr, 2*32768))
+ {
+ printk("rc: check_region failed\n");
+ continue;
+ }
+#ifdef RCDEBUG
+ else
+ {
+ printk("rc: check_region passed\n");
+ }
+#endif
+
+ /*
+ * Get and check the bus-master and latency values.
+ * Some PCI BIOSes fail to set the master-enable bit.
+ */
+
+ pcibios_read_config_word(pci_bus,
+ pci_device_fn,
+ PCI_COMMAND,
+ &pci_command);
+ if ( ! (pci_command & PCI_COMMAND_MASTER)) {
+ printk("rc: PCI Master Bit has not been set!\n");
+
+ pci_command |= PCI_COMMAND_MASTER;
+ pcibios_write_config_word(pci_bus,
+ pci_device_fn,
+ PCI_COMMAND,
+ pci_command);
+ }
+ if ( ! (pci_command & PCI_COMMAND_MEMORY)) {
+ /*
+ * If the BIOS did not set the memory enable bit, what else
+ * did it not initialize? Skip this adapter.
+ */
+ printk("rc: Adapter %d, PCI Memory Bit has not been set!\n",
+ cards_found);
+ printk("rc: Bios problem? \n");
+ continue;
+ }
+
+ if (!RCfound_device(dev, pci_ioaddr, pci_irq_line,
+ pci_bus, pci_device_fn,
+ board_index++, cards_found))
+ {


+ dev = 0;
+ cards_found++;

+ }
+ }
+#ifdef RCDEBUG
+ printk("rc: found %d cards \n", cards_found);
+#endif
+ return cards_found;


X }
X
-static struct device *

+static int RCinit(struct device *dev)
+{
+ dev->open = &RCopen;
+ dev->hard_start_xmit = &RC_xmit_packet;
+ dev->stop = &RCclose;
+ dev->get_stats = &RCget_stats;
+ dev->do_ioctl = &RCioctl;
+ dev->set_config = &RCconfig;


+ return 0;
+}
+

+static int
X RCfound_device(struct device *dev, int memaddr, int irq,
X int bus, int function, int product_index, int card_idx)
X {
- int dev_size = 32768;
- unsigned long *vaddr=0;
- PDPA pDpa;
- int init_status;
-
- /*
- * Allocate and fill new device structure.
- * We need enough for struct device plus DPA plus the LAN API private
- * area, which requires a minimum of 16KB. The top of the allocated
- * area will be assigned to struct device; the next chunk will be
- * assigned to DPA; and finally, the rest will be assigned to the
- * the LAN API layer.
- */
- dev = (struct device *) kmalloc(dev_size, GFP_DMA | GFP_KERNEL |GFP_ATOMIC);
- memset(dev, 0, dev_size);
+ int dev_size = 32768;
+ unsigned long *vaddr=0;
+ PDPA pDpa;
+ int init_status;
+
+ /*
+ * Allocate and fill new device structure.
+ * We need enough for struct device plus DPA plus the LAN API private
+ * area, which requires a minimum of 16KB. The top of the allocated
+ * area will be assigned to struct device; the next chunk will be
+ * assigned to DPA; and finally, the rest will be assigned to the
+ * the LAN API layer.
+ */
+
+#ifdef MODULE
+ dev = (struct device *) kmalloc(dev_size, GFP_DMA | GFP_KERNEL |GFP_ATOMIC);
+ if (!dev)
+ {
+ printk("rc: unable to kmalloc dev\n");
+ return 1;
+ }
+ memset(dev, 0, dev_size);
+ /*
+ * dev->priv will point to the start of DPA.
+ */
+ dev->priv = (void *)(((long)dev + sizeof(struct device) + 15) & ~15);
+#else
+ dev->priv = 0;
+ dev->priv = (struct device *) kmalloc(dev_size, GFP_DMA | GFP_KERNEL |GFP_ATOMIC);
+ if (!dev->priv)
+ {
+ printk("rc: unable to kmalloc private area\n");
+ return 1;
+ }
+ memset(dev->priv, 0, dev_size);
+#endif
+
X #ifdef RCDEBUG
- printk("rc: dev = 0x%08X\n", (uint)dev);
-#endif
+ printk("rc: dev = 0x%x, dev->priv = 0x%x\n", (uint)dev, (uint)dev->priv);
+#endif
X
- /*
- * dev->priv will point to the start of DPA.
- */


- dev->priv = (void *)(((long)dev + sizeof(struct device) + 15) & ~15);

- pDpa = dev->priv;
- dev->name = pDpa->devname;
-
- pDpa->dev = dev; /* this is just for easy reference */
- pDpa->function = function;
- pDpa->bus = bus;
- pDpa->id = card_idx; /* the device number */
- pDpa->pci_addr = memaddr;
- PCIAdapters[card_idx] = pDpa;
-#ifdef RCDEBUG
- printk("rc: pDpa = 0x%x, id = %d \n", (uint)pDpa, (uint)pDpa->id);
-#endif
-
- /*
- * Save the starting address of the LAN API private area. We'll
- * pass that to InitRCApiMsgLayer().
- */
- pDpa->PLanApiPA = (void *)(((long)pDpa + sizeof(DPA) + 0xff) & ~0xff);
+ pDpa = dev->priv;
+ if (!dev->name)
+ dev->name = pDpa->devname;
+
+ pDpa->dev = dev; /* this is just for easy reference */
+ pDpa->function = function;
+ pDpa->bus = bus;
+ pDpa->id = card_idx; /* the device number */
+ pDpa->pci_addr = memaddr;
+ PCIAdapters[card_idx] = pDpa;
X #ifdef RCDEBUG
- printk("rc: pDpa->PLanApiPA = 0x%x\n", (uint)pDpa->PLanApiPA);
+ printk("rc: pDpa = 0x%x, id = %d \n", (uint)pDpa, (uint)pDpa->id);
X #endif
-
- /* The adapter is accessable through memory-access read/write, not
- * I/O read/write. Thus, we need to map it to some virtual address
- * area in order to access the registers are normal memory.
- */
- vaddr = (ulong *) vremap (memaddr, 32768);
+
+ /*
+ * Save the starting address of the LAN API private area. We'll
+ * pass that to RCInitI2OMsgLayer().
+ */
+ pDpa->PLanApiPA = (void *)(((long)pDpa + sizeof(DPA) + 0xff) & ~0xff);
X #ifdef RCDEBUG
- printk("rc: RCfound_device: 0x%x, priv = 0x%x, vaddr = 0x%x\n",
- (uint)dev, (uint)dev->priv, (uint)vaddr);
+ printk("rc: pDpa->PLanApiPA = 0x%x\n", (uint)pDpa->PLanApiPA);
X #endif
- dev->base_addr = (unsigned long)vaddr;


- dev->irq = irq;

- dev->interrupt = 0;
+

+ /* The adapter is accessable through memory-access read/write, not
+ * I/O read/write. Thus, we need to map it to some virtual address
+ * area in order to access the registers are normal memory.
+ */
+ vaddr = (ulong *) ioremap (memaddr, 2*32768);
+#ifdef RCDEBUG
+ printk("rc: RCfound_device: 0x%x, priv = 0x%x, vaddr = 0x%x\n",
+ (uint)dev, (uint)dev->priv, (uint)vaddr);
+#endif
+ dev->base_addr = (unsigned long)vaddr;


+ dev->irq = irq;

+ dev->interrupt = 0;

+
+ /*
+ * Request a shared interrupt line.
+ */
+ if ( request_irq(dev->irq, (void *)RCinterrupt,
+ SA_INTERRUPT|SA_SHIRQ, "RedCreek VPN Adapter", dev) )
+ {
+ printk( "RC PCI 45: %s: unable to get IRQ %d\n", (PU8)dev->name, (uint)dev->irq );
+ iounmap(vaddr);
+ kfree(dev);
+ return 1;
+ }
X
- /*
- * Request a shared interrupt line.
- */
- if ( request_irq(dev->irq, (void *)RCinterrupt,
- SA_INTERRUPT|SA_SHIRQ, "RedCreek VPN Adapter", dev) )
- {
- printk( "RC PCI 45: %s: unable to get IRQ %d\n", (PU8)dev->name, (uint)dev->irq );
- vfree(vaddr);
- kfree(dev);


- return 0;
- }
-

- init_status = InitRCApiMsgLayer(pDpa->id, dev->base_addr,
- pDpa->PLanApiPA, pDpa->PLanApiPA,
- (PFNTXCALLBACK)RCxmit_callback,
- (PFNRXCALLBACK)RCrecv_callback,
- (PFNCALLBACK)RCreboot_callback);

-#ifdef RCDEBUG
- printk("rc: msg initted: status = 0x%x\n", init_status);
-#endif
- if (init_status)
- {
- printk("rc: Unable to initialize msg layer\n");
- free_irq(dev->irq, dev);
- vfree(vaddr);
- kfree(dev);
- return 0;
- }
- if (RCGetMAC(pDpa->id, dev->dev_addr, NULL))
- {
- printk("rc: Unable to get adapter MAC\n");
- free_irq(dev->irq, dev);
- vfree(vaddr);
- kfree(dev);


- return 0;
- }
-

- DriverControlWord |= WARM_REBOOT_CAPABLE;


- RCReportDriverCapability(pDpa->id, DriverControlWord);
-

- dev->init = RCprobe1;
- ether_setup(dev); /* linux kernel interface */
-
- pDpa->next = root_RCdev;
- root_RCdev = dev;
-
- if (register_netdev(dev) != 0) /* linux kernel interface */
- {
- printk("rc: unable to register device \n");
- free_irq(dev->irq, dev);
- vfree(vaddr);
- kfree(dev);
- return 0;
- }
- return dev;
-}


+ init_status = RCInitI2OMsgLayer(pDpa->id, dev->base_addr,

+ pDpa->PLanApiPA, (PU8)virt_to_bus((void *)pDpa->PLanApiPA),


+ (PFNTXCALLBACK)RCxmit_callback,
+ (PFNRXCALLBACK)RCrecv_callback,
+ (PFNCALLBACK)RCreboot_callback);

+ if (init_status)
+ {
+ printk("rc: Unable to initialize msg layer\n");
+ free_irq(dev->irq, dev);
+ iounmap(vaddr);
+ kfree(dev);
+ return 1;
+ }
+ if (RCGetMAC(pDpa->id, dev->dev_addr, NULL))
+ {
+ printk("rc: Unable to get adapter MAC\n");
+ free_irq(dev->irq, dev);
+ iounmap(vaddr);
+ kfree(dev);
+ return 1;
+ }
X
-static int RCprobe1(struct device *dev)
-{
- dev->open = RCopen;
- dev->hard_start_xmit = RC_xmit_packet;
- dev->stop = RCclose;
- dev->get_stats = RCget_stats;
- dev->do_ioctl = RCioctl;
- dev->set_config = RCconfig;
- return 0;
+ DriverControlWord |= WARM_REBOOT_CAPABLE;


+ RCReportDriverCapability(pDpa->id, DriverControlWord);
+

+ dev->init = &RCinit;
+ ether_setup(dev); /* linux kernel interface */
+
+ pDpa->next = root_RCdev;
+ root_RCdev = dev;
+
+#ifdef MODULE
+ if (register_netdev(dev) != 0) /* linux kernel interface */
+ {
+ printk("rc: unable to register device \n");
+ free_irq(dev->irq, dev);
+ iounmap(vaddr);
+ kfree(dev);
+ return 1;
+ }
+#else
+ RCinit(dev);
+#endif
+ printk("%s: RedCreek Communications IPSEC VPN adapter\n",
+ dev->name);
+
+ return 0; /* success */


X }
X
X static int

@@ -438,25 +471,25 @@
X #ifdef RCDEBUG
X printk("rc: RCopen\n");
X #endif
- RCEnableAdapterInterrupts(pDpa->id);
+ RCEnableI2OInterrupts(pDpa->id);
X
X if (pDpa->nexus)
X {
- /* This is not the first time RCopen is called. Thus,
- * the interface was previously opened and later closed
- * by RCclose(). RCclose() does a Shutdown; to wake up
- * the adapter, a reset is mandatory before we can post
- * receive buffers. However, if the adapter initiated
- * a reboot while the interface was closed -- and interrupts
- * were turned off -- we need will need to reinitialize
- * the adapter, rather than simply waking it up.
- */
+ /* This is not the first time RCopen is called. Thus,
+ * the interface was previously opened and later closed
+ * by RCclose(). RCclose() does a Shutdown; to wake up
+ * the adapter, a reset is mandatory before we can post
+ * receive buffers. However, if the adapter initiated
+ * a reboot while the interface was closed -- and interrupts
+ * were turned off -- we need will need to reinitialize
+ * the adapter, rather than simply waking it up.
+ */
X printk("rc: Waking up adapter...\n");
X RCResetLANCard(pDpa->id,0,0,0);
X }
X else
X {
- pDpa->nexus = 1;
+ pDpa->nexus = 1;
X }
X
X while(post_buffers)
@@ -469,19 +502,19 @@
X
X if ( count < requested )
X {
- /*
- * Check to see if we were able to post any buffers at all.
- */
- if (post_buffers == MAX_NMBR_RCV_BUFFERS)
- {
- printk("rc: Error RCopen: not able to allocate any buffers\r\n");
- return(-ENOMEM);
- }
- printk("rc: Warning RCopen: not able to allocate all requested buffers\r\n");
- break; /* we'll try to post more buffers later */
+ /*
+ * Check to see if we were able to post any buffers at all.
+ */
+ if (post_buffers == MAX_NMBR_RCV_BUFFERS)
+ {
+ printk("rc: Error RCopen: not able to allocate any buffers\r\n");
+ return(-ENOMEM);
+ }
+ printk("rc: Warning RCopen: not able to allocate all requested buffers\r\n");
+ break; /* we'll try to post more buffers later */
X }
X else
- post_buffers -= count;
+ post_buffers -= count;
X }
X pDpa->numOutRcvBuffers = MAX_NMBR_RCV_BUFFERS - post_buffers;
X pDpa->shutdown = 0; /* just in case */
@@ -496,68 +529,70 @@
X RC_xmit_packet(struct sk_buff *skb, struct device *dev)
X {
X

- PDPA pDpa = (PDPA) dev->priv;

- singleTCB tcb;
- psingleTCB ptcb = &tcb;

- RC_RETURN status = 0;


+ PDPA pDpa = (PDPA) dev->priv;

+ singleTCB tcb;
+ psingleTCB ptcb = &tcb;

+ RC_RETURN status = 0;
X
- if (dev->tbusy || pDpa->shutdown || pDpa->reboot)
- {
+ if (dev->tbusy || pDpa->shutdown || pDpa->reboot)
+ {
X #ifdef RCDEBUG
- printk("rc: RC_xmit_packet: tbusy!\n");
+ printk("rc: RC_xmit_packet: tbusy!\n");
X #endif
- return 1;
- }
+ dev->tbusy = 1;
+ return 1;
+ }
X
- if ( skb->len <= 0 )
- {
- printk("RC_xmit_packet: skb->len less than 0!\n");
- return 0;
- }
-
- /*
- * The user is free to reuse the TCB after RCSendPacket() returns, since
- * the function copies the necessary info into its own private space. Thus,
- * our TCB can be a local structure. The skb, on the other hand, will be
- * freed up in our interrupt handler.
- */


- ptcb->bcount = 1;

- /*
- * we'll get the context when the adapter interrupts us to tell us that
- * the transmision is done. At that time, we can free skb.


- */
- ptcb->b.context = (U32)skb;
- ptcb->b.scount = 1;

- ptcb->b.size = skb->len;


- ptcb->b.addr = (U32)skb->data;

-
-#ifdef RCDEBUG
- printk("rc: RC xmit: skb = 0x%x, pDpa = 0x%x, id = %d, ptcb = 0x%x\n",
- (uint)skb, (uint)pDpa, (uint)pDpa->id, (uint)ptcb);
-#endif
- if ( (status = RCSendPacket(pDpa->id, (U32)NULL, (PRCTCB)ptcb))
- != RC_RTN_NO_ERROR)
- {
-#ifdef RCDEBUG
- printk("rc: RC send error 0x%x\n", (uint)status);
-#endif
- dev->tbusy = 1;
- }
- else
- {
- dev->trans_start = jiffies;
- // dev->tbusy = 0;
- }
- /*
- * That's it!
- */
- return 0;
+ if ( skb->len <= 0 )
+ {
+ printk("RC_xmit_packet: skb->len less than 0!\n");
+ return 0;
+ }
+
+ /*
+ * The user is free to reuse the TCB after RCI2OSendPacket() returns, since
+ * the function copies the necessary info into its own private space. Thus,
+ * our TCB can be a local structure. The skb, on the other hand, will be
+ * freed up in our interrupt handler.
+ */


+ ptcb->bcount = 1;

+ /*
+ * we'll get the context when the adapter interrupts us to tell us that
+ * the transmision is done. At that time, we can free skb.


+ */
+ ptcb->b.context = (U32)skb;
+ ptcb->b.scount = 1;

+ ptcb->b.size = skb->len;


+ ptcb->b.addr = virt_to_bus((void *)skb->data);
+

+#ifdef RCDEBUG
+ printk("rc: RC xmit: skb = 0x%x, pDpa = 0x%x, id = %d, ptcb = 0x%x\n",
+ (uint)skb, (uint)pDpa, (uint)pDpa->id, (uint)ptcb);
+#endif
+ if ( (status = RCI2OSendPacket(pDpa->id, (U32)NULL, (PRCTCB)ptcb))
+ != RC_RTN_NO_ERROR)
+ {
+#ifdef RCDEBUG
+ printk("rc: RC send error 0x%x\n", (uint)status);
+#endif
+ dev->tbusy = 1;
+ return 1;
+ }
+ else
+ {
+ dev->trans_start = jiffies;
+ // dev->tbusy = 0;
+ }
+ /*
+ * That's it!
+ */


+ return 0;
X }
X

X /*
X * RCxmit_callback()
X *
- * The transmit callback routine. It's called by RCProcMsgQ()
+ * The transmit callback routine. It's called by RCProcI2OMsgQ()
X * because the adapter is done with one or more transmit buffers and
X * it's returning them to us, or we asked the adapter to return the
X * outstanding transmit buffers by calling RCResetLANCard() with
@@ -574,80 +609,84 @@
X PDPA pDpa;
X struct device *dev;


X
- pDpa = PCIAdapters[AdapterID];

- if (!pDpa)
- {
- printk("rc: Fatal error: xmit callback, !pDpa\n");
- return;
- }


- dev = pDpa->dev;
+ pDpa = PCIAdapters[AdapterID];

+ if (!pDpa)
+ {
+ printk("rc: Fatal error: xmit callback, !pDpa\n");
+ return;
+ }


+ dev = pDpa->dev;
X

X // printk("xmit_callback: Status = 0x%x\n", (uint)Status);
- if (Status != RC_REPLY_STATUS_SUCCESS)
- {
- printk("rc: xmit_callback: Status = 0x%x\n", (uint)Status);
- }
+ if (Status != I2O_REPLY_STATUS_SUCCESS)
+ {
+ printk("rc: xmit_callback: Status = 0x%x\n", (uint)Status);
+ }
X #ifdef RCDEBUG
- if (pDpa->shutdown || pDpa->reboot)
- printk("rc: xmit callback: shutdown||reboot\n");
+ if (pDpa->shutdown || pDpa->reboot)
+ printk("rc: xmit callback: shutdown||reboot\n");


X #endif
X
X #ifdef RCDEBUG

- printk("rc: xmit_callback: PcktCount = %d, BC = 0x%x\n",
- (uint)PcktCount, (uint)BufferContext);
+ printk("rc: xmit_callback: PcktCount = %d, BC = 0x%x\n",
+ (uint)PcktCount, (uint)BufferContext);
X #endif
- while (PcktCount--)
- {
- skb = (struct sk_buff *)(BufferContext[0]);
+ while (PcktCount--)
+ {
+ skb = (struct sk_buff *)(BufferContext[0]);
X #ifdef RCDEBUG
- printk("rc: skb = 0x%x\n", (uint)skb);
+ printk("rc: skb = 0x%x\n", (uint)skb);
X #endif
- BufferContext++;
- dev_kfree_skb (skb, FREE_WRITE);
- }


- dev->tbusy = 0;

+ BufferContext++;


+#ifdef LINUX_2_1
+ dev_kfree_skb (skb);
+#else

+ dev_kfree_skb (skb, FREE_WRITE);
+#endif
+ }


+ dev->tbusy = 0;

X
X }
X
X static void
X RCreset_callback(U32 Status, U32 p1, U32 p2, U16 AdapterID)
X {
- PDPA pDpa;
- struct device *dev;
+ PDPA pDpa;
+ struct device *dev;


X
- pDpa = PCIAdapters[AdapterID];
- dev = pDpa->dev;
+ pDpa = PCIAdapters[AdapterID];
+ dev = pDpa->dev;

X #ifdef RCDEBUG
- printk("rc: RCreset_callback Status 0x%x\n", (uint)Status);
+ printk("rc: RCreset_callback Status 0x%x\n", (uint)Status);
X #endif
- /*
- * Check to see why we were called.
- */
- if (pDpa->shutdown)
- {
- printk("rc: Shutting down interface\n");


- pDpa->shutdown = 0;
- pDpa->reboot = 0;

- MOD_DEC_USE_COUNT;
- }
- else if (pDpa->reboot)
- {
- printk("rc: reboot, shutdown adapter\n");
- /*
- * We don't set any of the flags in RCShutdownLANCard()
- * and we don't pass a callback routine to it.
- * The adapter will have already initiated the reboot by
- * the time the function returns.
- */
- RCDisableAdapterInterrupts(pDpa->id);
- RCShutdownLANCard(pDpa->id,0,0,0);
- printk("rc: scheduling timer...\n");


- init_timer(&pDpa->timer);
- pDpa->timer.expires = RUN_AT((30*HZ)/10); /* 3 sec. */
- pDpa->timer.data = (unsigned long)dev;
- pDpa->timer.function = &rc_timer; /* timer handler */
- add_timer(&pDpa->timer);
- }

+ /*
+ * Check to see why we were called.
+ */
+ if (pDpa->shutdown)
+ {
+ printk("rc: Shutting down interface\n");


+ pDpa->shutdown = 0;
+ pDpa->reboot = 0;

+ MOD_DEC_USE_COUNT;
+ }
+ else if (pDpa->reboot)
+ {
+ printk("rc: reboot, shutdown adapter\n");
+ /*
+ * We don't set any of the flags in RCShutdownLANCard()
+ * and we don't pass a callback routine to it.
+ * The adapter will have already initiated the reboot by
+ * the time the function returns.
+ */
+ RCDisableI2OInterrupts(pDpa->id);
+ RCShutdownLANCard(pDpa->id,0,0,0);
+ printk("rc: scheduling timer...\n");
+ init_timer(&pDpa->timer);
+ pDpa->timer.expires = RUN_AT((40*HZ)/10); /* 4 sec. */


+ pDpa->timer.data = (unsigned long)dev;
+ pDpa->timer.function = &rc_timer; /* timer handler */
+ add_timer(&pDpa->timer);
+ }

X
X
X
@@ -656,33 +695,33 @@
X static void
X RCreboot_callback(U32 Status, U32 p1, U32 p2, U16 AdapterID)
X {
- PDPA pDpa;
+ PDPA pDpa;


X
- pDpa = PCIAdapters[AdapterID];

+ pDpa = PCIAdapters[AdapterID];

X #ifdef RCDEBUG
- printk("rc: RCreboot: rcv buffers outstanding = %d\n",
- (uint)pDpa->numOutRcvBuffers);
+ printk("rc: RCreboot: rcv buffers outstanding = %d\n",
+ (uint)pDpa->numOutRcvBuffers);
X #endif
- if (pDpa->shutdown)
- {
- printk("rc: skipping reboot sequence -- shutdown already initiated\n");
- return;
- }
- pDpa->reboot = 1;
- /*
- * OK, we reset the adapter and ask it to return all
- * outstanding transmit buffers as well as the posted
- * receive buffers. When the adapter is done returning
- * those buffers, it will call our RCreset_callback()
- * routine. In that routine, we'll call RCShutdownLANCard()
- * to tell the adapter that it's OK to start the reboot and
- * schedule a timer callback routine to execute 3 seconds
- * later; this routine will reinitialize the adapter at that time.
- */
- RCResetLANCard(pDpa->id,

- RC_RESOURCE_RETURN_POSTED_RX_BUCKETS |
- RC_RESOURCE_RETURN_PEND_TX_BUFFERS,0,
- (PFNCALLBACK)RCreset_callback);

+ if (pDpa->shutdown)
+ {
+ printk("rc: skipping reboot sequence -- shutdown already initiated\n");
+ return;
+ }
+ pDpa->reboot = 1;
+ /*
+ * OK, we reset the adapter and ask it to return all
+ * outstanding transmit buffers as well as the posted
+ * receive buffers. When the adapter is done returning
+ * those buffers, it will call our RCreset_callback()
+ * routine. In that routine, we'll call RCShutdownLANCard()
+ * to tell the adapter that it's OK to start the reboot and


SHAR_EOF
true || echo 'restore of patch-2.0.37 failed'
fi

echo 'End of part 15'
echo 'File patch-2.0.37 is continued in part 16'
echo 16 > _shar_seq_.tmp

Thomas...@ciw.uni-karlsruhe.de

unread,
Jun 16, 1999, 3:00:00 AM6/16/99
to
Archive-name: v2.0/patch-2.0.37/part18

#!/bin/sh
# this is part 18 of a 45 - part archive


# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.0.37 continued
if test ! -r _shar_seq_.tmp; then
echo 'Please unpack part 1 first!'
exit 1
fi
(read Scheck

if test "$Scheck" != 18; then


echo Please unpack part "$Scheck" next!
exit 1
else
exit 0
fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.0.37'
else
echo 'x - continuing with patch-2.0.37'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.0.37' &&

+ return -EAGAIN;
+ MOD_INC_USE_COUNT;
+
X /* Deassert reset.
X 486: Set 8 longword cache alignment, 8 longword burst.
X 586: Set 16 longword cache alignment, no burst limit.
@@ -1270,34 +1260,18 @@
X #endif
X outl(0x01A00000 | (x86 <= 4 ? 0x4800 : 0x8000), ioaddr + CSR0);
X if (x86 <= 4)
- printk(KERN_INFO "%s: This is a 386/486 PCI system, setting cache "
- "alignment to %x.\n", dev->name,
- 0x01A00000 | (x86 <= 4 ? 0x4800 : 0x8000));
+ printk(KERN_INFO "%s: This is a 386/486 PCI system, setting cache "
+ "alignment to %x.\n", dev->name,
+ 0x01A00000 | (x86 <= 4 ? 0x4800 : 0x8000));
X #endif
X #else
X outl(0x01A00000 | 0x4800, ioaddr + CSR0);
X #warning Processor architecture undefined!
X #endif
X
-#ifdef SA_SHIRQ
- if (request_irq(dev->irq, &tulip_interrupt, SA_SHIRQ, dev->name, dev)) {
- return -EAGAIN;
- }
-#else
- if (irq2dev_map[dev->irq] != NULL
- || (irq2dev_map[dev->irq] = dev) == NULL
- || dev->irq == 0
- || request_irq(dev->irq, &tulip_interrupt, 0,
- tulip_tbl[tp->chip_id].chip_name)) {


- return -EAGAIN;
- }
-#endif

-
X if (tulip_debug > 1)
X printk(KERN_DEBUG "%s: tulip_open() irq %d.\n", dev->name, dev->irq);
X
- MOD_INC_USE_COUNT;
-
X tulip_init_ring(dev);
X
X /* This is set_rx_mode(), but without starting the transmitter. */
@@ -1327,6 +1301,7 @@
X outl(virt_to_bus(tp->rx_ring), ioaddr + CSR3);
X outl(virt_to_bus(tp->tx_ring), ioaddr + CSR4);
X
+ tp->saved_if_port = dev->if_port;
X if (dev->if_port == 0)
X dev->if_port = tp->default_port;
X if (tp->chip_id == DC21041 && dev->if_port > 4)
@@ -1334,6 +1309,7 @@
X dev->if_port = 4;
X
X /* Allow selecting a default media. */
+ i = 0;
X if (tp->mtable == NULL)
X goto media_picked;
X if (dev->if_port) {
@@ -1362,15 +1338,36 @@
X tp->csr6 = 0;
X tp->cur_index = i;
X if (dev->if_port == 0 && tp->chip_id == DC21142) {
- tp->csr6 = 0x82420200;


- outl(0x0003FFFF, ioaddr + CSR14);
- outl(0x0008, ioaddr + CSR15);
- outl(0x0001, ioaddr + CSR13);
- outl(0x1301, ioaddr + CSR12);

+ if (tp->mii_cnt) {
+ if (tulip_debug > 1)
+ printk(KERN_INFO "%s: Using MII transceiver %d, status "
+ "%4.4x.\n",
+ dev->name, tp->phys[0], mdio_read(dev, tp->phys[0], 1));
+ select_media(dev, 1);


+ outl(0x82020000, ioaddr + CSR6);

+ tp->csr6 = 0x820E0000;
+ dev->if_port = 11;


+ outl(0x0000, ioaddr + CSR13);
+ outl(0x0000, ioaddr + CSR14);

+ outl(0x0008, ioaddr + CSR15);

+ } else {
+ if (tulip_debug > 1)
+ printk(KERN_INFO "%s: Using default 21143 media sense.\n",
+ dev->name);
+ tp->csr6 = 0x82420200;


+ outl(0x0003FFFF, ioaddr + CSR14);
+ outl(0x0008, ioaddr + CSR15);
+ outl(0x0001, ioaddr + CSR13);
+ outl(0x1301, ioaddr + CSR12);

+ }
X } else if (tp->chip_id == LC82C168 && tp->mii_cnt && ! tp->medialock) {
X dev->if_port = 11;
X tp->csr6 = 0x816C0000 | (tp->full_duplex ? 0x0200 : 0);
X outl(0x0001, ioaddr + CSR15);
+ } else if (tp->chip_id == MX98713 && ! tp->medialock) {
+ dev->if_port = 0;
+ tp->csr6 = 0x01a80000 | (tp->full_duplex ? 0x0200 : 0);
+ outl(0x0f370000 | inw(ioaddr + 0x80), ioaddr + 0x80);
X } else
X select_media(dev, 1);
X
@@ -1435,7 +1432,7 @@
X
X dev->if_port = p[0] & 15;
X if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: 21142 non-MII %s transceiver control %4.4x/%4.4x.\n",
+ printk(KERN_DEBUG "%s: 21143 non-MII %s transceiver control %4.4x/%4.4x.\n",
X dev->name, medianame[dev->if_port], setup[0], setup[1]);
X if (p[0] & 0x40) { /* SIA (CSR13-15) setup values are provided. */
X outl(0, ioaddr + CSR13);
@@ -1793,9 +1790,47 @@
X int new_csr6 = 0;
X
X if (tulip_debug > 1)
- printk(KERN_INFO"%s: 21142 negotiation status %8.8x, %s.\n",
+ printk(KERN_INFO"%s: 21143 negotiation status %8.8x, %s.\n",
X dev->name, csr12, medianame[dev->if_port]);
- if (dev->if_port == 3) {
+ if (media_cap[dev->if_port] & MediaIsMII) {
+ int mii_reg1 = mdio_read(dev, tp->phys[0], 1);


+ int mii_reg5 = mdio_read(dev, tp->phys[0], 5);

+ if (tulip_debug > 1)
+ printk(KERN_INFO "%s: MII status %4.4x, Link partner report "
+ "%4.4x, CSR6 %x.\n",
+ dev->name, mii_reg1, mii_reg5, inl(ioaddr + CSR6));
+ if (mii_reg1 != 0xffff && (mii_reg1 & 0x0004) == 0) {
+ int new_reg1 = mdio_read(dev, tp->phys[0], 1);
+ if ((new_reg1 & 0x0004) == 0) {
+ printk(KERN_INFO "%s: No link beat on the MII interface,"
+ " status then %4.4x now %4.4x.\n",
+ dev->name, mii_reg1, new_reg1);
+ }
+ if (tp->full_duplex_lock)
+ ;
+ else {
+ int negotiated = mii_reg5 & tp->advertising[0];
+ int duplex = ((negotiated & 0x0100) != 0
+ || (negotiated & 0x00C0) == 0x0040);
+ /* 100baseTx-FD or 10T-FD, but not 100-HD */


+ if (tp->full_duplex != duplex) {
+ tp->full_duplex = duplex;

+ if (tp->full_duplex)
+ tp->csr6 |= 0x0200;
+ else
+ tp->csr6 &= ~0x0200;
+ outl(tp->csr6 | 0x0002, ioaddr + CSR6);
+ outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+ if (tulip_debug > 0)


+ printk(KERN_INFO "%s: Setting %s-duplex based on MII"

+ " Xcvr #%d parter capability of %4.4x.\n",
+ dev->name, tp->full_duplex ? "full" : "half",
+ tp->phys[0], mii_reg5);
+ }


+ }
+ next_tick = 60*HZ;

+ }
+ } else if (dev->if_port == 3) {
X if (csr12 & 2) { /* No 100mbps link beat, revert to 10mbps. */
X new_csr6 = 0x82420200;
X outl(new_csr6, ioaddr + CSR6);
@@ -1808,7 +1843,7 @@
X } else if ((csr12 & 0x7000) != 0x5000) {
X /* Negotiation failed. Search media types. */
X if (tulip_debug > 1)
- printk(KERN_INFO"%s: 21142 negotiation failed, status %8.8x.\n",
+ printk(KERN_INFO"%s: 21143 negotiation failed, status %8.8x.\n",
X dev->name, csr12);
X if (!(csr12 & 4)) { /* 10mbps link beat good. */
X new_csr6 = 0x82420000;
@@ -1834,7 +1869,7 @@
X outl(1, ioaddr + CSR13);
X }
X if (tulip_debug > 1)
- printk(KERN_INFO"%s: Testing new 21142 media %s.\n",
+ printk(KERN_INFO"%s: Testing new 21143 media %s.\n",
X dev->name, medianame[dev->if_port]);
X if (new_csr6 != (tp->csr6 & ~0x00D5)) {
X tp->csr6 &= 0x00D5;
@@ -1855,7 +1890,7 @@
X int csr12 = inl(ioaddr + CSR12);
X
X if (tulip_debug > 1)
- printk(KERN_INFO"%s: 21142 link status interrupt %8.8x, CSR5 %x.\n",
+ printk(KERN_INFO"%s: 21143 link status interrupt %8.8x, CSR5 %x.\n",
X dev->name, csr12, inl(ioaddr + CSR5));
X
X if ((csr12 & 0x7000) == 0x5000) {
@@ -1873,20 +1908,20 @@
X } /* Else 10baseT-FD is handled automatically. */
X } else if (dev->if_port == 3) {
X if (!(csr12 & 2))
- printk(KERN_INFO"%s: 21142 100baseTx link beat good.\n",
+ printk(KERN_INFO"%s: 21143 100baseTx link beat good.\n",
X dev->name);
X else
X dev->if_port = 0;
X } else if (dev->if_port == 0) {
X if (!(csr12 & 4))
- printk(KERN_INFO"%s: 21142 10baseT link beat good.\n",
+ printk(KERN_INFO"%s: 21143 10baseT link beat good.\n",
X dev->name);
X } else if (!(csr12 & 4)) { /* 10mbps link beat good. */
- printk(KERN_INFO"%s: 21142 10mpbs sensed media.\n",
+ printk(KERN_INFO"%s: 21143 10mpbs sensed media.\n",
X dev->name);
X dev->if_port = 0;
X } else { /* 100mbps link beat good. */
- printk(KERN_INFO"%s: 21142 100baseTx sensed media.\n",
+ printk(KERN_INFO"%s: 21143 100baseTx sensed media.\n",
X dev->name);
X dev->if_port = 3;
X tp->csr6 = 0x83860000;
@@ -1896,7 +1931,6 @@
X outl(tp->csr6 | 0x2002, ioaddr + CSR6);
X }
X }
-
X

X static void mxic_timer(unsigned long data)

X {
@@ -2002,96 +2036,88 @@
X
X static void tulip_tx_timeout(struct device *dev)
X {
- struct tulip_private *tp = (struct tulip_private *)dev->priv;
- long ioaddr = dev->base_addr;
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;


+ long ioaddr = dev->base_addr;
X

- if (media_cap[dev->if_port] & MediaIsMII) {
- /* Do nothing -- the media monitor should handle this. */
- if (tulip_debug > 1)
- printk(KERN_WARNING "%s: Transmit timeout using MII device.\n",
- dev->name);


- dev->trans_start = jiffies;

- return;
- } else if (tp->chip_id == DC21040) {
- if (inl(ioaddr + CSR12) & 0x0002) {
- printk(KERN_INFO "%s: transmit timed out, switching to %s media.\n",
- dev->name, dev->if_port ? "10baseT" : "AUI");
- dev->if_port ^= 1;
- outl(dev->if_port ? 0x0000000C : 0x00000004, ioaddr + CSR13);


- }
- dev->trans_start = jiffies;

- return;
- } else if (tp->chip_id == DC21041) {
- u32 csr12 = inl(ioaddr + CSR12);
+ if (media_cap[dev->if_port] & MediaIsMII) {
+ /* Do nothing -- the media monitor should handle this. */
+ if (tulip_debug > 1)
+ printk(KERN_WARNING "%s: Transmit timeout using MII device.\n",
+ dev->name);
+ } else if (tp->chip_id == DC21040) {
+ if ( !tp->medialock && inl(ioaddr + CSR12) & 0x0002) {
+ dev->if_port ^= 1;
+ printk(KERN_INFO "%s: transmit timed out, switching to "
+ "%s10baseT media.\n",
+ dev->name, dev->if_port ? "non" : "");
+ outl(dev->if_port ? 0x0000000C : 0x00000004, ioaddr + CSR13);


+ }
+ dev->trans_start = jiffies;

+ return;
+ } else if (tp->chip_id == DC21041) {
+ int csr12 = inl(ioaddr + CSR12);
+
+ printk(KERN_WARNING "%s: 21041 transmit timed out, status %8.8x, "
+ "CSR12 %8.8x, CSR13 %8.8x, CSR14 %8.8x, resetting...\n",
+ dev->name, inl(ioaddr + CSR5), csr12,
+ inl(ioaddr + CSR13), inl(ioaddr + CSR14));
+ tp->mediasense = 1;
+ if ( ! tp->medialock) {
+ if (dev->if_port == 1 || dev->if_port == 2)
+ if (csr12 & 0x0004) {
+ dev->if_port = 2 - dev->if_port;
+ } else
+ dev->if_port = 0;
+ else
+ dev->if_port = 1;
+ select_media(dev, 0);
+ }
+ } else if (tp->chip_id == DC21140 || tp->chip_id == DC21142
+ || tp->chip_id == MX98713) {
+ printk(KERN_WARNING "%s: 21140 transmit timed out, status %8.8x, "
+ "SIA %8.8x %8.8x %8.8x %8.8x, resetting...\n",
+ dev->name, inl(ioaddr + CSR5), inl(ioaddr + CSR12),
+ inl(ioaddr + CSR13), inl(ioaddr + CSR14), inl(ioaddr + CSR15));
+ if ( ! tp->medialock && tp->mtable) {
+ if (--tp->cur_index < 0) {
+ /* We start again, but should instead look for default. */
+ tp->cur_index = tp->mtable->leafcount - 1;
+ }
+ select_media(dev, 0);
+ printk(KERN_WARNING "%s: transmit timed out, switching to %s "
+ "media.\n", dev->name, medianame[dev->if_port]);
+ }
+ } else {
+ printk(KERN_WARNING "%s: Transmit timed out, status %8.8x, CSR12 "
+ "%8.8x, resetting...\n",
+ dev->name, inl(ioaddr + CSR5), inl(ioaddr + CSR12));
+ dev->if_port = 0;
+ }
+
+#ifdef way_too_many_messages
+ printk(" Rx ring %8.8x: ", (int)tp->rx_ring);
+ for (i = 0; i < RX_RING_SIZE; i++)
+ printk(" %8.8x", (unsigned int)tp->rx_ring[i].status);
+ printk("\n Tx ring %8.8x: ", (int)tp->tx_ring);
+ for (i = 0; i < TX_RING_SIZE; i++)
+ printk(" %8.8x", (unsigned int)tp->tx_ring[i].status);
+ printk("\n");
+#endif
+
+ /* Stop and restart the chip's Tx processes . */
+ outl(tp->csr6 | 0x0002, ioaddr + CSR6);
+ outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+ /* Trigger an immediate transmit demand. */
+ outl(0, ioaddr + CSR1);
X
- printk(KERN_WARNING "%s: 21041 transmit timed out, status %8.8x, CSR12 %8.8x,"
- " CSR13 %8.8x, CSR14 %8.8x, resetting...\n",
- dev->name, inl(ioaddr + CSR5), csr12,
- inl(ioaddr + CSR13), inl(ioaddr + CSR14));
- tp->mediasense = 1;
- if (dev->if_port == 1 || dev->if_port == 2)
- if (csr12 & 0x0004) {
- dev->if_port = 2 - dev->if_port;
- } else
- dev->if_port = 0;
- else
- dev->if_port = 1;
- select_media(dev, 0);
- tp->stats.tx_errors++;


X dev->trans_start = jiffies;

+ tp->stats.tx_errors++;
X return;
- } else if (tp->chip_id == DC21140 || tp->chip_id == DC21142
- || tp->chip_id == MX98713) {
- /* Stop the transmit process. */
- outl(tp->csr6 | 0x0002, ioaddr + CSR6);
- printk(KERN_WARNING "%s: 21140 transmit timed out, status %8.8x, "
- "SIA %8.8x %8.8x %8.8x %8.8x, resetting...\n",
- dev->name, inl(ioaddr + CSR5), inl(ioaddr + CSR12),
- inl(ioaddr + CSR13), inl(ioaddr + CSR14), inl(ioaddr + CSR15));
- if (tp->mtable) {
- if (--tp->cur_index < 0) {
- /* We start again, but should instead look for default. */
- tp->cur_index = tp->mtable->leafcount - 1;
- }
- select_media(dev, 0);
- printk(KERN_WARNING "%s: transmit timed out, switching to %s media.\n",
- dev->name, dev->if_port ? "100baseTx" : "10baseT");
- }
- outl(tp->csr6 | 0x2002, ioaddr + CSR6);
- tp->stats.tx_errors++;


- dev->trans_start = jiffies;

- return;
- } else
- printk(KERN_WARNING "%s: transmit timed out, status %8.8x, CSR12 %8.8x,"
- " resetting...\n",
- dev->name, inl(ioaddr + CSR5), inl(ioaddr + CSR12));
-#ifdef way_too_many_messages
- printk(" Rx ring %8.8x: ", (int)tp->rx_ring);
- for (i = 0; i < RX_RING_SIZE; i++)
- printk(" %8.8x", (unsigned int)tp->rx_ring[i].status);
- printk("\n Tx ring %8.8x: ", (int)tp->tx_ring);
- for (i = 0; i < TX_RING_SIZE; i++)
- printk(" %8.8x", (unsigned int)tp->tx_ring[i].status);
- printk("\n");
-#endif
-
- /* Perhaps we should reinitialize the hardware here. */
- dev->if_port = 0;
- /* Stop and restart the chip's Tx processes . */
- outl(tp->csr6 | 0x0002, ioaddr + CSR6);
- outl(tp->csr6 | 0x2002, ioaddr + CSR6);
- /* Trigger an immediate transmit demand. */
- outl(0, ioaddr + CSR1);


-
- dev->trans_start = jiffies;

- tp->stats.tx_errors++;
- return;
X }


X
X
X /* Initialize the Rx and Tx rings, along with various 'dev' bits. */

-static void
-tulip_init_ring(struct device *dev)
+static void tulip_init_ring(struct device *dev)


X {
X struct tulip_private *tp = (struct tulip_private *)dev->priv;

X int i;
@@ -2108,7 +2134,7 @@
X dev_alloc_skb() provides 16 byte alignment. But do *not*
X use skb_reserve() to align the IP header! */
X struct sk_buff *skb;
- skb = DEV_ALLOC_SKB(PKT_BUF_SZ);
+ skb = dev_alloc_skb(PKT_BUF_SZ);
X tp->rx_skbuff[i] = skb;


X if (skb == NULL)

X break; /* Bad news! */
@@ -2122,7 +2148,7 @@
X tp->rx_ring[i].buffer2 = virt_to_bus(&tp->rx_ring[i+1]);
X }
X /* Mark the last entry as wrapping the ring. */
- tp->rx_ring[i-1].length = PKT_BUF_SZ | 0x02000000;
+ tp->rx_ring[i-1].length = PKT_BUF_SZ | DESC_RING_WRAP;
X tp->rx_ring[i-1].buffer2 = virt_to_bus(&tp->rx_ring[0]);
X
X /* The Tx buffer descriptor is filled in as needed, but we
@@ -2175,7 +2201,7 @@


X tp->tx_full = 1;
X }

X if (entry == TX_RING_SIZE-1)
- flag |= 0xe2000000;
+ flag |= 0xe0000000 | DESC_RING_WRAP;
X
X tp->tx_ring[entry].length = skb->len | flag;
X tp->tx_ring[entry].status = 0x80000000; /* Pass ownership to the chip. */
@@ -2190,39 +2216,28 @@
X
X /* The interrupt handler does all of the Rx thread work and cleans up
X after the Tx thread. */


-static void tulip_interrupt IRQ(int irq, void *dev_instance, struct pt_regs *regs)
+static void tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs)

X {
-#ifdef SA_SHIRQ /* Use the now-standard shared IRQ implementation. */

X struct device *dev = (struct device *)dev_instance;

-#else
- struct device *dev = (struct device *)(irq2dev_map[irq]);
-#endif
-

- struct tulip_private *tp;
- long ioaddr;
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;


+ long ioaddr = dev->base_addr;

X int csr5, work_budget = max_interrupt_work;


X
- if (dev == NULL) {

- printk (KERN_ERR" tulip_interrupt(): irq %d for unknown device.\n",
- irq);
- return;
- }


-
- ioaddr = dev->base_addr;

- tp = (struct tulip_private *)dev->priv;
- if (test_and_set_bit(0, (void*)&tp->interrupt)) {
-#ifdef SMP_CHECK
+#if defined(__i386__) && defined(SMP_CHECK) /* && defined(__SMP__) */


+ if (test_and_set_bit(0, (void*)&dev->interrupt)) {

X printk(KERN_ERR "%s: Re-entering the interrupt handler with proc %d,"
X " proc %d already handling.\n", dev->name,
X tp->smp_proc_id, hard_smp_processor_id());


+ dev->interrupt = 0;

+ return;
+ } else
+ tp->smp_proc_id = hard_smp_processor_id();
X #else


+ if (dev->interrupt) {
X printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name);

-#endif


X return;
X }
X dev->interrupt = 1;

-#ifdef SMP_CHECK
- tp->smp_proc_id = hard_smp_processor_id();
X #endif
X
X do {
@@ -2283,11 +2298,7 @@


X }
X
X /* Free the original skb. */

-#if (LINUX_VERSION_CODE > 0x20155)
- dev_kfree_skb(tp->tx_skbuff[entry]);
-#else


- dev_kfree_skb(tp->tx_skbuff[entry], FREE_WRITE);

-#endif


+ dev_free_skb(tp->tx_skbuff[entry]);
X tp->tx_skbuff[entry] = 0;
X }
X

@@ -2309,7 +2320,7 @@
X
X tp->dirty_tx = dirty_tx;
X if (csr5 & TxDied) {
- if (tulip_debug > 1)
+ if (tulip_debug)
X printk(KERN_WARNING "%s: The transmitter stopped!"
X " CSR5 is %x, CSR6 %x.\n",
X dev->name, csr5, inl(ioaddr + CSR6));
@@ -2320,6 +2331,8 @@
X
X /* Log errors. */
X if (csr5 & AbnormalIntr) { /* Abnormal error summary bit. */
+ if (csr5 == 0xffffffff)
+ break;
X if (csr5 & TxJabber) tp->stats.tx_errors++;
X if (csr5 & TxFIFOUnderflow) {
X if ((tp->csr6 & 0xC000) != 0xC000)
@@ -2342,7 +2355,7 @@
X if (csr5 & (TPLnkPass | TPLnkFail | 0x08000000)
X && tp->chip_id == DC21142) {
X if (tulip_debug > 1)
- printk(KERN_INFO"%s: 21142 link change, CSR5 = %8.8x.\n",
+ printk(KERN_INFO"%s: 21143 link change, CSR5 = %8.8x.\n",
X dev->name, csr5);
X t21142_lnk_change(dev);
X }


@@ -2351,7 +2364,7 @@
X }

X if (--work_budget < 0) {
X if (tulip_debug > 1)
- printk(KERN_WARNING "%s: Too much work at interrupt, "
+ printk(KERN_WARNING "%s: Too much work during an interrupt, "
X "csr5=0x%8.8x.\n", dev->name, csr5);
X /* Acknowledge all interrupt sources. */
X outl(0x8001ffff, ioaddr + CSR5);
@@ -2367,8 +2380,11 @@
X printk(KERN_DEBUG "%s: exiting interrupt, csr5=%#4.4x.\n",
X dev->name, inl(ioaddr + CSR5));


X
+#if defined(__i386__)
+ clear_bit(0, (void*)&dev->interrupt);
+#else
X dev->interrupt = 0;

- clear_bit(0, (void*)&tp->interrupt);


+#endif
X return;
X }
X

@@ -2389,69 +2405,67 @@
X
X if (--rx_work_limit < 0)
X break;
- if ((status & 0x0300) != 0x0300) {
- if ((status & 0xffff) != 0x7fff) { /* Ingore earlier buffers. */
- if (tulip_debug > 1)
- printk(KERN_WARNING "%s: Oversized Ethernet frame spanned "
- "multiple buffers, status %8.8x!\n",
+ if ((status & 0x38008300) != 0x0300) {
+ if ((status & 0x38000300) != 0x0300) {
+ /* Ingore earlier buffers. */
+ if ((status & 0xffff) != 0x7fff) {
+ if (tulip_debug > 1)
+ printk(KERN_WARNING "%s: Oversized Ethernet frame "
+ "spanned multiple buffers, status %8.8x!\n",
+ dev->name, status);
+ tp->stats.rx_length_errors++;
+ }
+ } else if (status & 0x8000) {
+ /* There was a fatal error. */
+ if (tulip_debug > 2)
+ printk(KERN_DEBUG "%s: Receive error, Rx status %8.8x.\n",
X dev->name, status);
- tp->stats.rx_length_errors++;
+ tp->stats.rx_errors++; /* end of a packet.*/
+ if (status & 0x0890) tp->stats.rx_length_errors++;
+ if (status & 0x0004) tp->stats.rx_frame_errors++;
+ if (status & 0x0002) tp->stats.rx_crc_errors++;
+ if (status & 0x0001) tp->stats.rx_fifo_errors++;
X }
- } else if (status & 0x8000) {
- /* There was a fatal error. */
- if (tulip_debug > 2)
- printk(KERN_DEBUG "%s: Receive error, Rx status %8.8x.\n",
- dev->name, status);
- tp->stats.rx_errors++; /* end of a packet.*/
- if (status & 0x0890) tp->stats.rx_length_errors++;
- if (status & 0x0004) tp->stats.rx_frame_errors++;
- if (status & 0x0002) tp->stats.rx_crc_errors++;
- if (status & 0x0001) tp->stats.rx_fifo_errors++;
X } else {
X /* Omit the four octet CRC from the length. */
- short pkt_len = ((status >> 16) & 0x7FF) - 4;
+ short pkt_len = ((status >> 16) & 0x7ff) - 4;


X struct sk_buff *skb;
X

- /* Check if the packet is long enough to just accept without
- copying to a properly sized skbuff. */
+#ifndef final_version
+ if (pkt_len > 1518) {
+ printk("%s: Bogus packet size of %d (%#x).\n",
+ dev->name, pkt_len, pkt_len);
+ pkt_len = 1518;
+ tp->stats.rx_length_errors++;
+ }
+#endif
+ /* Check if the packet is long enough to accept without copying
+ to a minimally-sized skbuff. */
X if (pkt_len < rx_copybreak
- && (skb = DEV_ALLOC_SKB(pkt_len+2)) != NULL) {
+ && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {


X skb->dev = dev;

X skb_reserve(skb, 2); /* 16 byte align the IP header */
-#if LINUX_VERSION_CODE < 0x10300
- memcpy(skb->data, tp->rx_ring[entry].buffer1, pkt_len);
-#elif LINUX_VERSION_CODE < 0x20200 || defined(__alpha__)
- memcpy(skb_put(skb, pkt_len),
- bus_to_virt(tp->rx_ring[entry].buffer1), pkt_len);
-#else
-#warning Code untested
+#if ! defined(__alpha__)
X eth_copy_and_sum(skb, bus_to_virt(tp->rx_ring[entry].buffer1),
X pkt_len, 0);
X skb_put(skb, pkt_len);
+#else
+ memcpy(skb_put(skb, pkt_len),
+ bus_to_virt(tp->rx_ring[entry].buffer1), pkt_len);
X #endif
X work_done++;
X } else { /* Pass up the skb already on the Rx ring. */
- skb = tp->rx_skbuff[entry];
+ char *temp = skb_put(skb = tp->rx_skbuff[entry], pkt_len);
X tp->rx_skbuff[entry] = NULL;
X #ifndef final_version
- {
- void *temp = skb_put(skb, pkt_len);
- if (bus_to_virt(tp->rx_ring[entry].buffer1) != temp)
- printk(KERN_ERR "%s: Internal consistency error! The "
- "skbuff addresses do not match in tulip_rx:"
- " %p vs. %p / %p.\n", dev->name,
- bus_to_virt(tp->rx_ring[entry].buffer1),
- skb->head, temp);
- }
-#else
- skb_put(skb, pkt_len);
+ if (bus_to_virt(tp->rx_ring[entry].buffer1) != temp)
+ printk(KERN_ERR "%s: Internal fault: The skbuff addresses "
+ "do not match in tulip_rx: %p vs. %p / %p.\n",
+ dev->name, bus_to_virt(tp->rx_ring[entry].buffer1),
+ skb->head, temp);
X #endif
X }
-#if LINUX_VERSION_CODE > 0x10300


X skb->protocol = eth_type_trans(skb, dev);

-#else
- skb->len = pkt_len;
-#endif
X netif_rx(skb);
X dev->last_rx = jiffies;

X tp->stats.rx_packets++;
@@ -2467,15 +2481,11 @@
X entry = tp->dirty_rx % RX_RING_SIZE;
X if (tp->rx_skbuff[entry] == NULL) {
X struct sk_buff *skb;
- skb = tp->rx_skbuff[entry] = DEV_ALLOC_SKB(PKT_BUF_SZ);
+ skb = tp->rx_skbuff[entry] = dev_alloc_skb(PKT_BUF_SZ);


X if (skb == NULL)

X break;


X skb->dev = dev; /* Mark as being used by this device. */

-#if LINUX_VERSION_CODE > 0x10300
X tp->rx_ring[entry].buffer1 = virt_to_bus(skb->tail);
-#else
- tp->rx_ring[entry].buffer1 = virt_to_bus(skb->data);
-#endif
X work_done++;
X }
X tp->rx_ring[entry].status = 0x80000000;
@@ -2506,16 +2516,14 @@
X if (tp->chip_id == DC21040)
X outl(0x00000004, ioaddr + CSR13);
X
- tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
+ if (inl(ioaddr + CSR6) != 0xffffffff)
+ tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
X
X del_timer(&tp->timer);


X
-#ifdef SA_SHIRQ
X free_irq(dev->irq, dev);
-#else
- free_irq(dev->irq);
- irq2dev_map[dev->irq] = 0;
-#endif

+
+ dev->if_port = tp->saved_if_port;
X
X /* Free all the skbuffs in the Rx queue. */
X for (i = 0; i < RX_RING_SIZE; i++) {
@@ -2528,20 +2536,12 @@
X #if LINUX_VERSION_CODE < 0x20100
X skb->free = 1;
X #endif
-#if (LINUX_VERSION_CODE > 0x20155)
- dev_kfree_skb(skb);
-#else
- dev_kfree_skb(skb, FREE_WRITE);
-#endif
+ dev_free_skb(skb);
X }
X }
X for (i = 0; i < TX_RING_SIZE; i++) {


X if (tp->tx_skbuff[i])

-#if (LINUX_VERSION_CODE > 0x20155)
- dev_kfree_skb(tp->tx_skbuff[i]);
-#else


- dev_kfree_skb(tp->tx_skbuff[i], FREE_WRITE);

-#endif


+ dev_free_skb(tp->tx_skbuff[i]);
X tp->tx_skbuff[i] = 0;
X }
X

@@ -2551,8 +2551,7 @@


X return 0;
X }
X

-static struct enet_statistics *
-tulip_get_stats(struct device *dev)


+static struct net_device_stats *tulip_get_stats(struct device *dev)

X {
X struct tulip_private *tp = (struct tulip_private *)dev->priv;
X long ioaddr = dev->base_addr;

@@ -2575,7 +2574,7 @@
X
X switch(cmd) {
X case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */
- if (tp->mtable && tp->mtable->has_mii)
+ if (tp->mii_cnt)


X data[0] = phy;

X else if (tp->chip_id == DC21142)
X data[0] = 32;
@@ -2595,11 +2594,11 @@
X + (csr12&0x06 ? 0x04 : 0);
X break;
X case 4: {
- int csr14 = inl(ioaddr + CSR14);
- data[3] = ((csr14>>9)&0x0380) + ((csr14>>1)&0x20) + 1;
+ data[3] = ((csr14>>9)&0x0380) +
+ ((inl(ioaddr + CSR6)>>3)&0x0040) +((csr14>>1)&0x20) + 1;
X break;
X }
- case 5: data[3] = inl(ioaddr + CSR12) >> 16; break;
+ case 5: data[3] = csr12 >> 16; break;
X default: data[3] = 0; break;
X }
X } else {
@@ -2613,6 +2612,8 @@
X if (!suser())
X return -EPERM;
X if (data[0] == 32) { /* 21142 pseudo-MII */
+ if (data[1] == 5)
+ tp->advertising[tp->mii_cnt] = data[2];
X } else {
X save_flags(flags);
X cli();
@@ -2654,11 +2655,7 @@
X return crc;
X }
X

-#ifdef NEW_MULTICAST
X static void set_rx_mode(struct device *dev)
-#else
-static void set_rx_mode(struct device *dev, int num_addrs, void *addrs)
-#endif
X {

X long ioaddr = dev->base_addr;
X int csr6 = inl(ioaddr + CSR6) & ~0x00D5;
@@ -2682,38 +2679,38 @@
X int i;
X
X if (dev->mc_count > 14) { /* Must use a multicast hash table. */
- u16 hash_table[32];
- memset(hash_table, 0, sizeof(hash_table));
- /* This should work on big-endian machines as well. */
- for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
- i++, mclist = mclist->next)
- set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x1ff,
- hash_table);
- /* Copy the hash table to the setup frame.
- NOTE that only the LOW SHORTWORD of setup_frame[] is valid! */
- for (i = 0; i < 32; i++)
- *setup_frm++ = hash_table[i];
- setup_frm += 7;
- tx_flags = 0x08400000 | 192;
- /* Too clever: i > 15 for fall-though. */
+ u16 hash_table[32];
+ memset(hash_table, 0, sizeof(hash_table));
+ /* This should work on big-endian machines as well. */
+ for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
+ i++, mclist = mclist->next)
+ set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x1ff,
+ hash_table);
+ /* Copy the hash table to the setup frame.
+ NOTE that only the LOW SHORTWORD of setup_frame[] is valid! */
+ for (i = 0; i < 32; i++)
+ *setup_frm++ = hash_table[i];
+ setup_frm += 7;
+ tx_flags = 0x08400000 | 192;
+ /* Too clever: i > 15 for fall-though. */
X } else {
- /* We have <= 15 addresses so we can use the wonderful
- 16 address perfect filtering of the Tulip. */
- for (i = 0, mclist = dev->mc_list; i < dev->mc_count;
- i++, mclist = mclist->next) {
- /* Note that only the low shortword of setup_frame[] is valid!
- This code may require tweaking for non-x86 architectures! */
- eaddrs = (u16 *)mclist->dmi_addr;
- *setup_frm++ = *eaddrs++;
- *setup_frm++ = *eaddrs++;
- *setup_frm++ = *eaddrs++;
- }
- /* Fill the rest of the table with our physical address.
- Once again, only the low shortword or setup_frame[] is valid! */
- *setup_frm++ = 0xffff;
- *setup_frm++ = 0xffff;
- *setup_frm++ = 0xffff;
- tx_flags = 0x08000000 | 192;
+ /* We have <= 15 addresses so we can use the wonderful
+ 16 address perfect filtering of the Tulip. */
+ for (i = 0, mclist = dev->mc_list; i < dev->mc_count;
+ i++, mclist = mclist->next) {
+ /* Note that only the low shortword of setup_frame[] is valid!
+ This code may require tweaking for non-x86 architectures! */
+ eaddrs = (u16 *)mclist->dmi_addr;
+ *setup_frm++ = *eaddrs++;
+ *setup_frm++ = *eaddrs++;
+ *setup_frm++ = *eaddrs++;
+ }
+ /* Fill the rest of the table with our physical address.
+ Once again, only the low shortword or setup_frame[] is valid! */
+ *setup_frm++ = 0xffff;
+ *setup_frm++ = 0xffff;
+ *setup_frm++ = 0xffff;
+ tx_flags = 0x08000000 | 192;
X }
X eaddrs = (u16 *)dev->dev_addr;
X do {
@@ -2727,7 +2724,7 @@
X } else {
X unsigned long flags;
X unsigned int entry;
-
+
X save_flags(flags); cli();
X entry = tp->cur_tx++ % TX_RING_SIZE;
X
@@ -2735,7 +2732,7 @@
X /* Avoid a chip errata by prefixing a dummy entry. */


X tp->tx_skbuff[entry] = 0;

X tp->tx_ring[entry].length =
- (entry == TX_RING_SIZE-1) ? 0x02000000 : 0;
+ (entry == TX_RING_SIZE-1) ? DESC_RING_WRAP : 0;
X tp->tx_ring[entry].buffer1 = 0;
X tp->tx_ring[entry].status = 0x80000000;
X entry = tp->cur_tx++ % TX_RING_SIZE;
@@ -2744,7 +2741,7 @@


X tp->tx_skbuff[entry] = 0;

X /* Put the setup frame on the Tx list. */
X if (entry == TX_RING_SIZE-1)
- tx_flags |= 0x02000000; /* Wrap ring. */
+ tx_flags |= DESC_RING_WRAP; /* Wrap ring. */
X tp->tx_ring[entry].length = tx_flags;
X tp->tx_ring[entry].buffer1 = virt_to_bus(tp->setup_frame);
X tp->tx_ring[entry].status = 0x80000000;
@@ -2766,18 +2763,18 @@
X
X static dev_node_t *tulip_attach(dev_locator_t *loc)
X {
+ struct device *dev;
X u16 dev_id;
X u32 io;
- u8 bus, devfn;
- struct device *dev;
+ u8 bus, devfn, irq;


X
X if (loc->bus != LOC_PCI) return NULL;
X bus = loc->b.pci.bus; devfn = loc->b.pci.devfn;

X printk(KERN_INFO "tulip_attach(bus %d, function %d)\n", bus, devfn);


X pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, &io);

X pcibios_read_config_word(bus, devfn, PCI_DEVICE_ID, &dev_id);
- io &= ~3;
- dev = tulip_probe1(bus, devfn, NULL, DC21142, -1);
+ pcibios_read_config_byte(bus, devfn, PCI_INTERRUPT_LINE, &irq);
+ dev = tulip_probe1(bus, devfn, NULL, io & ~3, irq, DC21142, -1);


X if (dev) {
X dev_node_t *node = kmalloc(sizeof(dev_node_t), GFP_KERNEL);
X strcpy(node->dev_name, dev->name);

@@ -2789,6 +2786,37 @@
X return NULL;
X }
X
+static void tulip_suspend(dev_node_t *node)
+{
+ struct device **devp, **next;
+ printk(KERN_INFO "tulip_suspend(%s)\n", node->dev_name);
+ for (devp = &root_tulip_dev; *devp; devp = next) {
+ next = &((struct tulip_private *)(*devp)->priv)->next_module;
+ if (strcmp((*devp)->name, node->dev_name) == 0) break;
+ }
+ if (*devp) {
+ struct tulip_private *tp = (struct tulip_private *)(*devp)->priv;
+ tulip_close(*devp);
+ /* Put the chip into sleep mode. */
+ pcibios_write_config_dword(tp->pci_bus,tp->pci_devfn, 0x40,0x80000000);
+ }
+}
+
+static void tulip_resume(dev_node_t *node)
+{
+ struct device **devp, **next;
+ printk(KERN_INFO "tulip_resume(%s)\n", node->dev_name);
+ for (devp = &root_tulip_dev; *devp; devp = next) {
+ next = &((struct tulip_private *)(*devp)->priv)->next_module;
+ if (strcmp((*devp)->name, node->dev_name) == 0) break;
+ }
+ if (*devp) {
+ struct tulip_private *tp = (struct tulip_private *)(*devp)->priv;
+ pcibios_write_config_dword(tp->pci_bus, tp->pci_devfn, 0x40, 0x0000);
+ tulip_open(*devp);
+ }
+}
+
X static void tulip_detach(dev_node_t *node)
X {
X struct device **devp, **next;
@@ -2807,34 +2835,17 @@
X }
X
X struct driver_operations tulip_ops = {
- "tulip_cb", tulip_attach, NULL, NULL, tulip_detach
+ "tulip_cb", tulip_attach, tulip_suspend, tulip_resume, tulip_detach


X };
X
X #endif /* Cardbus support */

X
X
X #ifdef MODULE

-#if LINUX_VERSION_CODE > 0x20118
-MODULE_AUTHOR("Donald Becker <bec...@cesdis.gsfc.nasa.gov>");
-MODULE_DESCRIPTION("Digital 21*4* Tulip ethernet driver");
-MODULE_PARM(debug, "i");
-MODULE_PARM(max_interrupt_work, "i");
-MODULE_PARM(reverse_probe, "i");
-MODULE_PARM(rx_copybreak, "i");
-MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
-MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
-#endif


-
-/* An additional parameter that may be passed in... */
-static int debug = -1;
-
-int
-init_module(void)
+int init_module(void)
X {

- if (debug >= 0)

- tulip_debug = debug;
-
X #ifdef CARDBUS
+ reverse_probe = 0; /* Not used. */
X register_driver(&tulip_ops);


X return 0;
X #else

@@ -2842,8 +2853,7 @@
X #endif
X }
X

-void
-cleanup_module(void)
+void cleanup_module(void)
X {
X struct device *next_dev;
X

@@ -2853,9 +2863,11 @@


X
X /* No need to check MOD_IN_USE, as sys_delete_module() checks. */

X while (root_tulip_dev) {
- next_dev = ((struct tulip_private *)root_tulip_dev->priv)->next_module;
+ struct tulip_private *tp = (struct tulip_private *)root_tulip_dev->priv;


+ next_dev = tp->next_module;

X unregister_netdev(root_tulip_dev);
- release_region(root_tulip_dev->base_addr, TULIP_TOTAL_SIZE);
+ release_region(root_tulip_dev->base_addr,
+ tulip_tbl[tp->chip_id].io_size);
X kfree(root_tulip_dev);
X root_tulip_dev = next_dev;
X }
@@ -2867,6 +2879,7 @@
X * Local variables:
X * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c tulip.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
X * compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c tulip.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
+ * cardbus-compile-command: "gcc -DCARDBUS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c tulip.c -o tulip_cb.o -I/usr/src/pcmcia-cs-3.0.5/include/"


X * c-indent-level: 4
X * c-basic-offset: 4
X * tab-width: 4

diff -u --recursive --new-file v2.0.36/linux/drivers/net/wavelan.c linux/drivers/net/wavelan.c
--- v2.0.36/linux/drivers/net/wavelan.c Sun Nov 15 21:51:46 1998
+++ linux/drivers/net/wavelan.c Sun Jun 13 10:21:02 1999
@@ -290,24 +290,26 @@
X wv_16_on(ioaddr, hacr);
X } /* psa_write */
X
-#ifdef PSA_CRC
+#ifdef SET_PSA_CRC
X /*------------------------------------------------------------------*/
X /*
- * Calculate the PSA CRC (not tested yet)
- * As the WaveLAN drivers don't use the CRC, I won't use it either.
+ * Calculate the PSA CRC
X * Thanks to Valster, Nico <NVAL...@wcnd.nl.lucent.com> for the code
X * NOTE: By specifying a length including the CRC position the
X * returned value should be zero. (i.e. a correct checksum in the PSA)
+ *
+ * The Windows drivers don't use the CRC, but the AP and the PtP tool
+ * depend on it.
X */
-static u_short
-psa_crc(u_short * psa, /* The PSA */
+static inline u_short
+psa_crc(u_char * psa, /* The PSA */
X int size) /* Number of short for CRC */
X {
X int byte_cnt; /* Loop on the PSA */
X u_short crc_bytes = 0; /* Data in the PSA */
X int bit_cnt; /* Loop on the bits of the short */
X
- for(byte_cnt = 0; byte_cnt <= size; byte_cnt++ )
+ for(byte_cnt = 0; byte_cnt < size; byte_cnt++ )
X {
X crc_bytes ^= psa[byte_cnt]; /* Its an xor */
X
@@ -322,7 +324,47 @@
X
X return crc_bytes;
X } /* psa_crc */
-#endif /* PSA_CRC */
+
+/*------------------------------------------------------------------*/
+/*
+ * update the checksum field in the Wavelan's PSA
+ */
+static void
+update_psa_checksum(device * dev,
+ u_long ioaddr,
+ u_short hacr)
+{
+ psa_t psa;
+ u_short crc;
+
+ /* read the parameter storage area */
+ psa_read(ioaddr, hacr, 0, (unsigned char *) &psa, sizeof(psa));
+
+ /* update the checksum */
+ crc = psa_crc((unsigned char *) &psa,
+ sizeof(psa) - sizeof(psa.psa_crc[0]) - sizeof(psa.psa_crc[1])
+ - sizeof(psa.psa_crc_status));
+
+ psa.psa_crc[0] = crc & 0xFF;
+ psa.psa_crc[1] = (crc & 0xFF00) >> 8;
+
+ /* Write it ! */
+ psa_write(ioaddr, hacr, (char *)&psa.psa_crc - (char *)&psa,
+ (unsigned char *)&psa.psa_crc, 2);
+
+#ifdef DEBUG_IOCTL_INFO
+ printk (KERN_DEBUG "%s: update_psa_checksum(): crc = 0x%02x%02x\n",
+ dev->name, psa.psa_crc[0], psa.psa_crc[1]);
+
+ /* Check again (luxury !) */
+ crc = psa_crc ((unsigned char *) &psa,
+ sizeof(psa) - sizeof(psa.psa_crc_status));
+
+ if(crc != 0)
+ printk(KERN_WARNING "%s: update_psa_checksum(): CRC does not agree with PSA data (even after recalculating)\n", dev->name);
+#endif /* DEBUG_IOCTL_INFO */
+} /* update_psa_checksum */
+#endif /* SET_PSA_CRC */
X
X /*------------------------------------------------------------------*/
X /*
@@ -706,21 +748,21 @@
X unsigned short ias_addr;
X
X /* Check mc_config command */
- if(status & AC_SFLD_OK != 0)
+ if((status & AC_SFLD_OK) != 0)
X printk(KERN_INFO "wv_config_complete(): set_multicast_address failed; status = 0x%x\n",
X dev->name, str, status);
X
X /* check ia-config command */
X ias_addr = mcs_addr - sizeof(ac_ias_t);
X obram_read(ioaddr, acoff(ias_addr, ac_status), (unsigned char *)&status, sizeof(status));
- if(status & AC_SFLD_OK != 0)
+ if((status & AC_SFLD_OK) != 0)
X printk(KERN_INFO "wv_config_complete(): set_MAC_address; status = 0x%x\n",
X dev->name, str, status);
X
X /* Check config command */
X cfg_addr = ias_addr - sizeof(ac_cfg_t);
X obram_read(ioaddr, acoff(cfg_addr, ac_status), (unsigned char *)&status, sizeof(status));
- if(status & AC_SFLD_OK != 0)
+ if((status & AC_SFLD_OK) != 0)
X printk(KERN_INFO "wv_config_complete(): configure; status = 0x%x\n",
X dev->name, str, status);
X #endif /* DEBUG_CONFIG_ERROR */
@@ -1898,6 +1940,10 @@
X /* Disable nwid in the mmc (no filtering) */
X mmc_out(ioaddr, mmwoff(0, mmw_loopt_sel), MMW_LOOPT_SEL_DIS_NWID);
X }
+#ifdef SET_PSA_CRC
+ /* update the Wavelan checksum */
+ update_psa_checksum(dev, ioaddr, lp->hacr);
+#endif
X break;
X
X case SIOCGIWNWID:
@@ -1955,6 +2001,10 @@
X psa.psa_thr_pre_set = wrq->u.sensitivity & 0x3F;
X psa_write(ioaddr, lp->hacr, (char *)&psa.psa_thr_pre_set - (char *)&psa,
X (unsigned char *) &psa.psa_thr_pre_set, 1);
+#ifdef SET_PSA_CRC
+ /* update the Wavelan checksum */
+ update_psa_checksum(dev, ioaddr, lp->hacr);
+#endif
X mmc_out(ioaddr, mmwoff(0, mmw_thr_pre_set), psa.psa_thr_pre_set);
X break;
X
@@ -2002,6 +2052,10 @@
X
X mmc_out(ioaddr, mmwoff(0, mmw_encr_enable), 0);
X }
+#ifdef SET_PSA_CRC
+ /* update the Wavelan checksum */
+ update_psa_checksum(dev, ioaddr, lp->hacr);
+#endif
X break;
X
X case SIOCGIWENCODE:
@@ -2215,6 +2269,10 @@
X psa.psa_quality_thr = *(wrq->u.name) & 0x0F;
X psa_write(ioaddr, lp->hacr, (char *)&psa.psa_quality_thr - (char *)&psa,
X (unsigned char *)&psa.psa_quality_thr, 1);
+#ifdef SET_PSA_CRC
+ /* update the Wavelan checksum */
+ update_psa_checksum(dev, ioaddr, lp->hacr);
+#endif
X mmc_out(ioaddr, mmwoff(0, mmw_quality_thr), psa.psa_quality_thr);
X break;
X
@@ -2325,7 +2383,7 @@
X mmc_out(ioaddr, mmwoff(0, mmw_freeze), 0);
X
X /* Copy data to wireless stuff */
- wstats->status = m.mmr_dce_status;
+ wstats->status = m.mmr_dce_status & MMR_DCE_STATUS;
X wstats->qual.qual = m.mmr_sgnl_qual & MMR_SGNL_QUAL;
X wstats->qual.level = m.mmr_signal_lvl & MMR_SIGNAL_LVL;
X wstats->qual.noise = m.mmr_silence_lvl & MMR_SILENCE_LVL;
@@ -2909,6 +2967,10 @@
X (unsigned char *)&psa.psa_quality_thr, 1);
X psa_write(ioaddr, lp->hacr, (char *)&psa.psa_conf_status - (char *)&psa,
X (unsigned char *)&psa.psa_conf_status, 1);
+#ifdef SET_PSA_CRC
+ /* update the Wavelan checksum */
+ update_psa_checksum(dev, ioaddr, lp->hacr);
+#endif
X #endif
X }
X
@@ -2935,21 +2997,18 @@
X m.mmw_thr_pre_set = psa.psa_thr_pre_set & 0x3F;
X m.mmw_quality_thr = psa.psa_quality_thr & 0x0F;
X
- /* Missing: encryption stuff... */
-
X /*
X * Set default modem control parameters.
X * See NCR document 407-0024326 Rev. A.
X */
X m.mmw_jabber_enable = 0x01;
+ m.mmw_freeze = 0;
X m.mmw_anten_sel = MMW_ANTEN_SEL_ALG_EN;
X m.mmw_ifs = 0x20;
X m.mmw_mod_delay = 0x04;
X m.mmw_jam_time = 0x38;
X
- m.mmw_encr_enable = 0;
X m.mmw_des_io_invert = 0;
- m.mmw_freeze = 0;
X m.mmw_decay_prm = 0;
X m.mmw_decay_updat_prm = 0;
X
@@ -3414,39 +3473,29 @@
X /* Create a configure action */
X memset(&cfg, 0x00, sizeof(cfg));
X
-#if 0
- /*
- * The default board configuration
- */
- cfg.fifolim_bytecnt = 0x080c;
- cfg.addrlen_mode = 0x2600;
- cfg.linprio_interframe = 0x7820; /* IFS=120, ACS=2 */
- cfg.slot_time = 0xf00c; /* slottime=12 */
- cfg.hardware = 0x0008; /* tx even without CD */
- cfg.min_frame_len = 0x0040;
-#endif /* 0 */
-
X /*
X * For Linux we invert AC_CFG_ALOC(..) so as to conform
X * to the way that net packets reach us from above.
X * (See also ac_tx_t.)
+ *
+ * Updated from Wavelan Manual WCIN085B
X */
X cfg.cfg_byte_cnt = AC_CFG_BYTE_CNT(sizeof(ac_cfg_t) - sizeof(ach_t));
- cfg.cfg_fifolim = AC_CFG_FIFOLIM(8);
- cfg.cfg_byte8 = AC_CFG_SAV_BF(0) |
+ cfg.cfg_fifolim = AC_CFG_FIFOLIM(4);
+ cfg.cfg_byte8 = AC_CFG_SAV_BF(1) |
X AC_CFG_SRDY(0);
X cfg.cfg_byte9 = AC_CFG_ELPBCK(0) |
X AC_CFG_ILPBCK(0) |
X AC_CFG_PRELEN(AC_CFG_PLEN_2) |
X AC_CFG_ALOC(1) |
X AC_CFG_ADDRLEN(WAVELAN_ADDR_SIZE);
- cfg.cfg_byte10 = AC_CFG_BOFMET(0) |
- AC_CFG_ACR(0) |
+ cfg.cfg_byte10 = AC_CFG_BOFMET(1) |
+ AC_CFG_ACR(6) |
X AC_CFG_LINPRIO(0);
- cfg.cfg_ifs = 32;
- cfg.cfg_slotl = 0;
+ cfg.cfg_ifs = 0x20;
+ cfg.cfg_slotl = 0x0C;
X cfg.cfg_byte13 = AC_CFG_RETRYNUM(15) |
- AC_CFG_SLTTMHI(2);
+ AC_CFG_SLTTMHI(0);
X cfg.cfg_byte14 = AC_CFG_FLGPAD(0) |
X AC_CFG_BTSTF(0) |
X AC_CFG_CRC16(0) |
@@ -4045,6 +4094,10 @@
X #endif
X psa_write(ioaddr, HACR_DEFAULT,
X psaoff(0, psa_int_req_no), &irq_mask, 1);
+#ifdef SET_PSA_CRC
+ /* update the Wavelan checksum */
+ update_psa_checksum(dev, ioaddr, HACR_DEFAULT);
+#endif
X wv_hacr_reset(ioaddr);
X }
X }
@@ -4227,7 +4280,7 @@
X init_module(void)
X {
X mac_addr mac; /* MAC address (check WaveLAN existence) */
- int ret = 0;
+ int ret = -EIO; /* Return error if no cards found */
X int i;
X
X #ifdef DEBUG_MODULE_TRACE
@@ -4272,7 +4325,11 @@
X /* DeAllocate everything */
X /* Note : if dev->priv is mallocated, there is no way to fail */
X kfree_s(dev, sizeof(struct device));
- ret = -EIO;
+ }
+ else
+ {
+ /* If at least one device OK, we do not fail */
+ ret = 0;
X }
X } /* if there is something at the address */
X } /* Loop on all addresses. */
diff -u --recursive --new-file v2.0.36/linux/drivers/net/wavelan.h linux/drivers/net/wavelan.h
--- v2.0.36/linux/drivers/net/wavelan.h Thu Mar 6 10:03:51 1997
+++ linux/drivers/net/wavelan.h Sun Jun 13 10:21:02 1999
@@ -28,6 +28,8 @@
X {
X { 0x08, 0x00, 0x0E }, /* AT&T Wavelan (standard) & DEC RoamAbout */
X { 0x08, 0x00, 0x6A }, /* AT&T Wavelan (alternate) */
+ { 0x00, 0x00, 0xE1 }, /* Hitachi Wavelan */
+ { 0x00, 0x60, 0x1D } /* Lucent Wavelan (another one) */
X /* Add your card here and send me the patch ! */
X };
X
@@ -293,6 +295,7 @@
X #define MMR_DCE_STATUS_LOOPT_IND 0x02 /* loop test indicated */
X #define MMR_DCE_STATUS_TX_BUSY 0x04 /* transmitter on */
X #define MMR_DCE_STATUS_JBR_EXPIRED 0x08 /* jabber timer expired */
+#define MMR_DCE_STATUS 0x0F /* mask to get the bits */
X unsigned char mmr_dsp_id; /* DSP id (AA = Daedalus rev A) */
X unsigned char mmr_unused2[2]; /* unused */
X unsigned char mmr_correct_nwid_l; /* # of correct NWID's rxd (low) */
diff -u --recursive --new-file v2.0.36/linux/drivers/net/wavelan.p.h linux/drivers/net/wavelan.p.h
--- v2.0.36/linux/drivers/net/wavelan.p.h Wed Oct 15 15:23:20 1997
+++ linux/drivers/net/wavelan.p.h Sun Jun 13 10:21:02 1999
@@ -16,15 +16,9 @@
X /************************** DOCUMENTATION **************************/
X /*
X * This driver provide a Linux interface to the Wavelan ISA hardware
- * The Wavelan is a product of Lucent ("http://wavelan.netland.nl/").
+ * The Wavelan is a product of Lucent ("http://www.wavelan.com/").
X * This division was formerly part of NCR and then AT&T.
- * Wavelan are also distributed by DEC (RoamAbout), Digital Ocean and
- * Aironet (Arlan). If you have one of those product, you will need to
- * make some changes below...
- *
- * This driver is still a beta software. A lot of bugs have been corrected,
- * a lot of functionalities are implemented, the whole appear pretty stable,
- * but there is still some area of improvement (encryption, performance...).
+ * Wavelan are also distributed by DEC (RoamAbout DS) and Digital Ocean.
X *
X * To know how to use this driver, read the NET3 HOWTO.
X * If you want to exploit the many other fonctionalities, look comments
@@ -35,12 +29,22 @@
X
X /* ------------------------ SPECIFIC NOTES ------------------------ */
X /*
+ * Web page
+ * --------
+ * I try to maintain a web page with the Wireless LAN Howto at :
+ * http://www-uk.hpl.hp.com/people/jt/Linux/Wavelan.html
+ *
X * wavelan.o is darn too big
X * -------------------------
X * That's true ! There is a very simple way to reduce the driver
X * object by 33% (yes !). Comment out the following line :
X * #include <linux/wireless.h>
X *
+ * Debugging and options
+ * ---------------------
+ * You will find below a set of '#define" allowing a very fine control
+ * on the driver behaviour and the debug messages printed.
+ *
X * MAC address and hardware detection :
X * ----------------------------------
X * The detection code of the wavelan chech that the first 3
@@ -60,23 +64,6 @@
X * 3) Compile & verify
X * 4) Send me the MAC code - I will include it in the next version...
X *
- * "CU Inactive" message at boot up :
- * -----------------------------------
- * It seem that there is some weird timings problems with the
- * Intel microcontroler. In fact, this message is triggered by a
- * bad reading of the on board ram the first time we read the
- * control block. If you ignore this message, all is ok (but in
- * fact, currently, it reset the wavelan hardware).
- *
- * To get rid of that problem, there is two solution. The first
- * is to add a dummy read of the scb at the end of
- * wv_82586_config. The second is to add the timers
- * wv_synchronous_cmd and wv_ack (the udelay just after the
- * waiting loops - seem that the controler is not totally ready
- * when it say it is !).
- *
- * In the current code, I use the second solution (to be
- * consistent with the original solution of Bruce Janson).
X */
X
X /* --------------------- WIRELESS EXTENSIONS --------------------- */
@@ -271,6 +258,22 @@
X * - Encryption setting from Brent Elphick (thanks a lot !)
X * - 'ioaddr' to 'u_long' for the Alpha (thanks to Stanislav Sinyagin)
X *
+ * Other changes (not by me) :
+ * -------------------------
+ * - Spelling and gramar "rectification".
+ *
+ * Changes made for release in 2.0.37 & 2.2.2 :
+ * ------------------------------------------
+ * - Correct status in /proc/net/wireless
+ * - Set PSA CRC to make PtP diagnostic tool happy (Bob Gray)
+ * - Module init code don't fail if we found at least one card in
+ * the address list (Karlis Peisenieks)
+ * - Missing parenthesis (Christopher Peterson)
+ * - Correct i82586 configuration parameters
+ * - Encryption initialisation bug (Robert McCormack)
+ * - New mac addresses detected in the probe
+ * - Increase watchdog for busy envirnoments
+ *
X * Wishes & dreams :
X * ---------------
X * - Roaming
@@ -338,9 +341,9 @@
X
X /* Options : */
X #define USE_PSA_CONFIG /* Use info from the PSA */
+#define SET_PSA_CRC /* Calculate and set the CRC on PSA */
X #define IGNORE_NORMAL_XMIT_ERRS /* Don't bother with normal conditions */
X #undef STRUCT_CHECK /* Verify padding of structures */
-#undef PSA_CRC /* Check CRC in PSA */
X #undef OLDIES /* Old code (to redo) */
X #undef RECORD_SNR /* To redo */
X #undef EEPROM_IS_PROTECTED /* Doesn't seem to be necessary */
@@ -355,11 +358,11 @@
X /************************ CONSTANTS & MACROS ************************/
X
X #ifdef DEBUG_VERSION_SHOW
-static const char *version = "wavelan.c : v16 (wireless extensions) 17/4/97\n";
+static const char *version = "wavelan.c : v18 (wireless extensions) 18/2/99\n";
X #endif
X
X /* Watchdog temporisation */
-#define WATCHDOG_JIFFIES 32 /* TODO: express in HZ. */
+#define WATCHDOG_JIFFIES 256 /* TODO: express in HZ. */
X
X /* Macro to get the number of elements in an array */
X #define NELS(a) (sizeof(a) / sizeof(a[0]))
diff -u --recursive --new-file v2.0.36/linux/drivers/pci/pci.c linux/drivers/pci/pci.c
--- v2.0.36/linux/drivers/pci/pci.c Sun Nov 15 21:51:46 1998
+++ linux/drivers/pci/pci.c Sun Jun 13 10:21:02 1999
@@ -110,6 +110,8 @@
X DEVICE( DEC, DEC_21052, "DC21052"),
X DEVICE( DEC, DEC_21150, "DC21150"),
X DEVICE( DEC, DEC_21152, "DC21152"),
+ DEVICE( DEC, DEC_21154, "DC21154"),
+ DEVICE( DEC, DEC_21285, "DC21285 Footbridge"),
X DEVICE( CIRRUS, CIRRUS_7548, "GD 7548"),
X DEVICE( CIRRUS, CIRRUS_5430, "GD 5430"),
X DEVICE( CIRRUS, CIRRUS_5434_4, "GD 5434"),
@@ -146,7 +148,11 @@
X DEVICE( MATROX, MATROX_MYS, "Mystique"),
X DEVICE( MATROX, MATROX_MIL_2, "Millennium II"),
X DEVICE( MATROX, MATROX_MIL_2_AGP,"Millennium II AGP"),
+ DEVICE( MATROX, MATROX_G200_PCI,"Matrox G200 PCI"),
+ DEVICE( MATROX, MATROX_G200_AGP,"Matrox G200 AGP"),
X DEVICE( MATROX, MATROX_MGA_IMP, "MGA Impression"),
+ DEVICE( MATROX, MATROX_G100_MM, "Matrox G100 multi monitor"),
+ DEVICE( MATROX, MATROX_G100_AGP,"Matrox G100 AGP"),
X DEVICE( CT, CT_65545, "65545"),
X DEVICE( CT, CT_65548, "65548"),
X DEVICE( CT, CT_65550, "65550"),
@@ -219,6 +225,9 @@
X DEVICE( X, X_AGX016, "ITT AGX016"),
X DEVICE( PICOP, PICOP_PT86C52X, "PT86C52x Vesuvius"),
X DEVICE( PICOP, PICOP_PT80C524, "PT80C524 Nile"),
+ DEVICE( MYLEX, MYLEX_DAC960P_V2,"DAC960P V2"),
+ DEVICE( MYLEX, MYLEX_DAC960P_V3,"DAC960P V3"),
+ DEVICE( MYLEX, MYLEX_DAC960P_V4,"DAC960P V4"),
X DEVICE( APPLE, APPLE_BANDIT, "Bandit"),
X DEVICE( APPLE, APPLE_GC, "Grand Central"),
X DEVICE( APPLE, APPLE_HYDRA, "Hydra"),
@@ -321,6 +330,7 @@
X DEVICE( TRUEVISION, TRUEVISION_T1000,"TARGA 1000"),
X DEVICE( INIT, INIT_320P, "320 P"),
X DEVICE( INIT, INIT_360P, "360 P"),
+ DEVICE( TTI, TTI_HPT343, "HPT343"),
X DEVICE( VIA, VIA_82C505, "VT 82C505"),
X DEVICE( VIA, VIA_82C561, "VT 82C561"),
X DEVICE( VIA, VIA_82C586_1, "VT 82C586 Apollo IDE"),
@@ -329,6 +339,7 @@
X DEVICE( VIA, VIA_82C586_0, "VT 82C586 Apollo ISA"),
X DEVICE( VIA, VIA_82C595, "VT 82C595 Apollo VP2"),
X DEVICE( VIA, VIA_82C597_0, "VT 82C597 Apollo VP3"),
+ DEVICE( VIA, VIA_82C598_0, "VT 82C598 Apollo MVP3"),
X DEVICE( VIA, VIA_82C926, "VT 82C926 Amazon"),
X DEVICE( VIA, VIA_82C416, "VT 82C416MV"),
X DEVICE( VIA, VIA_82C595_97, "VT 82C595 Apollo VP2/97"),
@@ -336,6 +347,8 @@
X DEVICE( VIA, VIA_82C586_3, "VT 82C586B Apollo ACPI"),
X DEVICE( VIA, VIA_86C100A, "VT 86C100A"),
X DEVICE( VIA, VIA_82C597_1, "VT 82C597 Apollo VP3 AGP"),
+ DEVICE( VIA, VIA_82C598_1, "VT 82C598 Apollo MVP3 AGP"),
+ DEVICE( SMC2, SMC2_1211TX, "1211 TX"),
X DEVICE( VORTEX, VORTEX_GDT60x0, "GDT 60x0"),
X DEVICE( VORTEX, VORTEX_GDT6000B,"GDT 6000b"),
X DEVICE( VORTEX, VORTEX_GDT6x10, "GDT 6110/6510"),
@@ -419,8 +432,12 @@
X DEVICE( RP, RP32INTF, "RocketPort 32 Intf"),
X DEVICE( CYCLADES, CYCLOM_Y_Lo, "Cyclom-Y below 1Mbyte"),
X DEVICE( CYCLADES, CYCLOM_Y_Hi, "Cyclom-Y above 1Mbyte"),
- DEVICE( CYCLADES, CYCLOM_Z_Lo, "Cyclom-Z below 1Mbyte"),
- DEVICE( CYCLADES, CYCLOM_Z_Hi, "Cyclom-Z above 1Mbyte"),
+ DEVICE( CYCLADES, CYCLOM_4Y_Lo, "Cyclom-4Y below 1Mbyte"),
+ DEVICE( CYCLADES, CYCLOM_4Y_Hi, "Cyclom-4Y above 1Mbyte"),
+ DEVICE( CYCLADES, CYCLOM_8Y_Lo, "Cyclom-8Y below 1Mbyte"),
+ DEVICE( CYCLADES, CYCLOM_8Y_Hi, "Cyclom-8Y above 1Mbyte"),
+ DEVICE( CYCLADES, CYCLOM_Z_Lo, "Cyclades-Z below 1Mbyte"),
+ DEVICE( CYCLADES, CYCLOM_Z_Hi, "Cyclades-Z above 1Mbyte"),
X DEVICE( ESSENTIAL, ESSENTIAL_ROADRUNNER,"Roadrunner serial HIPPI"),
X DEVICE( O2, O2_6832, "6832"),
X DEVICE( 3DFX, 3DFX_VOODOO, "Voodoo"),
@@ -472,11 +489,13 @@
X DEVICE( S3, S3_ViRGE_MXP, "ViRGE/MX+"),
X DEVICE( S3, S3_ViRGE_MXPMV, "ViRGE/MX+MV"),
X DEVICE( S3, S3_SONICVIBES, "SonicVibes"),
+ DEVICE( DCI, DCI_PCCOM4, "PC COM PCI Bus 4 port serial Adapter"),
X DEVICE( INTEL, INTEL_82375, "82375EB"),
X BRIDGE( INTEL, INTEL_82424, "82424ZX Saturn", 0x00),
X DEVICE( INTEL, INTEL_82378, "82378IB"),
X DEVICE( INTEL, INTEL_82430, "82430ZX Aries"),
X BRIDGE( INTEL, INTEL_82434, "82434LX Mercury/Neptune", 0x00),
+ BRIDGE( INTEL, INTEL_I960, "i960", 0x00),
X DEVICE( INTEL, INTEL_82092AA_0,"82092AA PCMCIA bridge"),
X DEVICE( INTEL, INTEL_82092AA_1,"82092AA EIDE"),
X DEVICE( INTEL, INTEL_7116, "SAA7116"),
@@ -512,9 +531,12 @@
X DEVICE( INTEL, INTEL_82450GX, "82450GX Orion P6"),
X DEVICE( KTI, KTI_ET32P2, "ET32P2"),
X DEVICE( ADAPTEC, ADAPTEC_7810, "AIC-7810 RAID"),
+ DEVICE( ADAPTEC, ADAPTEC_7821, "AIC-7860"),
X DEVICE( ADAPTEC, ADAPTEC_7850, "AIC-7850"),
X DEVICE( ADAPTEC, ADAPTEC_7855, "AIC-7855"),
+ DEVICE( ADAPTEC, ADAPTEC_3860, "AIC-7860"),
X DEVICE( ADAPTEC, ADAPTEC_5800, "AIC-5800"),
+ DEVICE( ADAPTEC, ADAPTEC_1480A, "AIC-1480A"),
X DEVICE( ADAPTEC, ADAPTEC_7860, "AIC-7860"),
X DEVICE( ADAPTEC, ADAPTEC_7861, "AIC-7861"),
X DEVICE( ADAPTEC, ADAPTEC_7870, "AIC-7870"),
@@ -528,11 +550,26 @@
X DEVICE( ADAPTEC, ADAPTEC_7882, "AIC-7882U"),
X DEVICE( ADAPTEC, ADAPTEC_7883, "AIC-7883U"),
X DEVICE( ADAPTEC, ADAPTEC_7884, "AIC-7884U"),
+ DEVICE( ADAPTEC, ADAPTEC_7885, "AIC-7885U"),
+ DEVICE( ADAPTEC, ADAPTEC_7886, "AIC-7886U"),
+ DEVICE( ADAPTEC, ADAPTEC_7887, "AIC-7887U"),
+ DEVICE( ADAPTEC, ADAPTEC_7888, "AIC-7888U"),
X DEVICE( ADAPTEC, ADAPTEC_1030, "ABA-1030 DVB receiver"),
- DEVICE( ADAPTEC2, ADAPTEC2_2940U2, "AHA-2940U2"),
- DEVICE( ADAPTEC2, ADAPTEC2_7890, "AIC-7890/1"),
- DEVICE( ADAPTEC2, ADAPTEC2_3940U2, "AHA-3940U2"),
- DEVICE( ADAPTEC2, ADAPTEC2_7896, "AIC-7896/7"),
+ DEVICE( ADAPTEC2, ADAPTEC2_2940U2,"AHA-2940U2"),
+ DEVICE( ADAPTEC2, ADAPTEC2_2930U2,"AHA-2930U2"),
+ DEVICE( ADAPTEC2, ADAPTEC2_7890B, "AIC-7890/1"),
+ DEVICE( ADAPTEC2, ADAPTEC2_7890, "AIC-7890/1"),
+ DEVICE( ADAPTEC2, ADAPTEC2_3940U2,"AHA-3940U2"),
+ DEVICE( ADAPTEC2, ADAPTEC2_3950U2D, "AHA-3950U2D"),
+ DEVICE( ADAPTEC2, ADAPTEC2_7896, "AIC-7896/7"),
+ DEVICE( ADAPTEC2, ADAPTEC2_7892A, "AIC-7892"),
+ DEVICE( ADAPTEC2, ADAPTEC2_7892B, "AIC-7892"),
+ DEVICE( ADAPTEC2, ADAPTEC2_7892D, "AIC-7892"),
+ DEVICE( ADAPTEC2, ADAPTEC2_7892P, "AIC-7892"),
+ DEVICE( ADAPTEC2, ADAPTEC2_7899A, "AIC-7899"),
+ DEVICE( ADAPTEC2, ADAPTEC2_7899B, "AIC-7899"),
+ DEVICE( ADAPTEC2, ADAPTEC2_7899D, "AIC-7899"),
+ DEVICE( ADAPTEC2, ADAPTEC2_7899P, "AIC-7899"),
X DEVICE( ATRONICS, ATRONICS_2015, "IDE-2015PL"),
X DEVICE( TIGERJET, TIGERJET_300, "Tiger300 ISDN"),
X DEVICE( ARK, ARK_STING, "Stingray"),
@@ -662,8 +699,8 @@
X case PCI_CLASS_STORAGE_SCSI: return "SCSI storage controller";
X case PCI_CLASS_STORAGE_IDE: return "IDE interface";
X case PCI_CLASS_STORAGE_FLOPPY: return "Floppy disk controller";
- case PCI_CLASS_STORAGE_IPI: return "IPI bus controller";
- case PCI_CLASS_STORAGE_RAID: return "RAID bus controller";
+ case PCI_CLASS_STORAGE_IPI: return "IPI storage controller";
+ case PCI_CLASS_STORAGE_RAID: return "RAID storage controller";
X case PCI_CLASS_STORAGE_OTHER: return "Unknown mass storage controller";
X
X case PCI_CLASS_NETWORK_ETHERNET: return "Ethernet controller";
@@ -769,6 +806,7 @@
X case PCI_VENDOR_ID_N9: return "Number Nine";
X case PCI_VENDOR_ID_UMC: return "UMC";
X case PCI_VENDOR_ID_X: return "X TECHNOLOGY";
+ case PCI_VENDOR_ID_MYLEX: return "Mylex";
X case PCI_VENDOR_ID_NEXGEN: return "Nexgen";
X case PCI_VENDOR_ID_QLOGIC: return "Q Logic";
X case PCI_VENDOR_ID_LEADTEK: return "Leadtek Research";
@@ -797,7 +835,9 @@
X case PCI_VENDOR_ID_REALTEK: return "Realtek";
X case PCI_VENDOR_ID_TRUEVISION: return "Truevision";
X case PCI_VENDOR_ID_INIT: return "Initio Corp";
+ case PCI_VENDOR_ID_TTI: return "Triones Technologies, Inc.";
X case PCI_VENDOR_ID_VIA: return "VIA Technologies";
+ case PCI_VENDOR_ID_SMC2: return "SMC";
X case PCI_VENDOR_ID_VORTEX: return "VORTEX";
X case PCI_VENDOR_ID_EF: return "Efficient Networks";
X case PCI_VENDOR_ID_FORE: return "Fore Systems";
@@ -811,6 +851,7 @@
X case PCI_VENDOR_ID_RENDITION: return "Rendition";
X case PCI_VENDOR_ID_TOSHIBA: return "Toshiba";
X case PCI_VENDOR_ID_RICOH: return "Ricoh";
+ case PCI_VENDOR_ID_ARTOP: return "Artop Electronics";
X case PCI_VENDOR_ID_ZEITNET: return "ZeitNet";
X case PCI_VENDOR_ID_OMEGA: return "Omega Micro";
X case PCI_VENDOR_ID_NP: return "Network Peripherals";
@@ -831,6 +872,7 @@
X case PCI_VENDOR_ID_AVANCE: return "Avance";
X case PCI_VENDOR_ID_NETVIN: return "NetVin";
X case PCI_VENDOR_ID_S3: return "S3 Inc.";
+ case PCI_VENDOR_ID_DCI: return "Decision Computer Int.";
X case PCI_VENDOR_ID_INTEL: return "Intel";
X case PCI_VENDOR_ID_KTI: return "KTI";
X case PCI_VENDOR_ID_ADAPTEC: return "Adaptec";
diff -u --recursive --new-file v2.0.36/linux/drivers/scsi/ChangeLog.ncr53c8xx linux/drivers/scsi/ChangeLog.ncr53c8xx
--- v2.0.36/linux/drivers/scsi/ChangeLog.ncr53c8xx Sun Nov 15 10:49:42 1998
+++ linux/drivers/scsi/ChangeLog.ncr53c8xx Sun Jun 13 10:21:02 1999
@@ -1,5 +1,265 @@
-Fri Jan 2 18:00 1998 Gerard Roudier (grou...@club-internet.fr)
- * Revision 2.5f
+Sun Dec 13 18:00 1998 Gerard Roudier (grou...@club-internet.fr)
+ * revision 3.1e
+ - Same work-around as for the 53c876 rev <= 0x15 for 53c896 rev 1:
+ Disable overlapped arbitration. This will not make difference
+ since the chip has on-chip RAM.
+
+Thu Nov 26 22:00 1998 Gerard Roudier (grou...@club-internet.fr)
+ * revision 3.1d
+ - The SISL RAID change requires now remap_pci_mem() stuff to be
+ compiled for __i386__ when normal IOs are used.
+ - Minor spelling fixes in doc files.
+
+Sat Nov 21 18:00 1998 Gerard Roudier (grou...@club-internet.fr)


SHAR_EOF
true || echo 'restore of patch-2.0.37 failed'
fi

echo 'End of part 18'
echo 'File patch-2.0.37 is continued in part 19'
echo 19 > _shar_seq_.tmp

Thomas...@ciw.uni-karlsruhe.de

unread,
Jun 16, 1999, 3:00:00 AM6/16/99
to
Archive-name: v2.0/patch-2.0.37/part22

#!/bin/sh
# this is part 22 of a 45 - part archive


# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.0.37 continued
if test ! -r _shar_seq_.tmp; then
echo 'Please unpack part 1 first!'
exit 1
fi
(read Scheck

if test "$Scheck" != 22; then


echo Please unpack part "$Scheck" next!
exit 1
else
exit 0
fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.0.37'
else
echo 'x - continuing with patch-2.0.37'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.0.37' &&

X 32, C56_66 },
X {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_3940U2, AHC_AIC7896,
X AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
- AHC_AIC7896_FE, 23,
+ AHC_AIC7896_FE, 24,
+ 32, C56_66 },
+ {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_3950U2D, AHC_AIC7896,
+ AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
+ AHC_AIC7896_FE, 25,
+ 32, C56_66 },
+ {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_1480A, AHC_AIC7860,
+ AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+ AHC_AIC7860_FE, 26,
+ 32, C46 },
+ {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892A, AHC_AIC7892,
+ AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+ AHC_AIC7892_FE, 27,
+ 32, C46 },
+ {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892B, AHC_AIC7892,
+ AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+ AHC_AIC7892_FE, 27,
+ 32, C46 },
+ {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892D, AHC_AIC7892,
+ AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+ AHC_AIC7892_FE, 27,
+ 32, C46 },
+ {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892P, AHC_AIC7892,
+ AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+ AHC_AIC7892_FE, 27,
+ 32, C46 },
+ {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899A, AHC_AIC7899,
+ AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+ AHC_AIC7899_FE, 28,
+ 32, C56_66 },
+ {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899B, AHC_AIC7899,
+ AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+ AHC_AIC7899_FE, 28,
+ 32, C56_66 },
+ {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899D, AHC_AIC7899,
+ AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+ AHC_AIC7899_FE, 28,
+ 32, C56_66 },
+ {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899P, AHC_AIC7899,
+ AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+ AHC_AIC7899_FE, 28,
X 32, C56_66 },
X };
X
X unsigned short command;
X unsigned int devconfig, i, oldverbose;
-#ifdef MMAPIO
- unsigned long page_offset, base;
-#endif
X #if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
X struct pci_dev *pdev = NULL;
X #else
@@ -9016,21 +9082,68 @@
X temp_p->mbase &= PCI_BASE_ADDRESS_MEM_MASK;
X temp_p->unpause = INTEN;
X temp_p->pause = temp_p->unpause | PAUSE;
+ if ( ((temp_p->base == 0) &&
+ (temp_p->mbase == 0)) ||
+ (temp_p->irq == 0) )
+ {
+ printk("aic7xxx: <%s> at PCI %d/%d\n",
+ board_names[aic_pdevs[i].board_name_index],
+ PCI_SLOT(temp_p->pci_device_fn),
+ PCI_FUNC(temp_p->pci_device_fn));
+ printk("aic7xxx: Controller disabled by BIOS, ignoring.\n");
+ kfree(temp_p);
+ temp_p = NULL;
+ continue;
+ }
X
X #ifdef MMAPIO
- base = temp_p->mbase & PAGE_MASK;
- page_offset = temp_p->mbase - base;
+ {
+ unsigned long page_offset, base;
+
+ base = temp_p->mbase & PAGE_MASK;
+ page_offset = temp_p->mbase - base;
X #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
- temp_p->maddr = ioremap_nocache(base, page_offset + 256);
+ temp_p->maddr = ioremap_nocache(base, page_offset + 256);
X #else
- temp_p->maddr = vremap(base, page_offset + 256);
+ temp_p->maddr = vremap(base, page_offset + 256);
X #endif
- if(temp_p->maddr)
- {
- temp_p->maddr += page_offset;
+ if(temp_p->maddr)
+ {
+ temp_p->maddr += page_offset;
+ /*
+ * We need to check the I/O with the MMAPed address. Some machines
+ * simply fail to work with MMAPed I/O and certain controllers.
+ */
+ if(aic_inb(temp_p, HCNTRL) == 0xff)
+ {
+ /*
+ * OK.....we failed our test....go back to programmed I/O
+ */
+ printk(KERN_INFO "aic7xxx: <%s> at PCI %d/%d\n",
+ board_names[aic_pdevs[i].board_name_index],
+ PCI_SLOT(temp_p->pci_device_fn),
+ PCI_FUNC(temp_p->pci_device_fn));
+ printk(KERN_INFO "aic7xxx: MMAPed I/O failed, reverting to "
+ "Programmed I/O.\n");
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,0)
+ iounmap((void *) (((unsigned long) temp_p->maddr) & PAGE_MASK));
+#else
+ vfree((void *) (((unsigned long) temp_p->maddr) & PAGE_MASK));
+#endif
+ temp_p->maddr = 0;
+ }


+ }
X }
X #endif
X

+ /*
+ * We HAVE to make sure the first pause_sequencer() and all other
+ * subsequent I/O that isn't PCI config space I/O takes place
+ * after the MMAPed I/O region is configured and tested. The
+ * problem is the PowerPC architecture that doesn't support
+ * programmed I/O at all, so we have to have the MMAP I/O set up
+ * for this pause to even work on those machines.
+ */
X pause_sequencer(temp_p);
X
X /*
@@ -9065,44 +9178,36 @@
X }
X
X /*
- * Doing a switch based upon i is really gross, but since Justin
- * changed around the chip ID stuff, we can't use that any more.
- * Since we don't scan the devices the same way as FreeBSD, we end
- * up doing this gross hack in order to avoid totally splitting
- * away from Justin's init code in ahc_pci.c
+ * We need to set the CHNL? assignments before loading the SEEPROM
+ * The 3940 and 3985 cards (original stuff, not any of the later
+ * stuff) are 7870 and 7880 class chips. The Ultra2 stuff falls
+ * under 7896 and 7897. The 7895 is in a class by itself :)
X */
- switch (i)
+ switch (temp_p->chip & AHC_CHIPID_MASK)
X {
- case 7: /* 3940 */
- case 12: /* 3940-Ultra */
- switch(PCI_SLOT(temp_p->pci_device_fn))
+ case AHC_AIC7870: /* 3840 / 3985 */
+ case AHC_AIC7880: /* 3840 UW / 3985 UW */
+ if(temp_p->flags & AHC_MULTI_CHANNEL)
X {
- case 5:
- temp_p->flags |= AHC_CHNLB;
- break;
- default:
- break;
- }
- break;
-
- case 8: /* 3985 */
- case 13: /* 3985-Ultra */
- switch(PCI_SLOT(temp_p->pci_device_fn))
- {
- case 8:
- temp_p->flags |= AHC_CHNLB;
- break;
- case 12:
- temp_p->flags |= AHC_CHNLC;
- break;
- default:
- break;
+ switch(PCI_SLOT(temp_p->pci_device_fn))
+ {
+ case 5:
+ temp_p->flags |= AHC_CHNLB;


+ break;
+ case 8:

+ temp_p->flags |= AHC_CHNLB;
+ break;
+ case 12:
+ temp_p->flags |= AHC_CHNLC;
+ break;
+ default:
+ break;
+ }
X }
X break;
X
- case 15:
- case 18:
- case 19:
+ case AHC_AIC7895: /* 7895 */
+ case AHC_AIC7896: /* 7896/7 */
X #if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
X if (PCI_FUNC(temp_p->pdev->devfn) != 0)
X {
@@ -9178,16 +9283,6 @@
X aic_outb(temp_p, (aic_inb(temp_p, DSCOMMAND0) |
X CACHETHEN | MPARCKEN | USCBSIZE32 |
X CIOPARCKEN) & ~DPARCKEN, DSCOMMAND0);
- /* FALLTHROUGH */
- default:
- /*
- * We attempt to read a SEEPROM on *everything*. If we fail,
- * then we fail, but this covers things like 2910c cards that
- * now have SEEPROMs with their 7856 chipset that we would
- * otherwise ignore. They still don't have a BIOS, but they
- * have a SEEPROM that the SCSISelect utility on the Adaptec
- * diskettes can configure.
- */
X aic7xxx_load_seeprom(temp_p, &sxfrctl1);
X break;
X case AHC_AIC7850:
@@ -9199,14 +9294,13 @@
X aic_outb(temp_p, (aic_inb(temp_p, DSCOMMAND0) |
X CACHETHEN | MPARCKEN) & ~DPARCKEN,
X DSCOMMAND0);
+ /* FALLTHROUGH */
+ default:
X aic7xxx_load_seeprom(temp_p, &sxfrctl1);
X break;
X case AHC_AIC7880:
X /*
- * Only set the DSCOMMAND0 register if this is a Rev B.
- * chipset. For those, we also enable Ultra mode by
- * force due to brain-damage on the part of some BIOSes
- * We overload the devconfig variable here since we can.
+ * Check the rev of the chipset before we change DSCOMMAND0
X */
X #if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
X pci_read_config_dword(pdev, DEVCONFIG, &devconfig);
@@ -9270,13 +9364,10 @@
X }
X
X /*
- * We do another switch based on i so that we can exclude all
- * 3895 devices from the next option since the 3895 cards use
- * shared external SCB RAM while all other cards have dedicated
- * external SCB RAM per channel. Also exclude the 7850 and
- * 7860 based stuff since they can have garbage in the bit
- * that indicates external RAM and get some of this stuff
- * wrong as a result.
+ * We only support external SCB RAM on the 7895/6/7 chipsets.
+ * We could support it on the 7890/1 easy enough, but I don't
+ * know of any 7890/1 based cards that have it. I do know
+ * of 7895/6/7 cards that have it and they work properly.
X */
X switch(temp_p->chip & AHC_CHIPID_MASK)
X {
@@ -9340,9 +9431,6 @@
X aic_outb(temp_p, DFTHRSH_100, DSPCISTATUS);
X }
X
- if (aic7xxx_extended)
- temp_p->flags |= AHC_EXTEND_TRANS_A;
-
X if ( list_p == NULL )
X {
X list_p = current_p = temp_p;
@@ -10109,8 +10197,6 @@
X "message buffer\n", p->host_no, CTL_OF_SCB(scb));
X scb->flags |= SCB_RESET | SCB_DEVICE_RESET;
X aic7xxx_error(scb->cmd) = DID_RESET;
- p->dev_flags[TARGET_INDEX(scb->cmd)] &=
- ~DEVICE_SUCCESS;
X p->dev_flags[TARGET_INDEX(scb->cmd)] |=
X BUS_DEVICE_RESET_PENDING;
X /* Send the abort message to the active SCB. */
@@ -10131,8 +10217,6 @@
X "in use\n", p->host_no, CTL_OF_SCB(scb));
X scb->flags |= SCB_RESET | SCB_DEVICE_RESET;
X aic7xxx_error(scb->cmd) = DID_RESET;
- p->dev_flags[TARGET_INDEX(scb->cmd)] &=
- ~DEVICE_SUCCESS;
X p->dev_flags[TARGET_INDEX(scb->cmd)] |=
X BUS_DEVICE_RESET_PENDING;
X return(SCSI_RESET_ERROR);
@@ -10160,7 +10244,6 @@
X */
X scb->hscb->control |= MK_MESSAGE;
X scb->flags |= SCB_RESET | SCB_DEVICE_RESET;
- p->dev_flags[TARGET_INDEX(scb->cmd)] &= ~DEVICE_SUCCESS;
X p->dev_flags[TARGET_INDEX(scb->cmd)] |=
X BUS_DEVICE_RESET_PENDING;
X if (hscb_index != SCB_LIST_NULL)
@@ -10240,7 +10323,7 @@
X {
X mask = (0x01 << i);
X printk(INFO_LEAD "dev_flags=0x%x, WDTR:%c/%c/%c, SDTR:%c/%c/%c,"
- " q_depth=%d:%d:%d\n",
+ " q_depth=%d:%d\n",
X p->host_no, 0, i, 0, p->dev_flags[i],
X (p->wdtr_pending & mask) ? 'Y' : 'N',
X (p->needwdtr & mask) ? 'Y' : 'N',
@@ -10249,7 +10332,7 @@
X (p->needsdtr & mask) ? 'Y' : 'N',
X (p->needsdtr_copy & mask) ? 'Y' : 'N',
X p->dev_active_cmds[i],
- p->dev_max_queue_depth[i], p->dev_mid_level_queue_depth[i]);
+ p->dev_max_queue_depth[i] );
X printk(INFO_LEAD "targ_scsirate=0x%x", p->host_no, 0, i, 0,
X aic_inb(p, TARG_SCSIRATE + i));
X if (p->features & AHC_ULTRA2)
@@ -10890,7 +10973,7 @@
X {
X action = HOST_RESET;
X }
- if ( ((jiffies - p->dev_last_reset[tindex]) < (HZ * 3)) &&
+ if ( (p->dev_flags[tindex] & DEVICE_RESET_DELAY) &&
X !(action & (HOST_RESET | BUS_RESET)))
X {
X if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
@@ -10902,23 +10985,14 @@
X }
X action = BUS_RESET;
X }
- if ( ((jiffies - p->last_reset) < (HZ * 3)) &&
- (action & (HOST_RESET | BUS_RESET)) )
+ if ( (p->flags & AHC_RESET_DELAY) &&
+ (action & (HOST_RESET | BUS_RESET)) )
X {
X if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
X printk(INFO_LEAD "Reset called too soon after "
X "last bus reset, delaying.\n", p->host_no, CTL_OF_CMD(cmd));
X action = RESET_DELAY;
X }
- if ( (action & (BUS_RESET | HOST_RESET)) && (p->flags & AHC_IN_RESET)
- && ((jiffies - p->reset_start) > (2 * HZ * 3)) )
- {
- printk(KERN_ERR "(scsi%d:%d:%d:%d) Yikes!! Card must have left to go "
- "back to Adaptec!!\n", p->host_no, CTL_OF_CMD(cmd));
- unpause_sequencer(p, FALSE);
- DRIVER_UNLOCK
- return(SCSI_RESET_SNOOZE);
- }
X /*
X * By this point, we want to already know what we are going to do and
X * only have the following code implement our course of action.
@@ -10950,15 +11024,23 @@
X case BUS_RESET:
X case HOST_RESET:
X default:
- p->reset_start = jiffies;
- p->flags |= AHC_IN_RESET;
+ p->flags |= AHC_IN_RESET | AHC_RESET_DELAY;
+ p->dev_expires[p->scsi_id] = jiffies + (3 * HZ);
+ p->dev_timer_active |= (0x01 << p->scsi_id);
+ if ( !(p->dev_timer_active & (0x01 << MAX_TARGETS)) ||
+ time_after_eq(p->dev_timer.expires, p->dev_expires[p->scsi_id]) )
+ {
+ del_timer(&p->dev_timer);
+ p->dev_timer.expires = p->dev_expires[p->scsi_id];
+ add_timer(&p->dev_timer);
+ p->dev_timer_active |= (0x01 << MAX_TARGETS);
+ }
X aic7xxx_reset_channel(p, cmd->channel, TRUE);
X if ( (p->features & AHC_TWIN) && (action & HOST_RESET) )
X {
X aic7xxx_reset_channel(p, cmd->channel ^ 0x01, TRUE);
X restart_sequencer(p);
X }
- p->last_reset = jiffies;
X if (action != HOST_RESET)
X result = SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET;
X else
@@ -10973,9 +11055,27 @@
X p->msg_len = 0;
X }
X aic7xxx_run_done_queue(p, TRUE);
+ /*
+ * If this a SCSI_RESET_SYNCHRONOUS then the command we were given is
+ * in need of being re-started, so send it on through to aic7xxx_queue
+ * and let it set until the delay is over. This keeps it from dying
+ * entirely and avoids getting a bogus dead command back through the
+ * mid-level code due to too many retries.
+ */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,132)
+ if ( flags & SCSI_RESET_SYNCHRONOUS )
+ {
+ cmd->result = DID_BUS_BUSY << 16;
+ cmd->done(cmd);
+ }
+#endif
X p->flags &= ~AHC_IN_RESET;
- /* We can't rely on run_waiting_queues to unpause the sequencer for
- * PCI based controllers since we use AAP */
+ /*
+ * We can't rely on run_waiting_queues to unpause the sequencer for
+ * PCI based controllers since we use AAP. NOTE: this also sets
+ * the timer for the one command we might have queued in the case
+ * of a synch reset.
+ */
X aic7xxx_run_waiting_queues(p);
X unpause_sequencer(p, FALSE);
X DRIVER_UNLOCK
@@ -10994,16 +11094,21 @@
X int
X aic7xxx_biosparam(Disk *disk, kdev_t dev, int geom[])
X {
- int heads, sectors, cylinders;
+ int heads, sectors, cylinders, ret;
X struct aic7xxx_host *p;
+ struct buffer_head *bh;
X
X p = (struct aic7xxx_host *) disk->device->host->hostdata;
+ bh = bread(MKDEV(MAJOR(dev), MINOR(dev)&~0xf), 0, 1024);
X
- /*
- * XXX - if I could portably find the card's configuration
- * information, then this could be autodetected instead
- * of left to a boot-time switch.
- */
+ if ( bh )
+ {
+ ret = scsi_partsize(bh, disk->capacity, &geom[2], &geom[0], &geom[1]);
+ brelse(bh);
+ if ( ret != -1 )
+ return(ret);
+ }
+
X heads = 64;
X sectors = 32;
X cylinders = disk->capacity / (heads * sectors);
diff -u --recursive --new-file v2.0.36/linux/drivers/scsi/aic7xxx_proc.c linux/drivers/scsi/aic7xxx_proc.c
--- v2.0.36/linux/drivers/scsi/aic7xxx_proc.c Sun Nov 15 21:51:46 1998
+++ linux/drivers/scsi/aic7xxx_proc.c Sun Jun 13 10:21:02 1999
@@ -31,7 +31,7 @@
X
X #define BLS (&aic7xxx_buffer[size])
X #define HDRB \
-" < 512 512-1K 1-2K 2-4K 4-8K 8-16K 16-32K 32-64K 64-128K >128K"
+" < 2K 2K+ 4K+ 8K+ 16K+ 32K+ 64K+ 128K+"
X
X #ifdef PROC_DEBUG
X extern int vsprintf(char *, const char *, va_list);
@@ -86,7 +86,7 @@
X int size = 0;
X unsigned char i;
X struct aic7xxx_xferstats *sp;
- unsigned char target, lun;
+ unsigned char target;
X
X HBAptr = NULL;
X
@@ -130,15 +130,12 @@
X size = 4096;
X for (target = 0; target < MAX_TARGETS; target++)
X {
- for (lun = 0; lun < MAX_LUNS; lun++)
- {
- if (p->stats[target][lun].xfers != 0)
+ if (p->dev_flags[target] & DEVICE_PRESENT)
X #ifdef AIC7XXX_PROC_STATS
- size += 512;
+ size += 512;
X #else
- size += 256;
+ size += 256;
X #endif
- }
X }
X if (aic7xxx_buffer_size != size)
X {
@@ -163,21 +160,17 @@
X size += sprintf(BLS, "%s", AIC7XXX_H_VERSION);
X size += sprintf(BLS, "\n");
X size += sprintf(BLS, "Compile Options:\n");
-#ifdef AIC7XXX_RESET_DELAY
- size += sprintf(BLS, " AIC7XXX_RESET_DELAY : %d\n", AIC7XXX_RESET_DELAY);
+#ifdef CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT
+ size += sprintf(BLS, " TCQ Enabled By Default : Enabled\n");
+#else
+ size += sprintf(BLS, " TCQ Enabled By Default : Disabled\n");
X #endif
- size += sprintf(BLS, " AIC7XXX_TAGGED_QUEUEING: Adapter Support Enabled\n");
- size += sprintf(BLS, " Check below to see "
- "which\n"
- " devices use tagged "
- "queueing\n");
- size += sprintf(BLS, " AIC7XXX_PAGE_ENABLE : Enabled (This is no longer "
- "an option)\n");
X #ifdef AIC7XXX_PROC_STATS
X size += sprintf(BLS, " AIC7XXX_PROC_STATS : Enabled\n");
X #else
X size += sprintf(BLS, " AIC7XXX_PROC_STATS : Disabled\n");
X #endif
+ size += sprintf(BLS, " AIC7XXX_RESET_DELAY : %d\n", AIC7XXX_RESET_DELAY);
X size += sprintf(BLS, "\n");
X size += sprintf(BLS, "Adapter Configuration:\n");
X size += sprintf(BLS, " SCSI Adapter: %s\n",
@@ -253,11 +246,7 @@
X }
X size += sprintf(BLS, " Tag Queue Enable Flags: 0x%04x\n", p->tagenable);
X size += sprintf(BLS, "Ordered Queue Tag Flags: 0x%04x\n", p->orderedtag);
-#ifdef AIC7XXX_CMDS_PER_LUN
- size += sprintf(BLS, "Default Tag Queue Depth: %d\n", AIC7XXX_CMDS_PER_LUN);
-#else
- size += sprintf(BLS, "Default Tag Queue Depth: %d\n", 8);
-#endif
+ size += sprintf(BLS, "Default Tag Queue Depth: %d\n", AIC7XXX_CMDS_PER_DEVICE);
X size += sprintf(BLS, " Tagged Queue By Device array for aic7xxx host "
X "instance %d:\n", p->instance);
X size += sprintf(BLS, " {");
@@ -272,85 +261,83 @@
X size += sprintf(BLS, "%d}\n", p->dev_max_queue_depth[i]);
X
X size += sprintf(BLS, "\n");
- size += sprintf(BLS, "Statistics:\n");
+ size += sprintf(BLS, "Statistics:\n\n");
X for (target = 0; target < MAX_TARGETS; target++)
X {
- for (lun = 0; lun < MAX_LUNS; lun++)
+ sp = &p->stats[target];
+ if ((p->dev_flags[target] & DEVICE_PRESENT) == 0)
X {
- sp = &p->stats[target][lun];
- if (sp->xfers == 0)
- {
- continue;
- }
- if (p->features & AHC_TWIN)
+ continue;
+ }
+ if (p->features & AHC_TWIN)
+ {
+ size += sprintf(BLS, "(scsi%d:%d:%d:%d)\n",
+ p->host_no, (target >> 3), (target & 0x7), 0);
+ }
+ else
+ {
+ size += sprintf(BLS, "(scsi%d:%d:%d:%d)\n",
+ p->host_no, 0, target, 0);
+ }
+ size += sprintf(BLS, " Device using %s/%s",
+ (p->transinfo[target].cur_width == MSG_EXT_WDTR_BUS_16_BIT) ?
+ "Wide" : "Narrow",
+ (p->transinfo[target].cur_offset != 0) ?
+ "Sync transfers at " : "Async transfers.\n" );
+ if (p->transinfo[target].cur_offset != 0)
+ {
+ struct aic7xxx_syncrate *sync_rate;
+ int period = p->transinfo[target].cur_period;
+ int rate = (p->transinfo[target].cur_width ==
+ MSG_EXT_WDTR_BUS_16_BIT) ? 1 : 0;
+
+ sync_rate = aic7xxx_find_syncrate(p, &period, AHC_SYNCRATE_ULTRA2);
+ if (sync_rate != NULL)
X {
- size += sprintf(BLS, "(scsi%d:%d:%d:%d)\n",
- p->host_no, (target >> 3), (target & 0x7), lun);
+ size += sprintf(BLS, "%s MByte/sec, offset %d\n",
+ sync_rate->rate[rate],
+ p->transinfo[target].cur_offset );
X }
X else
X {
- size += sprintf(BLS, "(scsi%d:%d:%d:%d)\n",
- p->host_no, 0, target, lun);
- }
- size += sprintf(BLS, " Device using %s/%s\n",
- (p->transinfo[target].cur_width == MSG_EXT_WDTR_BUS_16_BIT) ?
- "Wide" : "Narrow",
- (p->transinfo[target].cur_offset != 0) ?
- "Sync transfers at" : "Async transfers." );
- if (p->transinfo[target].cur_offset != 0)
- {
- struct aic7xxx_syncrate *sync_rate;
- int period = p->transinfo[target].cur_period;
- int rate = (p->transinfo[target].cur_width ==
- MSG_EXT_WDTR_BUS_16_BIT) ? 1 : 0;
-
- sync_rate = aic7xxx_find_syncrate(p, &period, AHC_SYNCRATE_ULTRA2);
- if (sync_rate != NULL)
- {
- size += sprintf(BLS, " %s MByte/sec, offset %d\n",
- sync_rate->rate[rate],
- p->transinfo[target].cur_offset );
- }
- else
- {
- size += sprintf(BLS, " 3.3 MByte/sec, offset %d\n",
- p->transinfo[target].cur_offset );
- }
+ size += sprintf(BLS, "3.3 MByte/sec, offset %d\n",
+ p->transinfo[target].cur_offset );
X }
- size += sprintf(BLS, " Device Negotiation Settings\n");
- size += sprintf(BLS, " Period Offset Bus Width\n");
- size += sprintf(BLS, "User %03d %03d %d\n",
- p->transinfo[target].user_period,
- p->transinfo[target].user_offset,
- p->transinfo[target].user_width);
- size += sprintf(BLS, "Goal %03d %03d %d\n",
- p->transinfo[target].goal_period,
- p->transinfo[target].goal_offset,
- p->transinfo[target].goal_width);
- size += sprintf(BLS, "Current %03d %03d %d\n",
- p->transinfo[target].cur_period,
- p->transinfo[target].cur_offset,
- p->transinfo[target].cur_width);
- size += sprintf(BLS, " Total transfers %ld (%ld read;%ld written)\n",
- sp->xfers, sp->r_total, sp->w_total);
- size += sprintf(BLS, " blks(512) rd=%ld; blks(512) wr=%ld\n",
- sp->r_total512, sp->w_total512);
+ }
+ size += sprintf(BLS, " Transinfo settings: ");
+ size += sprintf(BLS, "current(%d/%d/%d), ",
+ p->transinfo[target].cur_period,
+ p->transinfo[target].cur_offset,
+ p->transinfo[target].cur_width);
+ size += sprintf(BLS, "goal(%d/%d/%d), ",
+ p->transinfo[target].goal_period,
+ p->transinfo[target].goal_offset,
+ p->transinfo[target].goal_width);
+ size += sprintf(BLS, "user(%d/%d/%d)\n",
+ p->transinfo[target].user_period,
+ p->transinfo[target].user_offset,
+ p->transinfo[target].user_width);
X #ifdef AIC7XXX_PROC_STATS
- size += sprintf(BLS, "%s\n", HDRB);
- size += sprintf(BLS, " Reads:");
- for (i = 0; i < NUMBER(sp->r_bins); i++)
- {
- size += sprintf(BLS, "%6ld ", sp->r_bins[i]);
- }
- size += sprintf(BLS, "\n");
- size += sprintf(BLS, "Writes:");
- for (i = 0; i < NUMBER(sp->w_bins); i++)
- {
- size += sprintf(BLS, "%6ld ", sp->w_bins[i]);
- }
-#endif /* AIC7XXX_PROC_STATS */
- size += sprintf(BLS, "\n\n");
+ size += sprintf(BLS, " Total transfers %ld (%ld reads and %ld writes)\n",
+ sp->r_total + sp->w_total, sp->r_total, sp->w_total);
+ size += sprintf(BLS, "%s\n", HDRB);
+ size += sprintf(BLS, " Reads:");
+ for (i = 0; i < NUMBER(sp->r_bins); i++)
+ {
+ size += sprintf(BLS, " %7ld", sp->r_bins[i]);
+ }
+ size += sprintf(BLS, "\n");
+ size += sprintf(BLS, " Writes:");
+ for (i = 0; i < NUMBER(sp->w_bins); i++)
+ {
+ size += sprintf(BLS, " %7ld", sp->w_bins[i]);
X }
+ size += sprintf(BLS, "\n");
+#else
+ size += sprintf(BLS, " Total transfers %ld (%ld reads and %ld writes)\n",
+ sp->r_total + sp->w_total, sp->r_total, sp->w_total);
+#endif /* AIC7XXX_PROC_STATS */
+ size += sprintf(BLS, "\n\n");
X }
X
X if (size >= aic7xxx_buffer_size)
diff -u --recursive --new-file v2.0.36/linux/drivers/scsi/atp870u.c linux/drivers/scsi/atp870u.c
--- v2.0.36/linux/drivers/scsi/atp870u.c Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/atp870u.c Sun Jun 13 10:21:02 1999
@@ -0,0 +1,2029 @@
+/* $Id: atp870u.c,v 1.0 1997/05/07 15:22:00 root Exp root $
+ * linux/kernel/atp870u.c
+ *
+ * Copyright (C) 1997 Wu Ching Chen


+ *
+ */
+

+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/head.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <linux/bios32.h>
+#include <linux/pci.h>
+#include <linux/blk.h>
+#include "scsi.h"
+#include "hosts.h"
+
+
+#include "atp870u.h"
+#include <linux/config.h> /* for CONFIG_PCI */
+
+#include<linux/stat.h>
+
+struct proc_dir_entry proc_scsi_atp870u = {
+ PROC_SCSI_ATP870U, 7, "atp870u",
+ S_IFDIR | S_IRUGO | S_IXUGO, 2
+};
+
+void mydlyu(unsigned int);
+/*
+static const char RCSid[] = "$Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/atp870u.c,v 1.0 1997/05/07 15:22:00 root Exp root $";
+*/
+
+static unsigned char admaxu=1,host_idu[2],chip_veru[2],scam_on[2],global_map[2];
+static unsigned short int active_idu[2],wide_idu[2],sync_idu,ultra_map[2];
+static int workingu[2]={0,0};
+static Scsi_Cmnd *querequ[2][qcnt],*curr_req[2][16];
+static unsigned char devspu[2][16] = {{0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
+ 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20},
+ {0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
+ 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20}};
+static unsigned char dirctu[2][16],last_cmd[2],in_snd[2],in_int[2];
+static unsigned char ata_cdbu[2][16];
+static unsigned int ioportu[2]={0,0};
+static unsigned int irqnumu[2]={0,0};
+static unsigned short int pciportu[2];
+static unsigned long prdaddru[2][16],tran_lenu[2][16],last_lenu[2][16];
+static unsigned char prd_tableu[2][16][1024];
+static unsigned char *prd_posu[2][16];
+static unsigned char quhdu[2],quendu[2];
+static unsigned char devtypeu[2][16] = {{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
+ { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+static struct Scsi_Host * atp_host[2]={NULL,NULL};
+
+static void atp870u_intr_handle(int irq, void *dev_id, struct pt_regs *regs)
+{
+ unsigned short int tmpcip,id;
+ unsigned char i,j,h,tarid,lun;
+ unsigned char *prd;
+ Scsi_Cmnd *workrequ;
+ unsigned int workportu,tmport;
+ unsigned long adrcntu,k;
+ int errstus;
+
+ for ( h=0; h < 2; h++ )
+ {
+ if ( ( irq & 0x0f ) == irqnumu[h] )
+ {
+ goto irq_numok;
+ }
+ }
+ return;
+irq_numok:
+ in_int[h]=1;
+ workportu=ioportu[h];
+ tmport=workportu;
+
+ if ( workingu[h] != 0 )
+ {
+ tmport += 0x1f;
+ j=inb(tmport);
+ tmpcip=pciportu[h];
+ if ((inb(tmpcip) & 0x08) != 0)
+ {
+ tmpcip += 0x2;
+ while((inb(tmpcip) & 0x08) != 0);
+ }
+ tmpcip=pciportu[h];
+ outb(0x00,tmpcip);
+ tmport -=0x08;
+ i=inb(tmport);
+ if ((j & 0x40) == 0)
+ {
+ if ((last_cmd[h] & 0x40) == 0)
+ {
+ last_cmd[h]=0xff;
+ }
+ }
+ else
+ {
+ last_cmd[h] |= 0x40;
+ }
+ tmport -= 0x02;
+ tarid=inb(tmport);
+ tmport += 0x02;
+ if ((tarid & 0x40) != 0)
+ {
+ tarid=(tarid & 0x07) | 0x08;
+ }
+ else
+ {
+ tarid &= 0x07;
+ }
+ if ( i == 0x85 )
+ {
+ if (wide_idu[h] != 0)
+ {
+ tmport=workportu+0x1b;
+ j=inb(tmport) & 0x0e;
+ j |= 0x01;
+ outb(j,tmport);
+ }
+ if (((quhdu[h] != quendu[h]) || (last_cmd[h] != 0xff)) &&
+ (in_snd[h] == 0))
+ {
+ send_s870(h);
+ }
+ in_int[h]=0;
+ return;
+ }
+ if ( i == 0x21 )
+ {
+ tmport -= 0x05;
+ adrcntu=0;
+ ((unsigned char *)&adrcntu)[2]=inb(tmport++);
+ ((unsigned char *)&adrcntu)[1]=inb(tmport++);
+ ((unsigned char *)&adrcntu)[0]=inb(tmport);
+ k=last_lenu[h][tarid];
+ k -= adrcntu;
+ tran_lenu[h][tarid]= k;
+ last_lenu[h][tarid]=adrcntu;
+ tmport -= 0x04;
+ outb(0x41,tmport);
+ tmport += 0x08;
+ outb(0x08,tmport);
+ in_int[h]=0;
+ return ;
+ }
+
+ if ((i == 0x80) || (i == 0x8f))
+ {
+ lun=0;
+ tmport -= 0x07;
+ j=inb(tmport);
+ if ( j == 0x44 )
+ {
+ tmport += 0x0d;
+ lun=inb(tmport) & 0x07;
+ }
+ else
+ {
+ if ( j == 0x41 )
+ {
+ tmport += 0x02;
+ adrcntu=0;
+ ((unsigned char *)&adrcntu)[2]=inb(tmport++);
+ ((unsigned char *)&adrcntu)[1]=inb(tmport++);
+ ((unsigned char *)&adrcntu)[0]=inb(tmport);
+ k=last_lenu[h][tarid];
+ k -= adrcntu;
+ tran_lenu[h][tarid]= k;
+ last_lenu[h][tarid]=adrcntu;
+ tmport += 0x04;
+ outb(0x08,tmport);
+ in_int[h]=0;
+ return ;
+ }
+ else
+ {
+ outb(0x46,tmport);
+ dirctu[h][tarid]=0x00;
+ tmport += 0x02;
+ outb(0x00,tmport++);
+ outb(0x00,tmport++);
+ outb(0x00,tmport++);
+ tmport+=0x03;
+ outb(0x08,tmport);
+ in_int[h]=0;
+ return;
+ }
+ }
+ tmport=workportu + 0x10;
+ outb(0x45,tmport);
+ tmport += 0x06;
+ tarid=inb(tmport);
+ if ((tarid & 0x10) != 0)
+ {
+ tarid=(tarid & 0x07) | 0x08;
+ }
+ else
+ {
+ tarid &= 0x07;
+ }
+ workrequ=curr_req[h][tarid];
+ tmport=workportu + 0x0f;
+ outb(lun,tmport);
+ tmport += 0x02;
+ outb(devspu[h][tarid],tmport++);
+ adrcntu=tran_lenu[h][tarid];
+ k=last_lenu[h][tarid];
+ outb(((unsigned char *)&k)[2],tmport++);
+ outb(((unsigned char *)&k)[1],tmport++);
+ outb(((unsigned char *)&k)[0],tmport++);
+ j=tarid;
+ if ( tarid > 7 )
+ {
+ j = (j & 0x07) | 0x40;
+ }
+ j |= dirctu[h][tarid];
+ outb(j,tmport++);
+ outb(0x80,tmport);
+ tmport=workportu + 0x1b;
+ j=inb(tmport) & 0x0e;
+ id=1;
+ id=id << tarid;
+ if ((id & wide_idu[h]) != 0)
+ {
+ j |= 0x01;
+ }
+ outb(j,tmport);
+ if ( last_lenu[h][tarid] == 0 )
+ {
+ tmport=workportu + 0x18;
+ outb(0x08,tmport);
+ in_int[h]=0;
+ return ;
+ }
+ prd=prd_posu[h][tarid];
+ while ( adrcntu != 0 )
+ {
+ id=((unsigned short int *)(prd))[2];
+ if ( id == 0 )
+ {
+ k=0x10000;
+ }
+ else
+ {
+ k=id;
+ }
+ if ( k > adrcntu )
+ {
+ ((unsigned short int *)(prd))[2] =(unsigned short int)
+ (k - adrcntu);
+ ((unsigned long *)(prd))[0] += adrcntu;
+ adrcntu=0;
+ prd_posu[h][tarid]=prd;
+ }
+ else
+ {
+ adrcntu -= k;
+ prdaddru[h][tarid] += 0x08;
+ prd += 0x08;
+ if ( adrcntu == 0 )
+ {
+ prd_posu[h][tarid]=prd;
+ }
+ }
+ }
+ tmpcip=pciportu[h] + 0x04;
+ outl(prdaddru[h][tarid],tmpcip);
+ tmpcip -= 0x02;
+ outb(0x06,tmpcip);
+ outb(0x00,tmpcip);
+ tmpcip -= 0x02;
+ tmport=workportu + 0x18;
+ if ( dirctu[h][tarid] != 0 )
+ {
+ outb(0x08,tmport);
+ outb(0x01,tmpcip);
+ in_int[h]=0;
+ return;
+ }
+ outb(0x08,tmport);
+ outb(0x09,tmpcip);
+ in_int[h]=0;
+ return;
+ }
+
+ workrequ=curr_req[h][tarid];
+ if ( i == 0x42 )
+ {
+ errstus=0x02;
+ workrequ->result=errstus;
+ goto go_42;
+ }
+ if ( i == 0x16 )
+ {
+ errstus=0;
+ tmport -= 0x08;
+ errstus=inb(tmport);
+ workrequ->result=errstus;
+/* if ( errstus == 0x02 )
+ {
+ tmport +=0x10;
+ if ((inb(tmport) & 0x80) != 0)
+ {
+ printk(" autosense ");
+ }
+ tmport -=0x09;
+ outb(0,tmport);
+ tmport=workportu+0x3a;
+ outb((unsigned char)(inb(tmport) | 0x10),tmport);
+ tmport -= 0x39;
+
+ outb(0x08,tmport++);
+ outb(0x7f,tmport++);
+ outb(0x03,tmport++);
+ outb(0x00,tmport++);
+ outb(0x00,tmport++);
+ outb(0x00,tmport++);
+ outb(0x0e,tmport++);
+ outb(0x00,tmport);
+ tmport+=0x07;
+ outb(0x00,tmport++);
+ tmport++;
+ outb(devspu[h][workrequ->target],tmport++);
+ outb(0x00,tmport++);
+ outb(0x00,tmport++);
+ outb(0x0e,tmport++);
+ tmport+=0x03;
+ outb(0x09,tmport);
+ tmport+=0x07;
+ i=0;
+ adrcntu=(unsigned long)(&workrequ->sense_buffer[0]);
+get_sens:
+ j=inb(tmport);
+ if ((j & 0x01) != 0)
+ {
+ tmport-=0x06;
+ (unsigned char)(((caddr_t) adrcntu)[i++])=inb(tmport);
+ tmport+=0x06;
+ goto get_sens;
+ }
+ if ((j & 0x80) == 0)
+ {
+ goto get_sens;
+ }
+ if ((j & 0x40) == 0)
+ {
+ tmport-=0x08;
+ i=inb(tmport);
+ }
+ tmport=workportu+0x3a;
+ outb((unsigned char)(inb(tmport) & 0xef),tmport);
+ tmport=workportu+0x01;
+ outb(0x2c,tmport);
+ tmport += 0x15;
+ outb(0x80,tmport);
+ } */
+go_42:
+ (*workrequ->scsi_done)(workrequ);
+ curr_req[h][tarid]=0;
+ workingu[h]--;
+ if (wide_idu[h] != 0)
+ {
+ tmport=workportu+0x1b;
+ j=inb(tmport) & 0x0e;
+ j |= 0x01;
+ outb(j,tmport);
+ }
+ if (((last_cmd[h] != 0xff) || (quhdu[h] != quendu[h])) &&
+ (in_snd[h] == 0))
+ {
+ send_s870(h);
+ }
+ in_int[h]=0;
+ return;
+ }
+ if ( i == 0x4f )
+ {
+ i=0x89;
+ }
+ i &= 0x0f;
+ if ( i == 0x09 )
+ {
+ tmpcip=tmpcip+4;
+ outl(prdaddru[h][tarid],tmpcip);
+ tmpcip=tmpcip-2;
+ outb(0x06,tmpcip);
+ outb(0x00,tmpcip);
+ tmpcip=tmpcip-2;
+ tmport=workportu+0x10;
+ outb(0x41,tmport);
+ dirctu[h][tarid]=0x00;
+ tmport += 0x08;
+ outb(0x08,tmport);
+ outb(0x09,tmpcip);
+ in_int[h]=0;
+ return;
+ }
+ if ( i == 0x08 )
+ {
+ tmpcip=tmpcip+4;
+ outl(prdaddru[h][tarid],tmpcip);
+ tmpcip=tmpcip-2;
+ outb(0x06,tmpcip);
+ outb(0x00,tmpcip);
+ tmpcip=tmpcip-2;
+ tmport=workportu+0x10;
+ outb(0x41,tmport);
+ tmport += 0x05;
+ outb((unsigned char)(inb(tmport) | 0x20),tmport);
+ dirctu[h][tarid]=0x20;
+ tmport += 0x03;
+ outb(0x08,tmport);
+ outb(0x01,tmpcip);
+ in_int[h]=0;
+ return;
+ }
+ tmport -= 0x07;
+ if ( i == 0x0a )
+ {
+ outb(0x30,tmport);
+ }
+ else
+ {
+ outb(0x46,tmport);
+ }
+ dirctu[h][tarid]=0x00;
+ tmport += 0x02;
+ outb(0x00,tmport++);
+ outb(0x00,tmport++);
+ outb(0x00,tmport++);
+ tmport+=0x03;
+ outb(0x08,tmport);
+ in_int[h]=0;
+ return;
+ }
+ else
+ {
+ tmport=workportu+0x17;
+ inb(tmport);
+ workingu[h]=0;
+ in_int[h]=0;


+ return;
+ }
+}
+

+int atp870u_queuecommand(Scsi_Cmnd * req_p, void (*done)(Scsi_Cmnd *))
+{
+ unsigned char i,h;
+ unsigned long flags;
+ unsigned short int m;
+ unsigned int tmport;
+
+ for( h=0; h <= admaxu; h++ )
+ {
+ if ( req_p->host == atp_host[h] )
+ {
+ goto host_ok;
+ }
+ }
+ return 0;
+host_ok:
+ if ( req_p->channel != 0 )
+ {
+ req_p->result = 0x00040000;
+ done(req_p);
+ return 0;
+ }
+ m=1;
+ m= m << req_p->target;
+ if ( ( m & active_idu[h] ) == 0 )
+ {
+ req_p->result = 0x00040000;
+ done(req_p);
+ return 0;
+ }
+ if (done)
+ {
+ req_p->scsi_done = done;
+ }
+ else
+ {
+ printk("atp870u_queuecommand: done can't be NULL\n");
+ req_p->result = 0;
+ done(req_p);
+ return 0;
+ }
+ quendu[h]++;
+ if ( quendu[h] >= qcnt )
+ {
+ quendu[h]=0;
+ }
+ wait_que_empty:
+ if ( quhdu[h] == quendu[h] )
+ {
+ goto wait_que_empty;
+ }
+ save_flags(flags);
+ cli();
+ querequ[h][quendu[h]]=req_p;
+ if ( quendu[h] == 0 )
+ {
+ i=qcnt-1;
+ }
+ else
+ {
+ i=quendu[h]-1;
+ }
+ tmport = ioportu[h]+0x1c;
+ restore_flags(flags);
+ if ((inb(tmport) == 0) && (in_int[h] == 0) && (in_snd[h] == 0))
+ {
+ send_s870(h);
+ }


+ return 0;
+}
+

+void mydlyu(unsigned int dlycnt )
+{
+ unsigned int i ;
+ for ( i = 0 ; i < dlycnt ; i++ )
+ {
+ inb(0x80);
+ }
+}
+
+void send_s870(unsigned char h)
+{
+ unsigned int tmport;
+ Scsi_Cmnd *workrequ;
+ unsigned long flags;
+ unsigned int i;
+ unsigned char j,tarid;
+ unsigned char *prd;
+ unsigned short int tmpcip,w;
+ unsigned long l,bttl;
+ unsigned int workportu;
+ struct scatterlist * sgpnt;
+
+ save_flags(flags);
+ cli();
+ if ( in_snd[h] != 0 )
+ {
+ restore_flags(flags);
+ return;
+ }
+ in_snd[h]=1;
+ if ((last_cmd[h] != 0xff) && ((last_cmd[h] & 0x40) != 0))
+ {
+ last_cmd[h] &= 0x0f;
+ workrequ=curr_req[h][last_cmd[h]];
+ goto cmd_subp;
+ }
+ workingu[h]++;
+ j=quhdu[h];
+ quhdu[h]++;
+ if ( quhdu[h] >= qcnt )
+ {
+ quhdu[h]=0;
+ }
+ workrequ=querequ[h][quhdu[h]];
+ if ( curr_req[h][workrequ->target] == 0 )
+ {
+ curr_req[h][workrequ->target]=workrequ;
+ last_cmd[h]=workrequ->target;
+ goto cmd_subp;
+ }
+ quhdu[h]=j;
+ workingu[h]--;
+ in_snd[h]=0;
+ restore_flags(flags);
+ return ;
+cmd_subp:
+ workportu=ioportu[h];
+ tmport=workportu+0x1f;
+ if ((inb(tmport) & 0xb0) != 0)
+ {
+ goto abortsnd;
+ }
+ tmport=workportu+0x1c;
+ if ( inb(tmport) == 0 )
+ {
+ goto oktosend;
+ }
+abortsnd:
+ last_cmd[h] |= 0x40;
+ in_snd[h]=0;
+ restore_flags(flags);
+ return;
+oktosend:
+ memcpy(&ata_cdbu[h][0], &workrequ->cmnd[0], workrequ->cmd_len);
+ if ( ata_cdbu[h][0] == 0x25 )
+ {
+ if ( workrequ->request_bufflen > 8 )
+ {
+ workrequ->request_bufflen=0x08;
+ }
+ }
+ if ( ata_cdbu[h][0] == 0x12 )
+ {
+ if ( workrequ->request_bufflen > 0x24 )
+ {
+ workrequ->request_bufflen = 0x24;
+ ata_cdbu[h][4]=0x24;
+ }
+ }
+
+ tmport=workportu+0x1b;
+ j=inb(tmport) & 0x0e;
+ tarid=workrequ->target;
+ w=1;
+ w = w << tarid;
+ if ((w & wide_idu[h]) != 0)
+ {
+ j |= 0x01;
+ }
+ outb(j,tmport);
+ tmport=workportu;
+ outb(workrequ->cmd_len,tmport++);
+ outb(0x2c,tmport++);
+ outb(0xcf,tmport++);
+ for ( i=0 ; i < workrequ->cmd_len ; i++ )
+ {
+ outb(ata_cdbu[h][i],tmport++);
+ }
+ tmport=workportu+0x0f;
+ outb(0x00,tmport);
+ tmport+=0x02;
+ outb(devspu[h][tarid],tmport++);
+ if (workrequ->use_sg)
+ {
+
+ l=0;
+ sgpnt = (struct scatterlist *) workrequ->request_buffer;
+ for(i=0; i<workrequ->use_sg; i++)
+ {
+ if(sgpnt[i].length == 0 || workrequ->use_sg > ATP870U_SCATTER)
+ {
+ panic("Foooooooood fight!");
+ }
+ l += sgpnt[i].length;
+ }
+ }
+ else
+ {
+ l=workrequ->request_bufflen;
+ }
+ outb((unsigned char)(((unsigned char *)(&l))[2]),tmport++);
+ outb((unsigned char)(((unsigned char *)(&l))[1]),tmport++);
+ outb((unsigned char)(((unsigned char *)(&l))[0]),tmport++);
+ j=tarid;
+ last_lenu[h][j]=l;
+ tran_lenu[h][j]=0;
+ if ((j & 0x08) != 0)
+ {
+ j=(j & 0x07) | 0x40;
+ }
+ if ((ata_cdbu[h][0] == 0x0a) || (ata_cdbu[h][0] == 0x2a) ||
+ (ata_cdbu[h][0] == 0xaa) || (ata_cdbu[h][0] == 0x15))
+ {
+ outb((unsigned char)(j | 0x20),tmport++);
+ }
+ else
+ {
+ outb(j,tmport++);
+ }
+ outb(0x80,tmport);
+ tmport=workportu + 0x1c;
+ dirctu[h][tarid]=0;
+ if ( l == 0 )
+ {
+ if ( inb(tmport) == 0 )
+ {
+ tmport=workportu+0x18;
+ outb(0x08,tmport);
+ }
+ else
+ {
+ last_cmd[h] |= 0x40;
+ }
+ in_snd[h]=0;
+ restore_flags(flags);
+ return;
+ }
+ tmpcip=pciportu[h];
+ prd=&prd_tableu[h][tarid][0];
+ prd_posu[h][tarid]=prd;
+ if (workrequ->use_sg)
+ {
+ sgpnt = (struct scatterlist *) workrequ->request_buffer;
+ i=0;
+ for(j=0; j<workrequ->use_sg; j++)
+ {
+ (unsigned long)(((unsigned long *)(prd))[i >> 1])=(unsigned long)sgpnt[j].address;
+ (unsigned short int)(((unsigned short int *)(prd))[i+2])=sgpnt[j].length;
+ (unsigned short int)(((unsigned short int *)(prd))[i+3])=0;
+ i +=0x04;
+ }
+ (unsigned short int)(((unsigned short int *)(prd))[i-1])=0x8000;
+ }
+ else
+ {
+ bttl=(unsigned long)workrequ->request_buffer;
+ l=workrequ->request_bufflen;
+ i=0;
+ while ( l > 0x10000 )
+ {
+ (unsigned short int)(((unsigned short int *)(prd))[i+3])=0x0000;
+ (unsigned short int)(((unsigned short int *)(prd))[i+2])=0x0000;
+ (unsigned long)(((unsigned long *)(prd))[i >> 1])=bttl;
+ l -= 0x10000;
+ bttl += 0x10000;
+ i += 0x04;
+ }
+ (unsigned short int)(((unsigned short int *)(prd))[i+3])=0x8000;
+ (unsigned short int)(((unsigned short int *)(prd))[i+2])=l;
+ (unsigned long)(((unsigned long *)(prd))[i >> 1])=bttl;
+ }
+ tmpcip=tmpcip+4;
+ prdaddru[h][tarid]=(unsigned long)&prd_tableu[h][tarid][0];
+ outl(prdaddru[h][tarid],tmpcip);
+ tmpcip=tmpcip-2;
+ outb(0x06,tmpcip);
+ outb(0x00,tmpcip);
+ tmpcip=tmpcip-2;
+ if ((ata_cdbu[h][0] == 0x0a) || (ata_cdbu[h][0] == 0x2a) ||
+ (ata_cdbu[h][0] == 0xaa) || (ata_cdbu[h][0] == 0x15))
+ {
+ dirctu[h][tarid]=0x20;
+ if ( inb(tmport) == 0 )
+ {
+ tmport=workportu+0x18;
+ outb(0x08,tmport);
+ outb(0x01,tmpcip);
+ }
+ else
+ {
+ last_cmd[h] |= 0x40;
+ }
+ in_snd[h]=0;
+ restore_flags(flags);
+ return;
+ }
+ if ( inb(tmport) == 0 )
+ {
+ tmport=workportu+0x18;
+ outb(0x08,tmport);
+ outb(0x09,tmpcip);
+ }
+ else
+ {
+ last_cmd[h] |= 0x40;
+ }
+ in_snd[h]=0;
+ restore_flags(flags);
+ return;
+
+}
+
+static void internal_done(Scsi_Cmnd * SCpnt)
+{
+ SCpnt->SCp.Status++;
+}
+
+int atp870u_command(Scsi_Cmnd * SCpnt)
+{
+
+ atp870u_queuecommand(SCpnt, internal_done);
+
+ SCpnt->SCp.Status = 0;
+ while (!SCpnt->SCp.Status)
+ barrier();
+ return SCpnt->result;
+}
+
+unsigned char fun_scam ( unsigned char host,unsigned short int * val )
+{
+ unsigned int tmport ;
+ unsigned short int i,k;
+ unsigned char j;
+
+ tmport = ioportu[host]+0x1c;
+ outw(*val,tmport);
+FUN_D7:
+ for ( i=0; i < 10; i++ ) /* stable >= bus settle delay(400 ns) */
+ {
+ k=inw(tmport);
+ j= (unsigned char)(k >> 8);
+ if ((k & 0x8000) != 0) /* DB7 all release? */
+ {
+ goto FUN_D7;
+ }
+ }
+ *val |= 0x4000; /* assert DB6 */
+ outw(*val,tmport);
+ *val &= 0xdfff; /* assert DB5 */
+ outw(*val,tmport);
+FUN_D5:
+ for ( i=0; i < 10; i++ ) /* stable >= bus settle delay(400 ns) */
+ {
+ if ((inw(tmport) & 0x2000) != 0) /* DB5 all release? */
+ {
+ goto FUN_D5;
+ }
+ }
+ *val |= 0x8000; /* no DB4-0, assert DB7 */
+ *val &= 0xe0ff;
+ outw(*val,tmport);
+ *val &= 0xbfff; /* release DB6 */
+ outw(*val,tmport);
+FUN_D6:
+ for ( i=0; i < 10; i++ ) /* stable >= bus settle delay(400 ns) */
+ {
+ if ((inw(tmport) & 0x4000) != 0) /* DB6 all release? */
+ {
+ goto FUN_D6;
+ }
+ }
+
+ return j;
+}
+
+void tscam( unsigned char host )
+{
+
+ unsigned int tmport ;
+ unsigned char i,j,k;
+ unsigned long n;
+ unsigned short int m,assignid_map,val;
+ unsigned char mbuf[33],quintet[2];
+ static unsigned char g2q_tab[8]={ 0x38,0x31,0x32,0x2b,0x34,0x2d,0x2e,0x27 };
+
+
+ for ( i=0; i < 0x10; i++ )
+ {
+ mydlyu(0xffff);
+ }
+
+ tmport = ioportu[host]+1;
+ outb(0x08,tmport++);
+ outb(0x7f,tmport);
+ tmport = ioportu[host]+0x11;
+ outb(0x20,tmport);
+
+ if ((scam_on[host] & 0x40) == 0)


+ {
+ return;
+ }
+

+ m=1;
+ m <<= host_idu[host];
+ j=16;
+ if ( chip_veru[host] < 4 )
+ {
+ m |= 0xff00;
+ j=8;
+ }
+ assignid_map=m;
+ tmport = ioportu[host]+0x02;
+ outb(0x02,tmport++); /* 2*2=4ms,3EH 2/32*3E=3.9ms */
+ outb(0,tmport++);
+ outb(0,tmport++);
+ outb(0,tmport++);
+ outb(0,tmport++);
+ outb(0,tmport++);
+ outb(0,tmport++);
+
+ for ( i = 0 ; i < j ; i ++ )
+ {
+ m=1;
+ m=m<<i;
+ if ( ( m & assignid_map ) != 0 )
+ {
+ continue;
+ }
+ tmport = ioportu[host]+0x0f;
+ outb(0,tmport++);
+ tmport += 0x02;
+ outb(0,tmport++);
+ outb(0,tmport++);
+ outb(0,tmport++);
+ if ( i > 7 )
+ {
+ k=(i & 0x07) | 0x40;
+ }
+ else
+ {
+ k=i;
+ }
+ outb(k,tmport++);
+ tmport = ioportu[host]+0x1b;
+ if ( chip_veru[host] == 4 )
+ {
+ outb((unsigned char)((inb(tmport) & 0x0e) | 0x01),tmport);
+ }
+ else
+ {
+ outb((unsigned char)(inb(tmport) & 0x0e),tmport);
+ }
+wait_rdyok:
+ tmport = ioportu[host]+0x18;
+ outb(0x09,tmport);
+ tmport += 0x07;
+
+ while ((inb(tmport) & 0x80) == 0x00);
+ tmport -= 0x08;
+ k=inb(tmport);
+ if ( k != 0x16 )
+ {
+ if ((k == 0x85) || (k == 0x42))
+ {
+ continue;
+ }
+ tmport = ioportu[host]+0x10;
+ outb(0x41,tmport);
+ goto wait_rdyok;
+ }
+ assignid_map |= m;
+
+ }
+ tmport = ioportu[host]+0x02;
+ outb(0x7f,tmport);
+ tmport = ioportu[host]+0x1b;
+ outb(0x02,tmport);
+
+ outb(0,0x80);
+
+ val=0x0080; /* bsy */
+ tmport = ioportu[host]+0x1c;
+ outw(val,tmport);
+ val |=0x0040; /* sel */
+ outw(val,tmport);
+ val |=0x0004; /* msg */
+ outw(val,tmport);
+ inb(0x80); /* 2 deskew delay(45ns*2=90ns) */
+ val &=0x007f; /* no bsy */
+ outw(val,tmport);
+ mydlyu(0xffff); /* recommanded SCAM selection response time */
+ mydlyu(0xffff);
+ val &=0x00fb; /* after 1ms no msg */
+ outw(val,tmport);
+wait_nomsg:
+ if ((inb(tmport) & 0x04) != 0)
+ {
+ goto wait_nomsg;
+ }
+ outb(1,0x80);
+ mydlyu(100);
+ for ( n=0; n < 0x30000; n++ )
+ {
+ if ((inb(tmport) & 0x80) != 0) /* bsy ? */
+ {
+ goto wait_io;
+ }
+ }
+ goto TCM_SYNC;
+wait_io:
+ for ( n=0; n < 0x30000; n++ )
+ {
+ if ((inb(tmport) & 0x81) == 0x0081)
+ {
+ goto wait_io1;
+ }
+ }
+ goto TCM_SYNC;
+wait_io1:
+ inb(0x80);
+ val |=0x8003; /* io,cd,db7 */
+ outw(val,tmport);
+ inb(0x80);
+ val &=0x00bf; /* no sel */
+ outw(val,tmport);
+ outb(2,0x80);
+TCM_SYNC:
+ mydlyu(0x800);
+ if ((inb(tmport) & 0x80) == 0x00) /* bsy ? */
+ {
+ outw(0,tmport--);
+ outb(0,tmport);
+ tmport=ioportu[host] + 0x15;
+ outb(0,tmport);
+ tmport += 0x03;
+ outb(0x09,tmport);
+ tmport += 0x07;
+ while ((inb(tmport) & 0x80) == 0);
+ tmport -= 0x08;
+ inb(tmport);
+ return;
+ }
+
+ val &= 0x00ff; /* synchronization */
+ val |= 0x3f00;
+ fun_scam(host,&val);
+ outb(3,0x80);
+ val &= 0x00ff; /* isolation */
+ val |= 0x2000;
+ fun_scam(host,&val);
+ outb(4,0x80);
+ i=8;
+ j=0;
+TCM_ID:
+ if ((inw(tmport) & 0x2000) == 0)
+ {
+ goto TCM_ID;
+ }
+ outb(5,0x80);
+ val &= 0x00ff; /* get ID_STRING */
+ val |= 0x2000;
+ k=fun_scam(host,&val);
+ if ((k & 0x03) == 0)
+ {
+ goto TCM_5;
+ }
+ mbuf[j] <<= 0x01;
+ mbuf[j] &= 0xfe;
+ if ((k & 0x02) != 0)
+ {
+ mbuf[j] |= 0x01;
+ }
+ i--;
+ if ( i > 0 )
+ {
+ goto TCM_ID;
+ }
+ j++;
+ i=8;
+ goto TCM_ID;
+
+TCM_5: /* isolation complete.. */
+/* mbuf[32]=0;
+ printk(" \n%x %x %x %s\n ",assignid_map,mbuf[0],mbuf[1],&mbuf[2]); */
+ i=15;
+ j=mbuf[0];
+ if ((j & 0x20) != 0) /* bit5=1:ID upto 7 */
+ {
+ i=7;
+ }
+ if ((j & 0x06) == 0) /* IDvalid? */
+ {
+ goto G2Q5;
+ }
+ k=mbuf[1];
+small_id:
+ m=1;
+ m <<= k;
+ if ((m & assignid_map) == 0)
+ {
+ goto G2Q_QUIN;
+ }
+ if ( k > 0 )
+ {
+ k--;
+ goto small_id;
+ }
+G2Q5: /* srch from max acceptable ID# */
+ k=i; /* max acceptable ID# */
+G2Q_LP:
+ m=1;
+ m <<= k;
+ if ((m & assignid_map) == 0)
+ {
+ goto G2Q_QUIN;
+ }
+ if ( k > 0 )
+ {
+ k--;
+ goto G2Q_LP;
+ }
+G2Q_QUIN: /* k=binID#, */
+ assignid_map |= m;
+ if ( k < 8 )
+ {
+ quintet[0]=0x38; /* 1st dft ID<8 */
+ }
+ else
+ {
+ quintet[0]=0x31; /* 1st ID>=8 */
+ }
+ k &= 0x07;
+ quintet[1]=g2q_tab[k];
+
+ val &= 0x00ff; /* AssignID 1stQuintet,AH=001xxxxx */
+ m=quintet[0] << 8;
+ val |= m;
+ fun_scam(host,&val);
+ val &= 0x00ff; /* AssignID 2ndQuintet,AH=001xxxxx */
+ m=quintet[1] << 8;
+ val |= m;
+ fun_scam(host,&val);
+
+ goto TCM_SYNC;
+
+}
+
+void is870(unsigned long host,unsigned int wkport )
+{
+ unsigned int tmport ;
+ unsigned char i,j,k,rmb;
+ unsigned short int m;
+ static unsigned char mbuf[512];
+ static unsigned char satn[9] = { 0,0,0,0,0,0,0,6,6 };
+ static unsigned char inqd[9] = { 0x12,0,0,0,0x24,0,0,0x24,6 };
+ static unsigned char synn[6] = { 0x80,1,3,1,0x19,0x0e };
+ static unsigned char synu[6] = { 0x80,1,3,1,0x0c,0x0e };
+ static unsigned char synw[6] = { 0x80,1,3,1,0x0c,0x07 };
+ static unsigned char wide[6] = { 0x80,1,2,3,1,0 };
+
+ sync_idu=0;
+ tmport=wkport+0x3a;
+ outb((unsigned char)(inb(tmport) | 0x10),tmport);
+
+ for ( i = 0 ; i < 16 ; i ++ )
+ {
+ if ((chip_veru[host] != 4) && (i > 7))
+ {
+ break;
+ }
+ m=1;
+ m=m<<i;
+ if ( ( m & active_idu[host] ) != 0 )
+ {
+ continue;
+ }
+ if ( i == host_idu[host] )
+ {
+ printk(" ID: %2d Host Adapter\n",host_idu[host]);
+ continue;
+ }
+ if ( chip_veru[host] == 4 )
+ {
+ tmport=wkport+0x1b;
+ j=(inb(tmport) & 0x0e) | 0x01;
+ outb(j,tmport);
+ }
+ tmport=wkport+1;
+ outb(0x08,tmport++);
+ outb(0x7f,tmport++);
+ outb(satn[0],tmport++);
+ outb(satn[1],tmport++);
+ outb(satn[2],tmport++);
+ outb(satn[3],tmport++);
+ outb(satn[4],tmport++);
+ outb(satn[5],tmport++);
+ tmport+=0x06;
+ outb(0,tmport);
+ tmport+=0x02;
+ outb(devspu[host][i],tmport++);
+ outb(0,tmport++);
+ outb(satn[6],tmport++);
+ outb(satn[7],tmport++);
+ j=i;
+ if ((j & 0x08) != 0)
+ {
+ j=(j & 0x07) | 0x40;
+ }
+ outb(j,tmport);
+ tmport+=0x03;
+ outb(satn[8],tmport);
+ tmport+=0x07;
+
+ while ((inb(tmport) & 0x80) == 0x00);
+ tmport-=0x08;
+ if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e))
+ {
+ continue;
+ }
+ while ( inb(tmport) != 0x8e );
+ active_idu[host] |= m;
+
+ tmport=wkport+0x10;
+ outb(0x30,tmport);
+ tmport=wkport+0x04;
+ outb(0x00,tmport);
+
+phase_cmd:
+ tmport=wkport+0x18;
+ outb(0x08,tmport);
+ tmport+=0x07;
+ while ((inb(tmport) & 0x80) == 0x00);
+ tmport-=0x08;
+ j=inb(tmport);
+ if ( j != 0x16 )
+ {
+ tmport=wkport+0x10;
+ outb(0x41,tmport);
+ goto phase_cmd;
+ }
+sel_ok:
+ tmport=wkport+3;
+ outb(inqd[0],tmport++);
+ outb(inqd[1],tmport++);
+ outb(inqd[2],tmport++);
+ outb(inqd[3],tmport++);
+ outb(inqd[4],tmport++);
+ outb(inqd[5],tmport);
+ tmport+=0x07;
+ outb(0,tmport);
+ tmport+=0x02;
+ outb(devspu[host][i],tmport++);
+ outb(0,tmport++);
+ outb(inqd[6],tmport++);
+ outb(inqd[7],tmport++);
+ tmport+=0x03;
+ outb(inqd[8],tmport);
+ tmport+=0x07;
+ while ((inb(tmport) & 0x80) == 0x00);
+ tmport-=0x08;
+ if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e))
+ {
+ continue;
+ }
+ while ( inb(tmport) != 0x8e );
+ if ( chip_veru[host] == 4 )
+ {
+ tmport=wkport+0x1b;
+ j=inb(tmport) & 0x0e;
+ outb(j,tmport);
+ }
+ tmport=wkport+0x18;
+ outb(0x08,tmport);
+ tmport += 0x07;
+ j=0;
+rd_inq_data:
+ k=inb(tmport);
+ if ((k & 0x01) != 0 )
+ {
+ tmport-=0x06;
+ mbuf[j++]=inb(tmport);
+ tmport+=0x06;
+ goto rd_inq_data;
+ }
+ if ((k & 0x80) == 0 )
+ {
+ goto rd_inq_data;
+ }
+ tmport-=0x08;
+ j=inb(tmport);
+ if ( j == 0x16 )
+ {
+ goto inq_ok;
+ }
+ tmport=wkport+0x10;
+ outb(0x46,tmport);
+ tmport+=0x02;
+ outb(0,tmport++);
+ outb(0,tmport++);
+ outb(0,tmport++);
+ tmport+=0x03;
+ outb(0x08,tmport);
+ tmport+=0x07;
+ while ((inb(tmport) & 0x80) == 0x00);
+ tmport-=0x08;
+ if (inb(tmport) != 0x16)
+ {
+ goto sel_ok;
+ }
+inq_ok:
+ mbuf[36]=0;
+ printk(" ID: %2d %s\n",i,&mbuf[8]);
+ devtypeu[host][i]=mbuf[0];
+ rmb=mbuf[1];
+ if ( chip_veru[host] != 4 )
+ {
+ goto not_wide;
+ }
+ if ((mbuf[7] & 0x60) == 0)
+ {
+ goto not_wide;
+ }
+ if ((global_map[host] & 0x20) == 0)
+ {
+ goto not_wide;
+ }
+ tmport=wkport+0x1b;
+ j=(inb(tmport) & 0x0e) | 0x01;
+ outb(j,tmport);
+ tmport=wkport+3;
+ outb(satn[0],tmport++);
+ outb(satn[1],tmport++);
+ outb(satn[2],tmport++);
+ outb(satn[3],tmport++);
+ outb(satn[4],tmport++);
+ outb(satn[5],tmport++);
+ tmport+=0x06;
+ outb(0,tmport);
+ tmport+=0x02;
+ outb(devspu[host][i],tmport++);
+ outb(0,tmport++);
+ outb(satn[6],tmport++);
+ outb(satn[7],tmport++);
+ tmport+=0x03;
+ outb(satn[8],tmport);
+ tmport+=0x07;
+
+ while ((inb(tmport) & 0x80) == 0x00);
+ tmport-=0x08;
+ if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e))
+ {
+ continue;
+ }
+ while ( inb(tmport) != 0x8e );
+try_wide:
+ j=0;
+ tmport=wkport+0x14;
+ outb(0x05,tmport);
+ tmport += 0x04;
+ outb(0x20,tmport);
+ tmport+=0x07;
+
+ while ((inb(tmport) & 0x80) == 0 )
+ {
+ if ((inb(tmport) & 0x01) != 0 )
+ {
+ tmport-=0x06;
+ outb(wide[j++],tmport);
+ tmport+=0x06;
+ }
+ }
+ tmport-=0x08;
+ while ((inb(tmport) & 0x80) == 0x00);
+ j=inb(tmport) & 0x0f;
+ if ( j == 0x0f )
+ {
+ goto widep_in;
+ }
+ if ( j == 0x0a )
+ {
+ goto widep_cmd;
+ }
+ if ( j == 0x0e )
+ {
+ goto try_wide;
+ }
+ continue;
+widep_out:
+ tmport=wkport+0x18;
+ outb(0x20,tmport);
+ tmport+=0x07;
+ while ((inb(tmport) & 0x80) == 0 )
+ {
+ if ((inb(tmport) & 0x01) != 0 )
+ {
+ tmport-=0x06;
+ outb(0,tmport);
+ tmport+=0x06;
+ }
+ }
+ tmport-=0x08;
+ j=inb(tmport) & 0x0f;
+ if ( j == 0x0f )
+ {
+ goto widep_in;
+ }
+ if ( j == 0x0a )
+ {
+ goto widep_cmd;
+ }
+ if ( j == 0x0e )
+ {
+ goto widep_out;
+ }
+ continue;
+widep_in:
+ tmport=wkport+0x14;
+ outb(0xff,tmport);
+ tmport += 0x04;
+ outb(0x20,tmport);
+ tmport+=0x07;
+ k=0;
+widep_in1:
+ j=inb(tmport);
+ if ((j & 0x01) != 0)
+ {
+ tmport-=0x06;
+ mbuf[k++]=inb(tmport);
+ tmport+=0x06;
+ goto widep_in1;
+ }
+ if ((j & 0x80) == 0x00)
+ {
+ goto widep_in1;
+ }
+ tmport-=0x08;
+ j=inb(tmport) & 0x0f;
+ if ( j == 0x0f )
+ {
+ goto widep_in;
+ }
+ if ( j == 0x0a )
+ {
+ goto widep_cmd;
+ }
+ if ( j == 0x0e )
+ {
+ goto widep_out;
+ }
+ continue;
+widep_cmd:
+ tmport=wkport+0x10;
+ outb(0x30,tmport);
+ tmport=wkport+0x14;
+ outb(0x00,tmport);
+ tmport+=0x04;
+ outb(0x08,tmport);
+ tmport+=0x07;
+ while ((inb(tmport) & 0x80) == 0x00);
+ tmport-=0x08;
+ j=inb(tmport);
+ if ( j != 0x16 )
+ {
+ if ( j == 0x4e )


SHAR_EOF
true || echo 'restore of patch-2.0.37 failed'
fi

echo 'End of part 22'
echo 'File patch-2.0.37 is continued in part 23'
echo 23 > _shar_seq_.tmp
exit 0

Thomas...@ciw.uni-karlsruhe.de

unread,
Jun 16, 1999, 3:00:00 AM6/16/99
to
Archive-name: v2.0/patch-2.0.37/part26

#!/bin/sh
# this is part 26 of a 45 - part archive


# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.0.37 continued
if test ! -r _shar_seq_.tmp; then
echo 'Please unpack part 1 first!'
exit 1
fi
(read Scheck

if test "$Scheck" != 26; then


echo Please unpack part "$Scheck" next!
exit 1
else
exit 0
fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.0.37'
else
echo 'x - continuing with patch-2.0.37'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.0.37' &&

+#define TUL_SStatus0 0x85 /* 05 R Status 0 */
+#define TUL_SCtrl1 0x86 /* 06 W Control 1 */
+#define TUL_SStatus1 0x86 /* 06 R Status 1 */
+#define TUL_SConfig 0x87 /* 07 W Configuration */
+#define TUL_SStatus2 0x87 /* 07 R Status 2 */
+#define TUL_SPeriod 0x88 /* 08 W Sync. Transfer Period & Offset */
+#define TUL_SOffset 0x88 /* 08 R Offset */
+#define TUL_SScsiId 0x89 /* 09 W SCSI ID */
+#define TUL_SBusId 0x89 /* 09 R SCSI BUS ID */
+#define TUL_STimeOut 0x8A /* 0A W Sel/Resel Time Out Register */
+#define TUL_SIdent 0x8A /* 0A R Identify Message Register */
+#define TUL_SAvail 0x8A /* 0A R Availiable Counter Register */
+#define TUL_SData 0x8B /* 0B R/W SCSI data in/out */
+#define TUL_SFifo 0x8C /* 0C R/W FIFO */
+#define TUL_SSignal 0x90 /* 10 R/W SCSI signal in/out */
+#define TUL_SCmd 0x91 /* 11 R/W Command */
+#define TUL_STest0 0x92 /* 12 R/W Test0 */
+#define TUL_STest1 0x93 /* 13 R/W Test1 */
+#define TUL_SCFG1 0x94 /* 14 R/W Configuration */
+
+#define TUL_XAddH 0xC0 /*DMA Transfer Physical Address */
+#define TUL_XAddW 0xC8 /*DMA Current Transfer Physical Address */
+#define TUL_XCntH 0xD0 /*DMA Transfer Counter */
+#define TUL_XCntW 0xD4 /*DMA Current Transfer Counter */
+#define TUL_XCmd 0xD8 /*DMA Command Register */
+#define TUL_Int 0xDC /*Interrupt Register */
+#define TUL_XStatus 0xDD /*DMA status Register */
+#define TUL_Mask 0xE0 /*Interrupt Mask Register */
+#define TUL_XCtrl 0xE4 /*DMA Control Register */
+#define TUL_XCtrl1 0xE5 /*DMA Control Register 1 */
+#define TUL_XFifo 0xE8 /*DMA FIFO */
+
+#define TUL_WCtrl 0xF7 /*Bus master wait state control */
+#define TUL_DCtrl 0xFB /*DMA delay control */
+
+/*----------------------------------------------------------------------*/
+/* bit definition for Command register of Configuration Space Header */
+/*----------------------------------------------------------------------*/
+#define BUSMS 0x04 /* BUS MASTER Enable */
+#define IOSPA 0x01 /* IO Space Enable */
+
+/*----------------------------------------------------------------------*/
+/* Command Codes of Tulip SCSI Command register */
+/*----------------------------------------------------------------------*/
+#define TSC_EN_RESEL 0x80 /* Enable Reselection */
+#define TSC_CMD_COMP 0x84 /* Command Complete Sequence */
+#define TSC_SEL 0x01 /* Select Without ATN Sequence */
+#define TSC_SEL_ATN 0x11 /* Select With ATN Sequence */
+#define TSC_SEL_ATN_DMA 0x51 /* Select With ATN Sequence with DMA */
+#define TSC_SEL_ATN3 0x31 /* Select With ATN3 Sequence */
+#define TSC_SEL_ATNSTOP 0x12 /* Select With ATN and Stop Sequence */
+#define TSC_SELATNSTOP 0x1E /* Select With ATN and Stop Sequence */
+
+#define TSC_SEL_ATN_DIRECT_IN 0x95 /* Select With ATN Sequence */
+#define TSC_SEL_ATN_DIRECT_OUT 0x15 /* Select With ATN Sequence */
+#define TSC_SEL_ATN3_DIRECT_IN 0xB5 /* Select With ATN3 Sequence */
+#define TSC_SEL_ATN3_DIRECT_OUT 0x35 /* Select With ATN3 Sequence */
+#define TSC_XF_DMA_OUT_DIRECT 0x06 /* DMA Xfer Infomation out */
+#define TSC_XF_DMA_IN_DIRECT 0x86 /* DMA Xfer Infomation in */
+
+#define TSC_XF_DMA_OUT 0x43 /* DMA Xfer Infomation out */
+#define TSC_XF_DMA_IN 0xC3 /* DMA Xfer Infomation in */
+#define TSC_XF_FIFO_OUT 0x03 /* FIFO Xfer Infomation out */
+#define TSC_XF_FIFO_IN 0x83 /* FIFO Xfer Infomation in */
+
+#define TSC_MSG_ACCEPT 0x0F /* Message Accept */
+
+/*----------------------------------------------------------------------*/
+/* bit definition for Tulip SCSI Control 0 Register */
+/*----------------------------------------------------------------------*/
+#define TSC_RST_SEQ 0x20 /* Reset sequence counter */
+#define TSC_FLUSH_FIFO 0x10 /* Flush FIFO */
+#define TSC_ABT_CMD 0x04 /* Abort command (sequence) */
+#define TSC_RST_CHIP 0x02 /* Reset SCSI Chip */
+#define TSC_RST_BUS 0x01 /* Reset SCSI Bus */
+
+/*----------------------------------------------------------------------*/
+/* bit definition for Tulip SCSI Control 1 Register */
+/*----------------------------------------------------------------------*/
+#define TSC_EN_SCAM 0x80 /* Enable SCAM */
+#define TSC_TIMER 0x40 /* Select timeout unit */
+#define TSC_EN_SCSI2 0x20 /* SCSI-2 mode */
+#define TSC_PWDN 0x10 /* Power down mode */
+#define TSC_WIDE_CPU 0x08 /* Wide CPU */
+#define TSC_HW_RESELECT 0x04 /* Enable HW reselect */
+#define TSC_EN_BUS_OUT 0x02 /* Enable SCSI data bus out latch */
+#define TSC_EN_BUS_IN 0x01 /* Enable SCSI data bus in latch */
+
+/*----------------------------------------------------------------------*/
+/* bit definition for Tulip SCSI Configuration Register */
+/*----------------------------------------------------------------------*/
+#define TSC_EN_LATCH 0x80 /* Enable phase latch */
+#define TSC_INITIATOR 0x40 /* Initiator mode */
+#define TSC_EN_SCSI_PAR 0x20 /* Enable SCSI parity */
+#define TSC_DMA_8BIT 0x10 /* Alternate dma 8-bits mode */
+#define TSC_DMA_16BIT 0x08 /* Alternate dma 16-bits mode */
+#define TSC_EN_WDACK 0x04 /* Enable DACK while wide SCSI xfer */
+#define TSC_ALT_PERIOD 0x02 /* Alternate sync period mode */
+#define TSC_DIS_SCSIRST 0x01 /* Disable SCSI bus reset us */
+
+#define TSC_INITDEFAULT (TSC_INITIATOR | TSC_EN_LATCH | TSC_ALT_PERIOD | TSC_DIS_SCSIRST)
+
+#define TSC_WIDE_SCSI 0x80 /* Enable Wide SCSI */
+
+/*----------------------------------------------------------------------*/
+/* bit definition for Tulip SCSI signal Register */
+/*----------------------------------------------------------------------*/
+#define TSC_RST_ACK 0x00 /* Release ACK signal */
+#define TSC_RST_ATN 0x00 /* Release ATN signal */
+#define TSC_RST_BSY 0x00 /* Release BSY signal */
+
+#define TSC_SET_ACK 0x40 /* ACK signal */
+#define TSC_SET_ATN 0x08 /* ATN signal */
+
+#define TSC_REQI 0x80 /* REQ signal */
+#define TSC_ACKI 0x40 /* ACK signal */
+#define TSC_BSYI 0x20 /* BSY signal */
+#define TSC_SELI 0x10 /* SEL signal */
+#define TSC_ATNI 0x08 /* ATN signal */
+#define TSC_MSGI 0x04 /* MSG signal */
+#define TSC_CDI 0x02 /* C/D signal */
+#define TSC_IOI 0x01 /* I/O signal */
+
+
+/*----------------------------------------------------------------------*/
+/* bit definition for Tulip SCSI Status 0 Register */
+/*----------------------------------------------------------------------*/
+#define TSS_INT_PENDING 0x80 /* Interrupt pending */
+#define TSS_SEQ_ACTIVE 0x40 /* Sequencer active */
+#define TSS_XFER_CNT 0x20 /* Transfer counter zero */
+#define TSS_FIFO_EMPTY 0x10 /* FIFO empty */
+#define TSS_PAR_ERROR 0x08 /* SCSI parity error */
+#define TSS_PH_MASK 0x07 /* SCSI phase mask */
+
+/*----------------------------------------------------------------------*/
+/* bit definition for Tulip SCSI Status 1 Register */
+/*----------------------------------------------------------------------*/
+#define TSS_STATUS_RCV 0x08 /* Status received */
+#define TSS_MSG_SEND 0x40 /* Message sent */
+#define TSS_CMD_PH_CMP 0x20 /* command phase done */
+#define TSS_DATA_PH_CMP 0x10 /* Data phase done */
+#define TSS_STATUS_SEND 0x08 /* Status sent */
+#define TSS_XFER_CMP 0x04 /* Transfer completed */
+#define TSS_SEL_CMP 0x02 /* Selection completed */
+#define TSS_ARB_CMP 0x01 /* Arbitration completed */
+
+/*----------------------------------------------------------------------*/
+/* bit definition for Tulip SCSI Status 2 Register */
+/*----------------------------------------------------------------------*/
+#define TSS_CMD_ABTED 0x80 /* Command aborted */
+#define TSS_OFFSET_0 0x40 /* Offset counter zero */
+#define TSS_FIFO_FULL 0x20 /* FIFO full */
+#define TSS_TIMEOUT_0 0x10 /* Timeout counter zero */
+#define TSS_BUSY_RLS 0x08 /* Busy release */
+#define TSS_PH_MISMATCH 0x04 /* Phase mismatch */
+#define TSS_SCSI_BUS_EN 0x02 /* SCSI data bus enable */
+#define TSS_SCSIRST 0x01 /* SCSI bus reset in progress */
+
+/*----------------------------------------------------------------------*/
+/* bit definition for Tulip SCSI Interrupt Register */
+/*----------------------------------------------------------------------*/
+#define TSS_RESEL_INT 0x80 /* Reselected interrupt */
+#define TSS_SEL_TIMEOUT 0x40 /* Selected/reselected timeout */
+#define TSS_BUS_SERV 0x20
+#define TSS_SCSIRST_INT 0x10 /* SCSI bus reset detected */
+#define TSS_DISC_INT 0x08 /* Disconnected interrupt */
+#define TSS_SEL_INT 0x04 /* Select interrupt */
+#define TSS_SCAM_SEL 0x02 /* SCAM selected */
+#define TSS_FUNC_COMP 0x01
+
+/*----------------------------------------------------------------------*/
+/* SCSI Phase Codes. */
+/*----------------------------------------------------------------------*/
+#define DATA_OUT 0
+#define DATA_IN 1 /* 4 */
+#define CMD_OUT 2
+#define STATUS_IN 3 /* 6 */
+#define MSG_OUT 6 /* 3 */
+#define MSG_IN 7
+
+
+
+/*----------------------------------------------------------------------*/
+/* Command Codes of Tulip xfer Command register */
+/*----------------------------------------------------------------------*/
+#define TAX_X_FORC 0x02
+#define TAX_X_ABT 0x04
+#define TAX_X_CLR_FIFO 0x08
+
+#define TAX_X_IN 0x21
+#define TAX_X_OUT 0x01
+#define TAX_SG_IN 0xA1
+#define TAX_SG_OUT 0x81
+
+/*----------------------------------------------------------------------*/
+/* Tulip Interrupt Register */
+/*----------------------------------------------------------------------*/
+#define XCMP 0x01
+#define FCMP 0x02
+#define XABT 0x04
+#define XERR 0x08
+#define SCMP 0x10
+#define IPEND 0x80
+
+/*----------------------------------------------------------------------*/
+/* Tulip DMA Status Register */
+/*----------------------------------------------------------------------*/
+#define XPEND 0x01 /* Transfer pending */
+#define FEMPTY 0x02 /* FIFO empty */
+
+
+
+/*----------------------------------------------------------------------*/
+/* bit definition for TUL_GCTRL */
+/*----------------------------------------------------------------------*/
+#define EXTSG 0x80
+#define EXTAD 0x60
+#define SEG4K 0x08
+#define EEPRG 0x04
+#define MRMUL 0x02
+
+/*----------------------------------------------------------------------*/
+/* bit definition for TUL_NVRAM */
+/*----------------------------------------------------------------------*/
+#define SE2CS 0x08
+#define SE2CLK 0x04
+#define SE2DO 0x02
+#define SE2DI 0x01
+
+
+/************************************************************************/
+/* Scatter-Gather Element Structure */
+/************************************************************************/
+typedef struct SG_Struc {
+ U32 SG_Ptr; /* Data Pointer */
+ U32 SG_Len; /* Data Length */
+} SG;
+
+/***********************************************************************
+ SCSI Control Block
+************************************************************************/
+typedef struct Scsi_Ctrl_Blk {
+ struct Scsi_Ctrl_Blk *SCB_NxtScb;
+ UBYTE SCB_Status; /*4 */
+ UBYTE SCB_NxtStat; /*5 */
+ UBYTE SCB_Mode; /*6 */
+ UBYTE SCB_Msgin; /*7 SCB_Res0 */
+ UWORD SCB_SGIdx; /*8 */
+ UWORD SCB_SGMax; /*A */
+#ifdef ALPHA
+ U32 SCB_Reserved[2]; /*C */
+#else
+ U32 SCB_Reserved[3]; /*C */
+#endif
+
+ U32 SCB_XferLen; /*18 Current xfer len */
+ U32 SCB_TotXLen; /*1C Total xfer len */
+ U32 SCB_PAddr; /*20 SCB phy. Addr. */
+
+ UBYTE SCB_Opcode; /*24 SCB command code */
+ UBYTE SCB_Flags; /*25 SCB Flags */
+ UBYTE SCB_Target; /*26 Target Id */
+ UBYTE SCB_Lun; /*27 Lun */
+ U32 SCB_BufPtr; /*28 Data Buffer Pointer */
+ U32 SCB_BufLen; /*2C Data Allocation Length */
+ UBYTE SCB_SGLen; /*30 SG list # */
+ UBYTE SCB_SenseLen; /*31 Sense Allocation Length */
+ UBYTE SCB_HaStat; /*32 */
+ UBYTE SCB_TaStat; /*33 */
+ UBYTE SCB_CDBLen; /*34 CDB Length */
+ UBYTE SCB_Ident; /*35 Identify */
+ UBYTE SCB_TagMsg; /*36 Tag Message */
+ UBYTE SCB_TagId; /*37 Queue Tag */
+ UBYTE SCB_CDB[12]; /*38 */
+ U32 SCB_SGPAddr; /*44 SG List/Sense Buf phy. Addr. */
+ U32 SCB_SensePtr; /*48 Sense data pointer */
+ void (*SCB_Post) (BYTE *, BYTE *); /*4C POST routine */
+ unsigned char *SCB_Srb; /*50 SRB Pointer */
+ SG SCB_SGList[TOTAL_SG_ENTRY]; /*54 Start of SG list */
+} SCB;
+
+/* Bit Definition for SCB_Status */
+#define SCB_RENT 0x01
+#define SCB_PEND 0x02
+#define SCB_CONTIG 0x04 /* Contigent Allegiance */
+#define SCB_SELECT 0x08
+#define SCB_BUSY 0x10
+#define SCB_DONE 0x20
+
+
+/* Opcodes of SCB_Opcode */
+#define ExecSCSI 0x1
+#define BusDevRst 0x2
+#define AbortCmd 0x3
+
+
+/* Bit Definition for SCB_Mode */
+#define SCM_RSENS 0x01 /* request sense mode */
+
+
+/* Bit Definition for SCB_Flags */
+#define SCF_DONE 0x01
+#define SCF_POST 0x02
+#define SCF_SENSE 0x04
+#define SCF_DIR 0x18
+#define SCF_NO_DCHK 0x00
+#define SCF_DIN 0x08
+#define SCF_DOUT 0x10
+#define SCF_NO_XF 0x18
+#define SCF_WR_VF 0x20 /* Write verify turn on */
+#define SCF_POLL 0x40
+#define SCF_SG 0x80
+
+/* Error Codes for SCB_HaStat */
+#define HOST_SEL_TOUT 0x11
+#define HOST_DO_DU 0x12
+#define HOST_BUS_FREE 0x13
+#define HOST_BAD_PHAS 0x14
+#define HOST_INV_CMD 0x16
+#define HOST_ABORTED 0x1A /* 07/21/98 */
+#define HOST_SCSI_RST 0x1B
+#define HOST_DEV_RST 0x1C
+
+/* Error Codes for SCB_TaStat */
+#define TARGET_CHKCOND 0x02
+#define TARGET_BUSY 0x08
+#define QUEUE_FULL 0x28
+
+/* SCSI MESSAGE */
+#define MSG_COMP 0x00
+#define MSG_EXTEND 0x01
+#define MSG_SDP 0x02
+#define MSG_RESTORE 0x03
+#define MSG_DISC 0x04
+#define MSG_IDE 0x05
+#define MSG_ABORT 0x06
+#define MSG_REJ 0x07
+#define MSG_NOP 0x08
+#define MSG_PARITY 0x09
+#define MSG_LINK_COMP 0x0A
+#define MSG_LINK_FLAG 0x0B
+#define MSG_DEVRST 0x0C
+#define MSG_ABORT_TAG 0x0D
+
+/* Queue tag msg: Simple_quque_tag, Head_of_queue_tag, Ordered_queue_tag */
+#define MSG_STAG 0x20
+#define MSG_HTAG 0x21
+#define MSG_OTAG 0x22
+
+#define MSG_IGNOREWIDE 0x23
+
+#define MSG_IDENT 0x80
+
+/***********************************************************************
+ Target Device Control Structure
+**********************************************************************/
+
+typedef struct Tar_Ctrl_Struc {
+ UWORD TCS_Flags; /* 0 */
+ UBYTE TCS_JS_Period; /* 2 */
+ UBYTE TCS_SConfig0; /* 3 */
+
+ UWORD TCS_DrvFlags; /* 4 */
+ UBYTE TCS_DrvHead; /* 6 */
+ UBYTE TCS_DrvSector; /* 7 */
+} TCS;
+
+/***********************************************************************
+ Target Device Control Structure
+**********************************************************************/
+
+/* Bit Definition for TCF_Flags */
+#define TCF_SCSI_RATE 0x0007
+#define TCF_EN_DISC 0x0008
+#define TCF_NO_SYNC_NEGO 0x0010
+#define TCF_NO_WDTR 0x0020
+#define TCF_EN_255 0x0040
+#define TCF_EN_START 0x0080
+#define TCF_WDTR_DONE 0x0100
+#define TCF_SYNC_DONE 0x0200
+#define TCF_BUSY 0x0400
+
+
+/* Bit Definition for TCF_DrvFlags */
+#define TCF_DRV_BUSY 0x01 /* Indicate target busy(driver) */
+#define TCF_DRV_EN_TAG 0x0800
+#define TCF_DRV_255_63 0x0400
+
+typedef struct I91u_Adpt_Struc {
+ UWORD ADPT_BIOS; /* 0 */
+ UWORD ADPT_BASE; /* 1 */
+ UBYTE ADPT_Bus; /* 2 */
+ UBYTE ADPT_Device; /* 3 */
+ UBYTE ADPT_INTR; /* 4 */
+} INI_ADPT_STRUCT;
+
+
+/***********************************************************************
+ Host Adapter Control Structure
+************************************************************************/
+typedef struct Ha_Ctrl_Struc {
+ UWORD HCS_Base; /* 00 */
+ UWORD HCS_BIOS; /* 02 */
+ UBYTE HCS_Intr; /* 04 */
+ UBYTE HCS_SCSI_ID; /* 05 */
+ UBYTE HCS_MaxTar; /* 06 */
+ UBYTE HCS_NumScbs; /* 07 */
+
+ UBYTE HCS_Flags; /* 08 */
+ UBYTE HCS_Index; /* 09 */
+ UBYTE HCS_HaId; /* 0A */
+ UBYTE HCS_Config; /* 0B */
+ UWORD HCS_IdMask; /* 0C */
+ UBYTE HCS_Semaph; /* 0E */
+ UBYTE HCS_Phase; /* 0F */
+ UBYTE HCS_JSStatus0; /* 10 */
+ UBYTE HCS_JSInt; /* 11 */
+ UBYTE HCS_JSStatus1; /* 12 */
+ UBYTE HCS_SConf1; /* 13 */
+
+ UBYTE HCS_Msg[8]; /* 14 */
+ SCB *HCS_NxtAvail; /* 1C */
+ SCB *HCS_Scb; /* 20 */
+ SCB *HCS_ScbEnd; /* 24 */
+ SCB *HCS_NxtPend; /* 28 */
+ SCB *HCS_NxtContig; /* 2C */
+ SCB *HCS_ActScb; /* 30 */
+ TCS *HCS_ActTcs; /* 34 */
+
+ SCB *HCS_FirstAvail; /* 38 */
+ SCB *HCS_LastAvail; /* 3C */
+ SCB *HCS_FirstPend; /* 40 */
+ SCB *HCS_LastPend; /* 44 */
+ SCB *HCS_FirstBusy; /* 48 */
+ SCB *HCS_LastBusy; /* 4C */
+ SCB *HCS_FirstDone; /* 50 */
+ SCB *HCS_LastDone; /* 54 */
+ UBYTE HCS_MaxTags[16]; /* 58 */
+ UBYTE HCS_ActTags[16]; /* 68 */
+ TCS HCS_Tcs[MAX_TARGETS]; /* 78 */
+ ULONG pSRB_head; /* SRB save queue header */
+ ULONG pSRB_tail; /* SRB save queue tail */
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+ spinlock_t HCS_AvailLock;
+ spinlock_t HCS_SemaphLock;
+ spinlock_t pSRB_lock; /* SRB queue lock */
+#endif
+} HCS;
+
+/* Bit Definition for HCB_Config */
+#define HCC_SCSI_RESET 0x01
+#define HCC_EN_PAR 0x02
+#define HCC_ACT_TERM1 0x04
+#define HCC_ACT_TERM2 0x08
+#define HCC_AUTO_TERM 0x10
+#define HCC_EN_PWR 0x80
+
+/* Bit Definition for HCB_Flags */
+#define HCF_EXPECT_DISC 0x01
+#define HCF_EXPECT_SELECT 0x02
+#define HCF_EXPECT_RESET 0x10
+#define HCF_EXPECT_DONE_DISC 0x20
+
+/******************************************************************
+ Serial EEProm
+*******************************************************************/
+
+typedef struct _NVRAM_SCSI { /* SCSI channel configuration */
+ UCHAR NVM_ChSCSIID; /* 0Ch -> Channel SCSI ID */
+ UCHAR NVM_ChConfig1; /* 0Dh -> Channel config 1 */
+ UCHAR NVM_ChConfig2; /* 0Eh -> Channel config 2 */
+ UCHAR NVM_NumOfTarg; /* 0Fh -> Number of SCSI target */
+ /* SCSI target configuration */
+ UCHAR NVM_Targ0Config; /* 10h -> Target 0 configuration */
+ UCHAR NVM_Targ1Config; /* 11h -> Target 1 configuration */
+ UCHAR NVM_Targ2Config; /* 12h -> Target 2 configuration */
+ UCHAR NVM_Targ3Config; /* 13h -> Target 3 configuration */
+ UCHAR NVM_Targ4Config; /* 14h -> Target 4 configuration */
+ UCHAR NVM_Targ5Config; /* 15h -> Target 5 configuration */
+ UCHAR NVM_Targ6Config; /* 16h -> Target 6 configuration */
+ UCHAR NVM_Targ7Config; /* 17h -> Target 7 configuration */
+ UCHAR NVM_Targ8Config; /* 18h -> Target 8 configuration */
+ UCHAR NVM_Targ9Config; /* 19h -> Target 9 configuration */
+ UCHAR NVM_TargAConfig; /* 1Ah -> Target A configuration */
+ UCHAR NVM_TargBConfig; /* 1Bh -> Target B configuration */
+ UCHAR NVM_TargCConfig; /* 1Ch -> Target C configuration */
+ UCHAR NVM_TargDConfig; /* 1Dh -> Target D configuration */
+ UCHAR NVM_TargEConfig; /* 1Eh -> Target E configuration */
+ UCHAR NVM_TargFConfig; /* 1Fh -> Target F configuration */
+} NVRAM_SCSI;
+
+typedef struct _NVRAM {
+/*----------header ---------------*/
+ USHORT NVM_Signature; /* 0,1: Signature */
+ UCHAR NVM_Size; /* 2: Size of data structure */
+ UCHAR NVM_Revision; /* 3: Revision of data structure */
+ /* ----Host Adapter Structure ---- */
+ UCHAR NVM_ModelByte0; /* 4: Model number (byte 0) */
+ UCHAR NVM_ModelByte1; /* 5: Model number (byte 1) */
+ UCHAR NVM_ModelInfo; /* 6: Model information */
+ UCHAR NVM_NumOfCh; /* 7: Number of SCSI channel */
+ UCHAR NVM_BIOSConfig1; /* 8: BIOS configuration 1 */
+ UCHAR NVM_BIOSConfig2; /* 9: BIOS configuration 2 */
+ UCHAR NVM_HAConfig1; /* A: Hoat adapter configuration 1 */
+ UCHAR NVM_HAConfig2; /* B: Hoat adapter configuration 2 */
+ NVRAM_SCSI NVM_SCSIInfo[2];
+ UCHAR NVM_reserved[10];
+ /* ---------- CheckSum ---------- */
+ USHORT NVM_CheckSum; /* 0x3E, 0x3F: Checksum of NVRam */
+} NVRAM, *PNVRAM;
+
+/* Bios Configuration for nvram->BIOSConfig1 */
+#define NBC1_ENABLE 0x01 /* BIOS enable */
+#define NBC1_8DRIVE 0x02 /* Support more than 2 drives */
+#define NBC1_REMOVABLE 0x04 /* Support removable drive */
+#define NBC1_INT19 0x08 /* Intercept int 19h */
+#define NBC1_BIOSSCAN 0x10 /* Dynamic BIOS scan */
+#define NBC1_LUNSUPPORT 0x40 /* Support LUN */
+
+/* HA Configuration Byte 1 */
+#define NHC1_BOOTIDMASK 0x0F /* Boot ID number */
+#define NHC1_LUNMASK 0x70 /* Boot LUN number */
+#define NHC1_CHANMASK 0x80 /* Boot Channel number */
+
+/* Bit definition for nvram->SCSIconfig1 */
+#define NCC1_BUSRESET 0x01 /* Reset SCSI bus at power up */
+#define NCC1_PARITYCHK 0x02 /* SCSI parity enable */
+#define NCC1_ACTTERM1 0x04 /* Enable active terminator 1 */
+#define NCC1_ACTTERM2 0x08 /* Enable active terminator 2 */
+#define NCC1_AUTOTERM 0x10 /* Enable auto terminator */
+#define NCC1_PWRMGR 0x80 /* Enable power management */
+
+/* Bit definition for SCSI Target configuration byte */
+#define NTC_DISCONNECT 0x08 /* Enable SCSI disconnect */
+#define NTC_SYNC 0x10 /* SYNC_NEGO */
+#define NTC_NO_WDTR 0x20 /* SYNC_NEGO */
+#define NTC_1GIGA 0x40 /* 255 head / 63 sectors (64/32) */
+#define NTC_SPINUP 0x80 /* Start disk drive */
+
+/* Default NVRam values */
+#define INI_SIGNATURE 0xC925
+#define NBC1_DEFAULT (NBC1_ENABLE)
+#define NCC1_DEFAULT (NCC1_BUSRESET | NCC1_AUTOTERM | NCC1_PARITYCHK)
+#define NTC_DEFAULT (NTC_NO_WDTR | NTC_1GIGA | NTC_DISCONNECT)
+
+/* SCSI related definition */
+#define DISC_NOT_ALLOW 0x80 /* Disconnect is not allowed */
+#define DISC_ALLOW 0xC0 /* Disconnect is allowed */
+#define SCSICMD_RequestSense 0x03
+
+
+/*----------------------------------------------------------------------*/
+/* PCI */
+/*----------------------------------------------------------------------*/
+#define PCI_FUNCTION_ID 0xB1
+#define PCI_BIOS_PRESENT 0x01
+#define FIND_PCI_DEVICE 0x02
+#define FIND_PCI_CLASS_CODE 0x03
+#define GENERATE_SPECIAL_CYCLE 0x06
+#define READ_CONFIG_BYTE 0x08
+#define READ_CONFIG_WORD 0x09
+#define READ_CONFIG_DWORD 0x0A
+#define WRITE_CONFIG_BYTE 0x0B
+#define WRITE_CONFIG_WORD 0x0C
+#define WRITE_CONFIG_DWORD 0x0D
+
+#define SUCCESSFUL 0x00
+#define FUNC_NOT_SUPPORTED 0x81
+#define BAD_VENDOR_ID 0x83 /* Bad vendor ID */
+#define DEVICE_NOT_FOUND 0x86 /* PCI device not found */
+#define BAD_REGISTER_NUMBER 0x87
+
+#define MAX_PCI_DEVICES 21 /* Maximum devices supportted */
+
+#define MAX_PCI_CHANL 4
+
+typedef struct _BIOS32_ENTRY_STRUCTURE {
+ DWORD Signatures; /* Should be "_32_" */
+ DWORD BIOS32Entry; /* 32-bit physical address */
+ BYTE Revision; /* Revision level, should be 0 */
+ BYTE Length; /* Multiply of 16, should be 1 */
+ BYTE CheckSum; /* Checksum of whole structure */
+ BYTE Reserved[5]; /* Reserved */
+} BIOS32_ENTRY_STRUCTURE, *PBIOS32_ENTRY_STRUCTURE;
+
+typedef struct {
+ union {
+ unsigned int eax;
+ struct {
+ unsigned short ax;
+ } word;
+ struct {
+ unsigned char al;
+ unsigned char ah;
+ } byte;
+ } eax;
+ union {
+ unsigned int ebx;
+ struct {
+ unsigned short bx;
+ } word;
+ struct {
+ unsigned char bl;
+ unsigned char bh;
+ } byte;
+ } ebx;
+ union {
+ unsigned int ecx;
+ struct {
+ unsigned short cx;
+ } word;
+ struct {
+ unsigned char cl;
+ unsigned char ch;
+ } byte;
+ } ecx;
+ union {
+ unsigned int edx;
+ struct {
+ unsigned short dx;
+ } word;
+ struct {
+ unsigned char dl;
+ unsigned char dh;
+ } byte;
+ } edx;
+ union {
+ unsigned int edi;
+ struct {
+ unsigned short di;
+ } word;
+ } edi;
+ union {
+ unsigned int esi;
+ struct {
+ unsigned short si;
+ } word;
+ } esi;
+} REGS;
+
+typedef union { /* Union define for mechanism 1 */
+ struct {
+ unsigned char RegNum;
+ unsigned char FcnNum:3;
+ unsigned char DeviceNum:5;
+ unsigned char BusNum;
+ unsigned char Reserved:7;
+ unsigned char Enable:1;
+ } sConfigAdr;
+ unsigned long lConfigAdr;
+} CONFIG_ADR;
+
+typedef union { /* Union define for mechanism 2 */
+ struct {
+ unsigned char RegNum;
+ unsigned char DeviceNum;
+ unsigned short Reserved;
+ } sHostAdr;
+ unsigned long lHostAdr;
+} HOST_ADR;
+
+typedef struct _HCSinfo {
+ ULONG base;
+ UCHAR vec;
+ UCHAR bios; /* High byte of BIOS address */
+ USHORT BaseAndBios; /* high byte: pHcsInfo->bios,low byte:pHcsInfo->base */
+} HCSINFO;
+
+#define TUL_RD(x,y) (UCHAR)(inb( (int)((ULONG)(x+y)) ))
+#define TUL_RDLONG(x,y) (ULONG)(inl((int)((ULONG)(x+y)) ))
+#define TUL_WR( adr,data) outb( (UCHAR)(data), (int)(adr))
+#define TUL_WRSHORT(adr,data) outw( (UWORD)(data), (int)(adr))
+#define TUL_WRLONG( adr,data) outl( (ULONG)(data), (int)(adr))
+
+#define SCSI_ABORT_SNOOZE 0
+#define SCSI_ABORT_SUCCESS 1
+#define SCSI_ABORT_PENDING 2
+#define SCSI_ABORT_BUSY 3
+#define SCSI_ABORT_NOT_RUNNING 4
+#define SCSI_ABORT_ERROR 5
+
+#define SCSI_RESET_SNOOZE 0
+#define SCSI_RESET_PUNT 1
+#define SCSI_RESET_SUCCESS 2
+#define SCSI_RESET_PENDING 3
+#define SCSI_RESET_WAKEUP 4
+#define SCSI_RESET_NOT_RUNNING 5
+#define SCSI_RESET_ERROR 6
+
+#define SCSI_RESET_SYNCHRONOUS 0x01
+#define SCSI_RESET_ASYNCHRONOUS 0x02
+#define SCSI_RESET_SUGGEST_BUS_RESET 0x04
+#define SCSI_RESET_SUGGEST_HOST_RESET 0x08
+
+#define SCSI_RESET_BUS_RESET 0x100
+#define SCSI_RESET_HOST_RESET 0x200
+#define SCSI_RESET_ACTION 0xff
diff -u --recursive --new-file v2.0.36/linux/drivers/scsi/ini9100u.c linux/drivers/scsi/ini9100u.c
--- v2.0.36/linux/drivers/scsi/ini9100u.c Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/ini9100u.c Sun Jun 13 10:21:02 1999
@@ -0,0 +1,1104 @@
+/**************************************************************************
+ * Initio 9100 device driver for Linux.
+ *
+ * Copyright (c) 1994-1998 Initio Corporation
+ * Copyright (c) 1998 Bas Vermeulen <bver...@blackstar.xs4all.nl>
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.


+ *
+ * You should have received a copy of the GNU General Public License

+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * --------------------------------------------------------------------------
+ *
+ * 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,
+ * without modification, immediately at the beginning of the file.
+ * 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.
+ *
+ * Where this Software is combined with software released under the terms of
+ * the GNU Public License ("GPL") and the terms of the GPL would require the
+ * combined work to also be released under the terms of the GPL, the terms
+ * and conditions of this License will apply in addition to those of the
+ * GPL with the exception of any terms or conditions of this License that
+ * conflict with, or are expressly prohibited by, the GPL.
+ *
+ * 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.
+ *
+ *************************************************************************
+ *
+ * DESCRIPTION:
+ *
+ * This is the Linux low-level SCSI driver for Initio INI-9X00U/UW SCSI host
+ * adapters
+ *
+ * 08/06/97 hc - v1.01h
+ * - Support inic-940 and inic-935
+ * 09/26/97 hc - v1.01i
+ * - Make correction from J.W. Schultz suggestion
+ * 10/13/97 hc - Support reset function
+ * 10/21/97 hc - v1.01j
+ * - Support 32 LUN (SCSI 3)
+ * 01/14/98 hc - v1.01k
+ * - Fix memory allocation problem
+ * 03/04/98 hc - v1.01l
+ * - Fix tape rewind which will hang the system problem
+ * - Set can_queue to tul_num_scb
+ * 06/25/98 hc - v1.01m
+ * - Get it work for kernel version >= 2.1.75
+ * - Dynamic assign SCSI bus reset holding time in init_tulip()
+ * 07/02/98 hc - v1.01n
+ * - Support 0002134A
+ * 08/07/98 hc - v1.01o
+ * - Change the tul_abort_srb routine to use scsi_done. <01>
+ * 09/07/98 hl - v1.02
+ * - Change the INI9100U define and proc_dir_entry to
+ * reflect the newer Kernel 2.1.118, but the v1.o1o
+ * should work with Kernel 2.1.118.
+ * 09/20/98 wh - v1.02a
+ * - Support Abort command.
+ * - Handle reset routine.
+ * 09/21/98 hl - v1.03
+ * - remove comments.
+ * 12/09/98 bv - v1.03a
+ * - Removed unused code
+ * 12/13/98 bv - v1.03b
+ * - Remove cli() locking for kernels >= 2.1.95. This uses
+ * spinlocks to serialize access to the pSRB_head and
+ * pSRB_tail members of the HCS structure.
+ * 09/01/99 bv - v1.03d
+ * - Fixed a deadlock problem in SMP.
+ * 21/01/99 bv - v1.03e
+ * - Add support for the Domex 3192U PCI SCSI
+ * This is a slightly modified patch by
+ * Brian Macy <bm...@sunshinecomputing.com>
+ * 22/02/99 bv - v1.03f
+ * - Didn't detect the INIC-950 in 2.0.x correctly.
+ * Now fixed.
+ **************************************************************************/
+
+#define CVT_LINUX_VERSION(V,P,S) (V * 65536 + P * 256 + S)
+
+#ifndef LINUX_VERSION_CODE
+#include <linux/version.h>
+#endif


+
+#ifdef MODULE
+#include <linux/module.h>

+#endif
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
+#include <stdarg.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#if LINUX_VERSION_CODE <= CVT_LINUX_VERSION(2,1,92)
+#include <linux/bios32.h>
+#endif
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/pci.h>
+#include <linux/proc_fs.h>
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,23)
+#include <linux/init.h>
+#endif
+#include <linux/blk.h>
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+#include <asm/spinlock.h>
+#endif
+#include "sd.h"
+#include "scsi.h"
+#include "hosts.h"
+#include "ini9100u.h"
+#include <linux/stat.h>
+#include <linux/malloc.h>
+#include <linux/config.h>
+
+#else


+
+#include <linux/kernel.h>
+#include <linux/head.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+

+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <asm/system.h>
+#include <asm/io.h>

+#include "../block/blk.h"
+#include "scsi.h"
+#include "sd.h"
+#include "hosts.h"
+#include <linux/malloc.h>
+#include "ini9100u.h"
+#endif
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,93)
+#ifdef CONFIG_PCI
+#include <linux/pci.h>
+#endif
+#endif
+
+#ifdef DEBUG_i91u
+unsigned int i91u_debug = DEBUG_DEFAULT;
+#endif
+
+#ifdef MODULE
+Scsi_Host_Template driver_template = INI9100U;
+#include "scsi_module.c"
+#endif
+
+char *i91uCopyright = "Copyright (C) 1996-98";
+char *i91uInitioName = "by Initio Corporation";
+char *i91uProductName = "INI-9X00U/UW";
+char *i91uVersion = "v1.03f";
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
+struct proc_dir_entry proc_scsi_ini9100u =
+{
+ PROC_SCSI_INI9100U, 7, "INI9100U",
+ S_IFDIR | S_IRUGO | S_IXUGO, 2,
+ 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+};
+#endif
+
+#define TULSZ(sz) (sizeof(sz) / sizeof(sz[0]))
+#define TUL_RDWORD(x,y) (short)(inl((int)((ULONG)((ULONG)x+(UCHAR)y)) ))
+
+/* set by i91_setup according to the command line */
+static int setup_called = 0;
+
+static int tul_num_ch = 4; /* Maximum 4 adapters */
+static int tul_num_scb;
+static int tul_tag_enable = 1;
+static SCB *tul_scb;
+
+#ifdef DEBUG_i91u
+static int setup_debug = 0;
+#endif
+
+static char *setup_str = (char *) NULL;
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
+static void i91u_intr0(int irq, void *dev_id, struct pt_regs *);
+static void i91u_intr1(int irq, void *dev_id, struct pt_regs *);
+static void i91u_intr2(int irq, void *dev_id, struct pt_regs *);
+static void i91u_intr3(int irq, void *dev_id, struct pt_regs *);
+static void i91u_intr4(int irq, void *dev_id, struct pt_regs *);
+static void i91u_intr5(int irq, void *dev_id, struct pt_regs *);
+static void i91u_intr6(int irq, void *dev_id, struct pt_regs *);
+static void i91u_intr7(int irq, void *dev_id, struct pt_regs *);
+#else
+static void i91u_intr0(int irq, struct pt_regs *);
+static void i91u_intr1(int irq, struct pt_regs *);
+static void i91u_intr2(int irq, struct pt_regs *);
+static void i91u_intr3(int irq, struct pt_regs *);
+static void i91u_intr4(int irq, struct pt_regs *);
+static void i91u_intr5(int irq, struct pt_regs *);
+static void i91u_intr6(int irq, struct pt_regs *);
+static void i91u_intr7(int irq, struct pt_regs *);
+#endif
+
+static void i91u_panic(char *msg);
+
+static void i91uSCBPost(BYTE * pHcb, BYTE * pScb);
+
+ /* ---- EXTERNAL FUNCTIONS ---- */
+ /* Get total number of adapters */
+extern void init_i91uAdapter_table(void);
+extern int Addi91u_into_Adapter_table(WORD, WORD, BYTE, BYTE, BYTE);
+extern int tul_ReturnNumberOfAdapters(void);
+extern void get_tulipPCIConfig(HCS * pHCB, int iChannel_index);
+extern int init_tulip(HCS * pHCB, SCB * pSCB, int tul_num_scb, BYTE * pbBiosAdr, int reset_time);
+extern SCB *tul_alloc_scb(HCS * pHCB);
+extern int tul_abort_srb(HCS * pHCB, Scsi_Cmnd * pSRB);
+extern void tul_exec_scb(HCS * pHCB, SCB * pSCB);
+extern void tul_release_scb(HCS * pHCB, SCB * pSCB);
+extern void tul_stop_bm(HCS * pHCB);
+extern int tul_reset_scsi(HCS * pCurHcb, int seconds);
+extern int tul_isr(HCS * pHCB);
+extern int tul_reset(HCS * pHCB, Scsi_Cmnd * pSRB, unsigned char target);
+extern int tul_reset_scsi_bus(HCS * pCurHcb);
+extern int tul_device_reset(HCS * pCurHcb, ULONG pSrb, unsigned int target, unsigned int ResetFlags);
+ /* ---- EXTERNAL VARIABLES ---- */
+extern HCS tul_hcs[];
+
+const PCI_ID i91u_pci_devices[] = {
+ { INI_VENDOR_ID, I950_DEVICE_ID },
+ { INI_VENDOR_ID, I940_DEVICE_ID },
+ { INI_VENDOR_ID, I935_DEVICE_ID },
+ { INI_VENDOR_ID, I920_DEVICE_ID },
+ { DMX_VENDOR_ID, I920_DEVICE_ID },
+};
+
+/*
+ * queue services:
+ */
+/*****************************************************************************
+ Function name : i91uAppendSRBToQueue
+ Description : This function will push current request into save list
+ Input : pSRB - Pointer to SCSI request block.
+ pHCB - Pointer to host adapter structure
+ Output : None.
+ Return : None.
+*****************************************************************************/
+static void i91uAppendSRBToQueue(HCS * pHCB, Scsi_Cmnd * pSRB)
+{
+ ULONG flags;
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+ spin_lock_irqsave(&(pHCB->pSRB_lock), flags);
+#else
+ save_flags(flags);
+ cli();
+#endif
+
+ pSRB->next = NULL; /* Pointer to next */
+
+ if (pHCB->pSRB_head == NULL)
+ pHCB->pSRB_head = pSRB;
+ else
+ pHCB->pSRB_tail->next = pSRB; /* Pointer to next */
+ pHCB->pSRB_tail = pSRB;
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+ spin_unlock_irqrestore(&(pHCB->pSRB_lock), flags);
+#else
+ restore_flags(flags);


+#endif
+ return;
+}
+

+/*****************************************************************************
+ Function name : i91uPopSRBFromQueue
+ Description : This function will pop current request from save list
+ Input : pHCB - Pointer to host adapter structure
+ Output : None.
+ Return : pSRB - Pointer to SCSI request block.
+*****************************************************************************/
+static Scsi_Cmnd *i91uPopSRBFromQueue(HCS * pHCB)
+{
+ Scsi_Cmnd *pSRB;
+ ULONG flags;
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+ spin_lock_irqsave(&(pHCB->pSRB_lock), flags);
+#else
+ save_flags(flags);
+ cli();
+#endif
+
+ if ((pSRB = pHCB->pSRB_head) != NULL) {
+ pHCB->pSRB_head = pHCB->pSRB_head->next;
+ pSRB->next = NULL;
+ }
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+ spin_unlock_irqrestore(&(pHCB->pSRB_lock), flags);
+#else
+ restore_flags(flags);
+#endif
+
+ return (pSRB);
+}
+
+/* called from init/main.c */
+
+void i91u_setup(char *str, int *ints)
+{
+ if (setup_called)
+ i91u_panic("i91u: i91u_setup called twice.\n");
+
+ setup_called = ints[0];
+ setup_str = str;
+
+#ifdef DEBUG_i91u
+ setup_debug = ints[0] >= 1 ? ints[1] : DEBUG_DEFAULT;
+#endif
+}
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,93)
+int tul_NewReturnNumberOfAdapters(void)
+{
+ struct pci_dev *pDev = NULL; /* Start from none */
+ int iAdapters = 0;
+ long dRegValue;
+ WORD wBIOS;
+ int i = 0;
+
+ init_i91uAdapter_table();
+
+ for (i = 0; i < TULSZ(i91u_pci_devices); i++)
+ {
+ while ((pDev = pci_find_device(i91u_pci_devices[i].vendor_id, i91u_pci_devices[i].device_id, pDev)) != NULL) {
+ pci_read_config_dword(pDev, 0x44, (u32 *) & dRegValue);
+ wBIOS = (UWORD) (dRegValue & 0xFF);
+ if (((dRegValue & 0xFF00) >> 8) == 0xFF)
+ dRegValue = 0;
+ wBIOS = (wBIOS << 8) + ((UWORD) ((dRegValue & 0xFF00) >> 8));
+ if (Addi91u_into_Adapter_table(wBIOS,
+ (pDev->base_address[0] & 0xFFFE),
+ pDev->irq,
+ pDev->bus->number,
+ (pDev->devfn >> 3)
+ ) == 0)
+ iAdapters++;
+ }
+ }
+
+ return (iAdapters);
+}
+
+#else /* <01> */
+
+/*****************************************************************************
+ Function name : tul_ReturnNumberOfAdapters
+ Description : This function will scan PCI bus to get all Orchid card
+ Input : None.
+ Output : None.
+ Return : SUCCESSFUL - Successful scan
+ ohterwise - No drives founded
+*****************************************************************************/
+int tul_ReturnNumberOfAdapters(void)
+{
+ unsigned int i, iAdapters;
+ unsigned int dRegValue;
+ unsigned short command;
+ WORD wBIOS, wBASE;
+ BYTE bPCIBusNum, bInterrupt, bPCIDeviceNum;
+
+ iAdapters = 0;
+ /*
+ * PCI-bus probe.
+ */
+ if (pcibios_present()) {
+#ifdef MMAPIO


+ unsigned long page_offset, base;

+#endif
+
+ int index;


+ unsigned char pci_bus, pci_devfn;

+
+ bPCIBusNum = 0;
+ bPCIDeviceNum = 0;
+ init_i91uAdapter_table();
+ for (i = 0; i < TULSZ(i91u_pci_devices); i++) {
+ index = 0;
+ while (!(pcibios_find_device(i91u_pci_devices[i].vendor_id,
+ i91u_pci_devices[i].device_id,
+ index++, &pci_bus, &pci_devfn)))
+ {
+ if (i == 2) {
+ printk("i91u: The RAID controller is not supported by\n");
+ printk("i91u: this driver, we are ignoring it.\n");
+ } else {
+ /*
+ * Read sundry information from PCI BIOS.
+ */
+ bPCIBusNum = pci_bus;
+ bPCIDeviceNum = pci_devfn;
+ pcibios_read_config_dword(pci_bus, pci_devfn, PCI_BASE_ADDRESS_0,
+ &dRegValue);
+ if (dRegValue == -1) { /* Check return code */
+ printk("\n\ri91u: tulip read configuration error.\n");
+ return (0); /* Read configuration space error */
+ }
+ /* <02> read from base address + 0x50 offset to get the wBIOS balue. */
+ wBASE = (WORD) dRegValue;
+
+ /* Now read the interrupt line */
+ pcibios_read_config_dword(pci_bus, pci_devfn, PCI_INTERRUPT_LINE,
+ &dRegValue);
+ bInterrupt = dRegValue & 0xFF; /* Assign interrupt line */
+ pcibios_read_config_word(pci_bus, pci_devfn, PCI_COMMAND, &command);
+ pcibios_write_config_word(pci_bus, pci_devfn, PCI_COMMAND,
+ command | PCI_COMMAND_MASTER | PCI_COMMAND_IO);
+ wBASE &= PCI_BASE_ADDRESS_IO_MASK;
+ wBIOS = TUL_RDWORD(wBASE, 0x50);
+
+#ifdef MMAPIO
+ base = wBASE & PAGE_MASK;
+ page_offset = wBASE - base;
+
+ /*
+ * replace the next line with this one if you are using 2.1.x:
+ * temp_p->maddr = ioremap(base, page_offset + 256);
+ */
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,0)
+ wBASE = ioremap(base, page_offset + 256);
+#else
+ wBASE = (WORD) vremap(base, page_offset + 256);
+#endif
+ if (wBASE) {
+ wBASE += page_offset;
+ }
+#endif
+
+ if (Addi91u_into_Adapter_table(wBIOS, wBASE, bInterrupt, bPCIBusNum,
+ bPCIDeviceNum) == 0x0)
+ iAdapters++;
+ }
+ } /* while(pdev=....) */
+ } /* for PCI_DEVICES */
+ } /* PCI BIOS present */
+ return (iAdapters);
+}
+#endif
+
+int i91u_detect(Scsi_Host_Template * tpnt)
+{
+ SCB *pSCB;
+ HCS *pHCB;
+ struct Scsi_Host *hreg;
+ unsigned long i; /* 01/14/98 */
+ int ok = 0, iAdapters;
+ ULONG dBiosAdr;
+ BYTE *pbBiosAdr;
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
+ tpnt->proc_dir = &proc_scsi_ini9100u;
+#endif
+
+ if (setup_called) { /* Setup by i91u_setup */
+ printk("i91u: processing commandline: ");
+
+#ifdef DEBUG_i91u
+ if (setup_called > 1) {
+ printk("\ni91u: %s\n", setup_str);
+ printk("i91u: usage: i91u[=<DEBUG>]\n");
+ i91u_panic("i91u panics in line %d", __LINE__);
+ }
+ i91u_debug = setup_debug;
+#endif
+ }
+ /* Get total number of adapters in the motherboard */
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,93)
+#ifdef CONFIG_PCI
+ iAdapters = tul_NewReturnNumberOfAdapters();
+#else
+ iAdapters = tul_ReturnNumberOfAdapters();
+#endif
+#else
+ iAdapters = tul_ReturnNumberOfAdapters();
+#endif
+
+ if (iAdapters == 0) /* If no tulip founded, return */
+ return (0);
+
+ tul_num_ch = (iAdapters > tul_num_ch) ? tul_num_ch : iAdapters;
+ /* Update actually channel number */
+ if (tul_tag_enable) { /* 1.01i */
+ tul_num_scb = MAX_TARGETS * i91u_MAXQUEUE;
+ } else {
+ tul_num_scb = MAX_TARGETS + 3; /* 1-tape, 1-CD_ROM, 1- extra */
+ } /* Update actually SCBs per adapter */
+
+ /* Get total memory needed for HCS */
+ i = tul_num_ch * sizeof(HCS);
+ memset((unsigned char *) &tul_hcs[0], 0, i); /* Initialize tul_hcs 0 */
+ /* Get total memory needed for SCB */
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
+ for (; tul_num_scb >= MAX_TARGETS + 3; tul_num_scb--) {
+ i = tul_num_ch * tul_num_scb * sizeof(SCB);
+ if ((tul_scb = (SCB *) kmalloc(i, GFP_ATOMIC | GFP_DMA)) != NULL)
+ break;
+ }
+#else
+ i = tul_num_ch * tul_num_scb * sizeof(SCB);
+ tul_scb = (SCB *) scsi_init_malloc(i, GFP_ATOMIC | GFP_DMA);
+#endif
+ if (tul_scb == NULL) {
+ printk("i91u: SCB memory allocation error\n");
+ return (0);
+ }
+ memset((unsigned char *) tul_scb, 0, i);
+
+ pSCB = tul_scb;
+ for (i = 0; i < tul_num_ch * tul_num_scb; i++, pSCB++) {
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
+ pSCB->SCB_SGPAddr = (U32) VIRT_TO_BUS(&pSCB->SCB_SGList[0]);
+#else
+ pSCB->SCB_SGPAddr = (U32) (&pSCB->SCB_SGList[0]);
+#endif
+ }
+
+ for (i = 0, pHCB = &tul_hcs[0]; /* Get pointer for control block */
+ i < tul_num_ch;
+ i++, pHCB++) {
+ pHCB->pSRB_head = NULL; /* Initial SRB save queue */
+ pHCB->pSRB_tail = NULL; /* Initial SRB save queue */
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+ pHCB->pSRB_lock = SPIN_LOCK_UNLOCKED; /* SRB save queue lock */
+#endif
+ request_region(pHCB->HCS_Base, 0x100, "i91u"); /* Register */
+
+ get_tulipPCIConfig(pHCB, i);
+
+ dBiosAdr = pHCB->HCS_BIOS;
+ dBiosAdr = (dBiosAdr << 4);
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
+ pbBiosAdr = phys_to_virt(dBiosAdr);
+#endif
+
+ init_tulip(pHCB, tul_scb + (i * tul_num_scb), tul_num_scb, pbBiosAdr, 10);
+ pHCB->HCS_Index = i; /* 7/29/98 */
+ hreg = scsi_register(tpnt, sizeof(HCS));
+ hreg->io_port = pHCB->HCS_Base;
+ hreg->n_io_port = 0xff;
+ hreg->can_queue = tul_num_scb; /* 03/05/98 */
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
+ hreg->unique_id = pHCB->HCS_Base;
+ hreg->max_id = pHCB->HCS_MaxTar;
+#endif
+ hreg->max_lun = 32; /* 10/21/97 */
+ hreg->irq = pHCB->HCS_Intr;
+ hreg->this_id = pHCB->HCS_SCSI_ID; /* Assign HCS index */
+ hreg->base = (UCHAR *) pHCB;
+ hreg->sg_tablesize = TOTAL_SG_ENTRY; /* Maximun support is 32 */
+
+ /* Initial tulip chip */
+ switch (i) {
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
+ case 0:
+ ok = request_irq(pHCB->HCS_Intr, i91u_intr0, SA_INTERRUPT | SA_SHIRQ, "i91u", NULL);
+ break;
+ case 1:
+ ok = request_irq(pHCB->HCS_Intr, i91u_intr1, SA_INTERRUPT | SA_SHIRQ, "i91u", NULL);
+ break;
+ case 2:
+ ok = request_irq(pHCB->HCS_Intr, i91u_intr2, SA_INTERRUPT | SA_SHIRQ, "i91u", NULL);
+ break;
+ case 3:
+ ok = request_irq(pHCB->HCS_Intr, i91u_intr3, SA_INTERRUPT | SA_SHIRQ, "i91u", NULL);
+ break;
+ case 4:
+ ok = request_irq(pHCB->HCS_Intr, i91u_intr4, SA_INTERRUPT | SA_SHIRQ, "i91u", NULL);
+ break;
+ case 5:
+ ok = request_irq(pHCB->HCS_Intr, i91u_intr5, SA_INTERRUPT | SA_SHIRQ, "i91u", NULL);
+ break;
+ case 6:
+ ok = request_irq(pHCB->HCS_Intr, i91u_intr6, SA_INTERRUPT | SA_SHIRQ, "i91u", NULL);
+ break;
+ case 7:
+ ok = request_irq(pHCB->HCS_Intr, i91u_intr7, SA_INTERRUPT | SA_SHIRQ, "i91u", NULL);
+ break;
+ default:
+ i91u_panic("i91u: Too many host adapters\n");
+ break;
+ }
+ if (ok < 0) {
+ if (ok == -EINVAL) {
+ printk("i91u: bad IRQ %d.\n", pHCB->HCS_Intr);
+ printk(" Contact author.\n");
+ } else if (ok == -EBUSY)
+ printk("i91u: IRQ %d already in use. Configure another.\n",
+ pHCB->HCS_Intr);
+ else {
+ printk("\ni91u: Unexpected error code on requesting IRQ %d.\n",
+ pHCB->HCS_Intr);
+ printk(" Contact author.\n");
+ }
+ i91u_panic("i91u: driver needs an IRQ.\n");
+ }
+#endif
+ }
+
+ tpnt->this_id = -1;
+ tpnt->can_queue = 1;
+


+ return 1;
+}
+

+static void i91uBuildSCB(HCS * pHCB, SCB * pSCB, Scsi_Cmnd * SCpnt)
+{ /* Create corresponding SCB */
+ struct scatterlist *pSrbSG;
+ SG *pSG; /* Pointer to SG list */
+ int i;
+ long TotalLen;
+
+ pSCB->SCB_Post = i91uSCBPost; /* i91u's callback routine */
+ pSCB->SCB_Srb = SCpnt;
+ pSCB->SCB_Opcode = ExecSCSI;
+ pSCB->SCB_Flags = SCF_POST; /* After SCSI done, call post routine */
+ pSCB->SCB_Target = SCpnt->target;
+ pSCB->SCB_Lun = SCpnt->lun;
+ pSCB->SCB_Ident = SCpnt->lun | DISC_ALLOW;
+ pSCB->SCB_Flags |= SCF_SENSE; /* Turn on auto request sense */
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
+ pSCB->SCB_SensePtr = (U32) VIRT_TO_BUS(SCpnt->sense_buffer);
+#else
+ pSCB->SCB_SensePtr = (U32) (SCpnt->sense_buffer);
+#endif
+
+ pSCB->SCB_SenseLen = SENSE_SIZE;
+
+ pSCB->SCB_CDBLen = SCpnt->cmd_len;
+ pSCB->SCB_HaStat = 0;
+ pSCB->SCB_TaStat = 0;
+ memcpy(&pSCB->SCB_CDB[0], &SCpnt->cmnd, SCpnt->cmd_len);
+
+ if (SCpnt->device->tagged_supported) { /* Tag Support */
+ pSCB->SCB_TagMsg = SIMPLE_QUEUE_TAG; /* Do simple tag only */
+ } else {
+ pSCB->SCB_TagMsg = 0; /* No tag support */
+ }
+
+ if (SCpnt->use_sg) {
+ pSrbSG = (struct scatterlist *) SCpnt->request_buffer;
+ if (SCpnt->use_sg == 1) { /* If only one entry in the list *//* treat it as regular I/O */
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
+ pSCB->SCB_BufPtr = (U32) VIRT_TO_BUS(pSrbSG->address);
+#else
+ pSCB->SCB_BufPtr = (U32) (pSrbSG->address);
+#endif
+ TotalLen = pSrbSG->length;
+ pSCB->SCB_SGLen = 0;
+ } else { /* Assign SG physical address */
+ pSCB->SCB_BufPtr = pSCB->SCB_SGPAddr;
+ pSCB->SCB_Flags |= SCF_SG; /* Turn on SG list flag */
+ for (i = 0, TotalLen = 0, pSG = &pSCB->SCB_SGList[0]; /* 1.01g */
+ i < SCpnt->use_sg;
+ i++, pSG++, pSrbSG++) {
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
+ pSG->SG_Ptr = (U32) VIRT_TO_BUS(pSrbSG->address);
+#else
+ pSG->SG_Ptr = (U32) (pSrbSG->address);
+#endif
+ TotalLen += pSG->SG_Len = pSrbSG->length;
+ }
+ pSCB->SCB_SGLen = i;
+ }
+ pSCB->SCB_BufLen = (SCpnt->request_bufflen > TotalLen) ?
+ TotalLen : SCpnt->request_bufflen;
+ } else { /* Non SG */
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
+ pSCB->SCB_BufPtr = (U32) VIRT_TO_BUS(SCpnt->request_buffer);
+#else
+ pSCB->SCB_BufPtr = (U32) (SCpnt->request_buffer);
+#endif
+ pSCB->SCB_BufLen = SCpnt->request_bufflen;
+ pSCB->SCB_SGLen = 0;
+ }


+
+ return;
+}
+

+/*
+ * Queue a command and setup interrupts for a free bus.
+ */
+int i91u_queue(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
+{
+ register SCB *pSCB;
+ HCS *pHCB; /* Point to Host adapter control block */
+
+ if (SCpnt->lun > 16) { /* 07/22/98 */
+
+ SCpnt->result = (DID_TIME_OUT << 16);
+ done(SCpnt); /* Notify system DONE */
+ return (0);
+ }
+ pHCB = (HCS *) SCpnt->host->base;
+
+ SCpnt->scsi_done = done;
+ /* Get free SCSI control block */
+ if ((pSCB = tul_alloc_scb(pHCB)) == NULL) {
+ i91uAppendSRBToQueue(pHCB, SCpnt); /* Buffer this request */
+ return (0);
+ }
+ i91uBuildSCB(pHCB, pSCB, SCpnt);
+ tul_exec_scb(pHCB, pSCB); /* Start execute SCB */


+ return (0);
+}
+
+/*

+ * We only support command in interrupt-driven fashion
+ */
+int i91u_command(Scsi_Cmnd * SCpnt)
+{
+ printk("i91u: interrupt driven driver; use i91u_queue()\n");


+ return -1;
+}
+

+/*
+ * Abort a queued command
+ * (commands that are on the bus can't be aborted easily)
+ */
+int i91u_abort(Scsi_Cmnd * SCpnt)
+{
+ HCS *pHCB;
+
+ pHCB = (HCS *) SCpnt->host->base;
+ return tul_abort_srb(pHCB, SCpnt);
+}
+
+/*
+ * Reset registers, reset a hanging bus and
+ * kill active and disconnected commands for target w/o soft reset
+ */
+int i91u_reset(Scsi_Cmnd * SCpnt, unsigned int reset_flags)
+{ /* I need Host Control Block Information */
+ HCS *pHCB;
+
+ pHCB = (HCS *) SCpnt->host->base;
+
+ if (reset_flags & (SCSI_RESET_SUGGEST_BUS_RESET | SCSI_RESET_SUGGEST_HOST_RESET))
+ return tul_reset_scsi_bus(pHCB);
+ else
+ return tul_device_reset(pHCB, (ULONG) SCpnt, SCpnt->target, reset_flags);
+}
+
+/*
+ * Return the "logical geometry"
+ */
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
+int i91u_biosparam(Scsi_Disk * disk, kdev_t dev, int *info_array)
+#else
+int i91u_biosparam(Scsi_Disk * disk, int dev, int *info_array)
+#endif
+{
+ HCS *pHcb; /* Point to Host adapter control block */
+ TCS *pTcb;
+
+ pHcb = (HCS *) disk->device->host->base;
+ pTcb = &pHcb->HCS_Tcs[disk->device->id];
+
+ if (pTcb->TCS_DrvHead) {
+ info_array[0] = pTcb->TCS_DrvHead;
+ info_array[1] = pTcb->TCS_DrvSector;
+ info_array[2] = disk->capacity / pTcb->TCS_DrvHead / pTcb->TCS_DrvSector;
+ } else {
+ if (pTcb->TCS_DrvFlags & TCF_DRV_255_63) {
+ info_array[0] = 255;
+ info_array[1] = 63;
+ info_array[2] = disk->capacity / 255 / 63;
+ } else {
+ info_array[0] = 64;
+ info_array[1] = 32;
+ info_array[2] = disk->capacity >> 11;
+ }
+ }
+
+#if defined(DEBUG_BIOSPARAM)
+ if (i91u_debug & debug_biosparam) {
+ printk("bios geometry: head=%d, sec=%d, cyl=%d\n",
+ info_array[0], info_array[1], info_array[2]);
+ printk("WARNING: check, if the bios geometry is correct.\n");
+ }
+#endif


+
+ return 0;
+}
+

+/*****************************************************************************
+ Function name : i91uSCBPost
+ Description : This is callback routine be called when tulip finish one
+ SCSI command.
+ Input : pHCB - Pointer to host adapter control block.
+ pSCB - Pointer to SCSI control block.
+ Output : None.
+ Return : None.
+*****************************************************************************/
+static void i91uSCBPost(BYTE * pHcb, BYTE * pScb)
+{
+ Scsi_Cmnd *pSRB; /* Pointer to SCSI request block */
+ HCS *pHCB;
+ SCB *pSCB;
+
+ pHCB = (HCS *) pHcb;
+ pSCB = (SCB *) pScb;
+ if ((pSRB = pSCB->SCB_Srb) == 0) {
+ printk("i91uSCBPost: SRB pointer is empty\n");
+
+ tul_release_scb(pHCB, pSCB); /* Release SCB for current channel */
+ return;
+ }
+ switch (pSCB->SCB_HaStat) {
+ case 0x0:
+ case 0xa: /* Linked command complete without error and linked normally */
+ case 0xb: /* Linked command complete without error interrupt generated */
+ pSCB->SCB_HaStat = 0;
+ break;
+
+ case 0x11: /* Selection time out-The initiator selection or target
+ reselection was not complete within the SCSI Time out period */
+ pSCB->SCB_HaStat = DID_TIME_OUT;
+ break;
+
+ case 0x14: /* Target bus phase sequence failure-An invalid bus phase or bus
+ phase sequence was requested by the target. The host adapter
+ will generate a SCSI Reset Condition, notifying the host with
+ a SCRD interrupt */
+ pSCB->SCB_HaStat = DID_RESET;
+ break;
+
+ case 0x1a: /* SCB Aborted. 07/21/98 */
+ pSCB->SCB_HaStat = DID_ABORT;
+ break;
+
+ case 0x12: /* Data overrun/underrun-The target attempted to transfer more data
+ than was allocated by the Data Length field or the sum of the
+ Scatter / Gather Data Length fields. */
+ case 0x13: /* Unexpected bus free-The target dropped the SCSI BSY at an unexpected time. */
+ case 0x16: /* Invalid SCB Operation Code. */
+
+ default:
+ printk("ini9100u: %x %x\n", pSCB->SCB_HaStat, pSCB->SCB_TaStat);
+ pSCB->SCB_HaStat = DID_ERROR; /* Couldn't find any better */
+ break;
+ }
+
+ pSRB->result = pSCB->SCB_TaStat | (pSCB->SCB_HaStat << 16);


SHAR_EOF
true || echo 'restore of patch-2.0.37 failed'
fi

echo 'End of part 26'
echo 'File patch-2.0.37 is continued in part 27'
echo 27 > _shar_seq_.tmp
exit 0

Thomas...@ciw.uni-karlsruhe.de

unread,
Jun 16, 1999, 3:00:00 AM6/16/99
to
Archive-name: v2.0/patch-2.0.37/part29

#!/bin/sh
# this is part 29 of a 45 - part archive


# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.0.37 continued
if test ! -r _shar_seq_.tmp; then
echo 'Please unpack part 1 first!'
exit 1
fi
(read Scheck

if test "$Scheck" != 29; then


echo Please unpack part "$Scheck" next!
exit 1
else
exit 0
fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.0.37'
else
echo 'x - continuing with patch-2.0.37'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.0.37' &&

+ long flag)
X {
X mega_host_config *megaCfg;
X struct Scsi_Host *host;
- u_char pciBus, pciDevFun, megaIrq;
- u_long megaBase;
- u_short pciIdx = 0;
+ u_char pciBus, pciDevFun, megaIrq;
+ u_long megaBase;
+ u_short pciIdx = 0;
X
X #if LINUX_VERSION_CODE < 0x20100
- while(!pcibios_find_device(pciVendor, pciDev, pciIdx,&pciBus,&pciDevFun)) {
+ while (!pcibios_find_device (pciVendor, pciDev, pciIdx, &pciBus, &pciDevFun)) {
+ if (flag & BOARD_QUARTZ) {
+ u_int magic;
+ pcibios_read_config_dword (pciBus, pciDevFun,
+ PCI_CONF_AMISIG,
+ &magic);
+ if (magic != AMI_SIGNATURE) {
+ continue; /* not an AMI board */
+ }
+ }
X #else
- struct pci_dev *pdev=pci_devices;
+ struct pci_dev *pdev = pci_devices;
X
- while((pdev = pci_find_device(pciVendor, pciDev, pdev))) {
+ while ((pdev = pci_find_device (pciVendor, pciDev, pdev))) {
X pciBus = pdev->bus->number;
X pciDevFun = pdev->devfn;
X #endif
- printk(KERN_INFO "megaraid: found 0x%4.04x:0x%4.04x:idx %d:bus %d:slot %d:fun %d\n",
- pciVendor,
- pciDev,
- pciIdx, pciBus,
- PCI_SLOT(pciDevFun),
- PCI_FUNC(pciDevFun));
-
+ printk (KERN_INFO "megaraid: found 0x%4.04x:0x%4.04x:idx %d:bus %d:slot %d:fun %d\n",
+ pciVendor,
+ pciDev,
+ pciIdx, pciBus,
+ PCI_SLOT (pciDevFun),
+ PCI_FUNC (pciDevFun));
+
X /* Read the base port and IRQ from PCI */
X #if LINUX_VERSION_CODE < 0x20100
- pcibios_read_config_dword(pciBus, pciDevFun,
- PCI_BASE_ADDRESS_0,
- (u_int *)&megaBase);
- pcibios_read_config_byte(pciBus, pciDevFun,
- PCI_INTERRUPT_LINE,
- &megaIrq);
+ pcibios_read_config_dword (pciBus, pciDevFun,
+ PCI_BASE_ADDRESS_0,
+ (u_int *) & megaBase);
+ pcibios_read_config_byte (pciBus, pciDevFun,
+ PCI_INTERRUPT_LINE,
+ &megaIrq);
X #else
X megaBase = pdev->base_address[0];
X megaIrq = pdev->irq;
@@ -1025,7 +1146,7 @@
X
X if (flag & BOARD_QUARTZ) {
X megaBase &= PCI_BASE_ADDRESS_MEM_MASK;
- megaBase = (long) ioremap(megaBase,128);
+ megaBase = (long) ioremap (megaBase, 128);
X }
X else {
X megaBase &= PCI_BASE_ADDRESS_IO_MASK;
@@ -1033,47 +1154,47 @@
X }
X
X /* Initialize SCSI Host structure */
- host = scsi_register(pHostTmpl, sizeof(mega_host_config));
- megaCfg = (mega_host_config *)host->hostdata;
- memset(megaCfg, 0, sizeof(mega_host_config));
-
- printk(KERN_INFO " scsi%d: Found a MegaRAID controller at 0x%x, IRQ: %d" CRLFSTR,
- host->host_no, (u_int)megaBase, megaIrq);
-
+ host = scsi_register (pHostTmpl, sizeof (mega_host_config));
+ megaCfg = (mega_host_config *) host->hostdata;
+ memset (megaCfg, 0, sizeof (mega_host_config));
+
+ printk (KERN_INFO " scsi%d: Found a MegaRAID controller at 0x%x, IRQ: %d" CRLFSTR,
+ host->host_no, (u_int) megaBase, megaIrq);
+
X /* Copy resource info into structure */
- megaCfg->flag = flag;
- megaCfg->host = host;
- megaCfg->base = megaBase;
- megaCfg->host->irq = megaIrq;
- megaCfg->host->io_port = megaBase;
+ megaCfg->flag = flag;
+ megaCfg->host = host;
+ megaCfg->base = megaBase;
+ megaCfg->host->irq = megaIrq;
+ megaCfg->host->io_port = megaBase;
X megaCfg->host->n_io_port = 16;
X megaCfg->host->unique_id = (pciBus << 8) | pciDevFun;
- megaCtlrs[numCtlrs++] = megaCfg;
+ megaCtlrs[numCtlrs++] = megaCfg;
X
X if (flag != BOARD_QUARTZ) {
X /* Request our IO Range */
- if (check_region(megaBase, 16)) {
- printk(KERN_WARNING "megaraid: Couldn't register I/O range!" CRLFSTR);
- scsi_unregister(host);
+ if (check_region (megaBase, 16)) {
+ printk (KERN_WARNING "megaraid: Couldn't register I/O range!" CRLFSTR);
+ scsi_unregister (host);
X continue;
X }
- request_region(megaBase, 16, "megaraid");
+ request_region (megaBase, 16, "megaraid");
X }
X
X /* Request our IRQ */
- if (request_irq(megaIrq, megaraid_isr, SA_SHIRQ,
- "megaraid", megaCfg)) {
- printk(KERN_WARNING "megaraid: Couldn't register IRQ %d!" CRLFSTR,
- megaIrq);
- scsi_unregister(host);
+ if (request_irq (megaIrq, megaraid_isr, SA_SHIRQ,
+ "megaraid", megaCfg)) {
+ printk (KERN_WARNING "megaraid: Couldn't register IRQ %d!" CRLFSTR,
+ megaIrq);
+ scsi_unregister (host);
X continue;
X }
X
- mega_register_mailbox(megaCfg, virt_to_bus((void*)&megaCfg->mailbox));
- mega_i_query_adapter(megaCfg);
+ mega_register_mailbox (megaCfg, virt_to_bus ((void *) &megaCfg->mailbox));
+ mega_i_query_adapter (megaCfg);
X
X /* Initialize SCBs */
- initSCB(megaCfg);
+ initSCB (megaCfg);
X
X }
X return pciIdx;
@@ -1082,23 +1203,22 @@
X /*---------------------------------------------------------
X * Detects if a megaraid controller exists in this system
X *---------------------------------------------------------*/
-int megaraid_detect(Scsi_Host_Template *pHostTmpl)
+int megaraid_detect (Scsi_Host_Template * pHostTmpl)
X {
X int count = 0;
X
X pHostTmpl->proc_dir = &proc_scsi_megaraid;
X
X #if LINUX_VERSION_CODE < 0x20100
- if (!pcibios_present())
- {
- printk(KERN_WARNING "megaraid: PCI bios not present." CRLFSTR);
- return 0;
- }
+ if (!pcibios_present ()) {
+ printk (KERN_WARNING "megaraid: PCI bios not present." CRLFSTR);
+ return 0;
+ }
X #endif
X
- count += findCard(pHostTmpl, 0x101E, 0x9010, 0);
- count += findCard(pHostTmpl, 0x101E, 0x9060, 0);
- count += findCard(pHostTmpl, 0x8086, 0x1960, BOARD_QUARTZ);
+ count += findCard (pHostTmpl, 0x101E, 0x9010, 0);
+ count += findCard (pHostTmpl, 0x101E, 0x9060, 0);
+ count += findCard (pHostTmpl, 0x8086, 0x1960, BOARD_QUARTZ);
X
X return count;
X }
@@ -1106,33 +1226,40 @@
X /*---------------------------------------------------------------------
X * Release the controller's resources
X *---------------------------------------------------------------------*/
-int megaraid_release(struct Scsi_Host *pSHost)
+int megaraid_release (struct Scsi_Host *pSHost)
X {
X mega_host_config *megaCfg;
- mega_mailbox *mbox;
- u_char mboxData[16];
+ mega_mailbox *mbox;
+ u_char mboxData[16];
+ int i;
X
- megaCfg = (mega_host_config*)pSHost->hostdata;
- mbox = (mega_mailbox *)mboxData;
+ megaCfg = (mega_host_config *) pSHost->hostdata;
+ mbox = (mega_mailbox *) mboxData;
X
X /* Flush cache to disk */
- memset(mbox, 0, 16);
+ memset (mbox, 0, 16);
X mboxData[0] = 0xA;
X
X /* Issue a blocking (interrupts disabled) command to the card */
- MegaIssueCmd(megaCfg, mboxData, NULL, 0);
+ MegaIssueCmd (megaCfg, mboxData, NULL, 0);
X
- schedule();
+ schedule ();
X
X /* Free our resources */
X if (megaCfg->flag & BOARD_QUARTZ) {
- iounmap((void *)megaCfg->base);
- } else {
- release_region(megaCfg->host->io_port, 16);
- }
- free_irq(megaCfg->host->irq, megaCfg); /* Must be freed first, otherwise
- extra interrupt is generated */
- scsi_unregister(pSHost);
+ iounmap ((void *) megaCfg->base);
+ }
+ else {
+ release_region (megaCfg->host->io_port, 16);
+ }
+ free_irq (megaCfg->host->irq, megaCfg); /* Must be freed first, otherwise
+
+ extra interrupt is generated */
+ for (i = 0; i < megaCfg->max_cmds; i++) {
+ if (megaCfg->scbList[i].sgList)
+ kfree (megaCfg->scbList[i].sgList); /* free sgList */
+ }
+ scsi_unregister (pSHost);


X
X return 0;
X }

@@ -1140,20 +1267,20 @@
X /*----------------------------------------------
X * Get information about the card/driver
X *----------------------------------------------*/
-const char *megaraid_info(struct Scsi_Host *pSHost)
+const char * megaraid_info (struct Scsi_Host *pSHost)
X {
- static char buffer[512];
- mega_host_config *megaCfg;
- mega_RAIDINQ *adapterInfo;
+ static char buffer[512];
+ mega_host_config *megaCfg;
+ mega_RAIDINQ *adapterInfo;
X
- megaCfg = (mega_host_config *)pSHost->hostdata;
- adapterInfo = (mega_RAIDINQ *)megaCfg->mega_buffer;
+ megaCfg = (mega_host_config *) pSHost->hostdata;
+ adapterInfo = (mega_RAIDINQ *) megaCfg->mega_buffer;
X
- sprintf(buffer, "AMI MegaRAID %s %d commands %d targs %d chans",
- megaCfg->fwVer,
- adapterInfo->AdpInfo.MaxConcCmds,
- megaCfg->host->max_id,
- megaCfg->host->max_channel);
+ sprintf (buffer, "AMI MegaRAID %s %d commands %d targs %d chans",
+ megaCfg->fwVer,
+ adapterInfo->AdpInfo.MaxConcCmds,
+ megaCfg->host->max_id,
+ megaCfg->host->max_channel);
X return buffer;
X }
X
@@ -1172,29 +1299,29 @@
X * 10 01 numstatus byte
X * 11 01 status byte
X *-----------------------------------------------------------------*/
-int megaraid_queue(Scsi_Cmnd *SCpnt, void (*pktComp)(Scsi_Cmnd *))
+int megaraid_queue (Scsi_Cmnd * SCpnt, void (*pktComp) (Scsi_Cmnd *))
X {
X mega_host_config *megaCfg;
- mega_scb *pScb;
+ mega_scb *pScb;
X
- megaCfg = (mega_host_config *)SCpnt->host->hostdata;
+ megaCfg = (mega_host_config *) SCpnt->host->hostdata;
X
X if (!(megaCfg->flag & (1L << SCpnt->channel))) {
- printk(KERN_INFO "scsi%d: scanning channel %c for devices.\n",
- megaCfg->host->host_no,
- SCpnt->channel + 'A');
+ printk (KERN_INFO "scsi%d: scanning channel %c for devices.\n",
+ megaCfg->host->host_no,
+ SCpnt->channel + 'A');
X megaCfg->flag |= (1L << SCpnt->channel);
X }
X
X SCpnt->scsi_done = pktComp;
X
X /* Allocate and build a SCB request */
- if ((pScb = mega_build_cmd(megaCfg, SCpnt)) != NULL) {
+ if ((pScb = mega_build_cmd (megaCfg, SCpnt)) != NULL) {
X /* Add SCB to the head of the pending queue */
- ENQUEUE(pScb, mega_scb, qPending, next);
+ ENQUEUE (pScb, mega_scb, qPending, next);
X
X /* Issue the command to the card */
- mega_runque(NULL);
+ mega_runque (NULL);
X }
X
X return 0;
@@ -1202,37 +1329,44 @@
X
X /*----------------------------------------------------------------------
X * Issue a blocking command to the controller
- *
- * Note - this isnt 2.0.x SMP safe
X *----------------------------------------------------------------------*/
-volatile static int internal_done_flag = 0;
+volatile static int internal_done_flag = 0;
X volatile static int internal_done_errcode = 0;
X
-static void internal_done(Scsi_Cmnd *SCpnt)
+static void internal_done (Scsi_Cmnd * SCpnt)
X {
X internal_done_errcode = SCpnt->result;
X internal_done_flag++;
X }
X
X /*
- * This seems dangerous in an SMP environment because
- * while spinning on internal_done_flag in 2.0.x SMP
- * no IRQ's will be taken, including those that might
- * be needed to clear this.
- *
- * I think this should be using a wait queue ?
- * -- AC
+ * This seems dangerous in an SMP environment because
+ * while spinning on internal_done_flag in 2.0.x SMP
+ * no IRQ's will be taken, including those that might
+ * be needed to clear this.
+ *
+ * I think this should be using a wait queue ?
+ * -- AC
+ */
+
+/*
+ * I'll probably fix this in the next version, but
+ * megaraid_command() will never get called since can_queue is set,
+ * except maybe in a *really* old kernel in which case it's very
+ * unlikely they'd be using SMP anyway. Really this function is
+ * just here for completeness.
+ * - JLJ
X */
-
-int megaraid_command(Scsi_Cmnd *SCpnt)
+
+int megaraid_command (Scsi_Cmnd * SCpnt)
X {
X internal_done_flag = 0;
X
X /* Queue command, and wait until it has completed */
- megaraid_queue(SCpnt, internal_done);
+ megaraid_queue (SCpnt, internal_done);
X
- while(!internal_done_flag)
- barrier();
+ while (!internal_done_flag)
+ barrier ();
X
X return internal_done_errcode;
X }
@@ -1240,67 +1374,67 @@
X /*---------------------------------------------------------------------
X * Abort a previous SCSI request
X *---------------------------------------------------------------------*/
-int megaraid_abort(Scsi_Cmnd *SCpnt)
+int megaraid_abort (Scsi_Cmnd * SCpnt)
X {
X mega_host_config *megaCfg;
- int idx;
- long flags;
+ int idx;
+ long flags;
X
- spin_lock_irqsave(&mega_lock,flags);
+ spin_lock_irqsave (&mega_lock, flags);
X
- megaCfg = (mega_host_config *)SCpnt->host->hostdata;
+ megaCfg = (mega_host_config *) SCpnt->host->hostdata;
X
- TRACE(("ABORT!!! %.08lx %.02x <%d.%d.%d>\n",
- SCpnt->serial_number, SCpnt->cmnd[0], SCpnt->channel, SCpnt->target,
- SCpnt->lun));
+ TRACE (("ABORT!!! %.08lx %.02x <%d.%d.%d>\n",
+ SCpnt->serial_number, SCpnt->cmnd[0], SCpnt->channel, SCpnt->target,
+ SCpnt->lun));
X /*
X * Walk list of SCBs for any that are still outstanding
X */
- for(idx=0; idx<megaCfg->max_cmds; idx++) {
+ for (idx = 0; idx < megaCfg->max_cmds; idx++) {
X if (megaCfg->scbList[idx].idx >= 0) {
X if (megaCfg->scbList[idx].SCpnt == SCpnt) {
- freeSCB(&megaCfg->scbList[idx]);
+ freeSCB (&megaCfg->scbList[idx]);
X
- SCpnt->result = (DID_RESET << 16) | (SUGGEST_RETRY<<24);
- callDone(SCpnt);
+ SCpnt->result = (DID_RESET << 16) | (SUGGEST_RETRY << 24);
+ callDone (SCpnt);
X }
X }
X }
- spin_unlock_irqrestore(&mega_lock,flags);
+ spin_unlock_irqrestore (&mega_lock, flags);
X return SCSI_ABORT_SNOOZE;
X }
X
X /*---------------------------------------------------------------------
X * Reset a previous SCSI request
X *---------------------------------------------------------------------*/
-int megaraid_reset(Scsi_Cmnd *SCpnt, unsigned int rstflags)
+int megaraid_reset (Scsi_Cmnd * SCpnt, unsigned int rstflags)
X {
X mega_host_config *megaCfg;
- int idx;
- long flags;
+ int idx;
+ long flags;
X
- spin_lock_irqsave(&mega_lock,flags);
+ spin_lock_irqsave (&mega_lock, flags);
X
- megaCfg = (mega_host_config *)SCpnt->host->hostdata;
+ megaCfg = (mega_host_config *) SCpnt->host->hostdata;
X
- TRACE(("RESET: %.08lx %.02x <%d.%d.%d>\n",
- SCpnt->serial_number, SCpnt->cmnd[0], SCpnt->channel, SCpnt->target,
- SCpnt->lun));
+ TRACE (("RESET: %.08lx %.02x <%d.%d.%d>\n",
+ SCpnt->serial_number, SCpnt->cmnd[0], SCpnt->channel, SCpnt->target,
+ SCpnt->lun));
X
X /*
X * Walk list of SCBs for any that are still outstanding
X */
- for(idx=0; idx<megaCfg->max_cmds; idx++) {
+ for (idx = 0; idx < megaCfg->max_cmds; idx++) {
X if (megaCfg->scbList[idx].idx >= 0) {
X SCpnt = megaCfg->scbList[idx].SCpnt;
- freeSCB(&megaCfg->scbList[idx]);
- SCpnt->result = (DID_RESET << 16) | (SUGGEST_RETRY<<24);
- callDone(SCpnt);
+ freeSCB (&megaCfg->scbList[idx]);
+ SCpnt->result = (DID_RESET << 16) | (SUGGEST_RETRY << 24);
+ callDone (SCpnt);
X }
X }
- spin_unlock_irqrestore(&mega_lock,flags);
+ spin_unlock_irqrestore (&mega_lock, flags);
X return SCSI_RESET_PUNT;
-}
+}
X
X /*-------------------------------------------------------------
X * Return the disk geometry for a particular disk
@@ -1312,23 +1446,23 @@
X * geom[1] = sectors
X * geom[2] = cylinders
X *-------------------------------------------------------------*/
-int megaraid_biosparam(Disk *disk, kdev_t dev, int *geom)
+int megaraid_biosparam (Disk * disk, kdev_t dev, int *geom)


X {
- int heads, sectors, cylinders;

+ int heads, sectors, cylinders;
X mega_host_config *megaCfg;
X
X /* Get pointer to host config structure */
- megaCfg = (mega_host_config *)disk->device->host->hostdata;
+ megaCfg = (mega_host_config *) disk->device->host->hostdata;
X
X /* Default heads (64) & sectors (32) */
- heads = 64;
- sectors = 32;
+ heads = 64;
+ sectors = 32;


X cylinders = disk->capacity / (heads * sectors);

X
X /* Handle extended translation size for logical drives > 1Gb */
X if (disk->capacity >= 0x200000) {
- heads = 255;
- sectors = 63;
+ heads = 255;
+ sectors = 63;


X cylinders = disk->capacity / (heads * sectors);

X }
X
diff -u --recursive --new-file v2.0.36/linux/drivers/scsi/megaraid.h linux/drivers/scsi/megaraid.h
--- v2.0.36/linux/drivers/scsi/megaraid.h Sun Nov 15 21:51:47 1998
+++ linux/drivers/scsi/megaraid.h Sun Jun 13 10:21:02 1999
@@ -1,6 +1,10 @@
X #ifndef __MEGARAID_H__
X #define __MEGARAID_H__
X

+#ifndef LINUX_VERSION_CODE
+#include <linux/version.h>
+#endif
+

X #define IN_ISR 0x80000000L
X #define NO_INTR 0x40000000L
X #define IN_TIMEOUT 0x20000000L
@@ -18,7 +22,7 @@
X
X #define MEGA_CMD_TIMEOUT 10
X
-#define MAX_SGLIST 20
+#define MAX_SGLIST 17
X #define MAX_COMMANDS 254
X
X #define MAX_LOGICAL_DRIVES 8
@@ -94,6 +98,8 @@
X
X #define PCI_CONF_BASE_ADDR_OFFSET 0x10
X #define PCI_CONF_IRQ_OFFSET 0x3c
+#define PCI_CONF_AMISIG 0xa0
+#define AMI_SIGNATURE 0x11223344
X
X #if LINUX_VERSION_CODE < 0x20100
X #define MEGARAID \
@@ -111,14 +117,14 @@
X megaraid_reset, /* Reset Command Function */\
X NULL, /* Slave Attach Function */\
X megaraid_biosparam, /* Disk BIOS Parameters */\
- 1, /* # of cmds that can be\
+ 254, /* # of cmds that can be\
X outstanding at any time */\
X 7, /* HBA Target ID */\
X MAX_SGLIST, /* Scatter/Gather Table Size */\
- 1, /* SCSI Commands per LUN */\
+ 64, /* SCSI Commands per LUN */\
X 0, /* Present */\
X 0, /* Default Unchecked ISA DMA */\
- ENABLE_CLUSTERING } /* Enable Clustering */
+ ENABLE_CLUSTERING } /* Enable Clustering */
X #else
X #define MEGARAID \
X {\
@@ -132,10 +138,10 @@
X abort: megaraid_abort, /* Abort Command Function */\
X reset: megaraid_reset, /* Reset Command Function */\
X bios_param: megaraid_biosparam, /* Disk BIOS Parameters */\
- can_queue: 255, /* Can Queue */\
+ can_queue: 254, /* Can Queue */\
X this_id: 7, /* HBA Target ID */\
X sg_tablesize: MAX_SGLIST, /* Scatter/Gather Table Size */\
- cmd_per_lun: 1, /* SCSI Commands per LUN */\
+ cmd_per_lun: 64, /* SCSI Commands per LUN */\
X present: 0, /* Present */\
X unchecked_isa_dma:0, /* Default Unchecked ISA DMA */\
X use_clustering: ENABLE_CLUSTERING /* Enable Clustering */\
@@ -143,140 +149,150 @@
X #endif
X
X /* Structures */
-typedef struct _mega_ADP_INFO
-{
- u_char MaxConcCmds;
- u_char RbldRate;
- u_char MaxTargPerChan;
- u_char ChanPresent;
- u_char FwVer[4];
- u_short AgeOfFlash;
- u_char ChipSet;
- u_char DRAMSize;
- u_char CacheFlushInterval;
- u_char BiosVer[4];
- u_char resvd[7];
+typedef struct _mega_ADP_INFO {
+ u_char MaxConcCmds;
+ u_char RbldRate;
+ u_char MaxTargPerChan;
+ u_char ChanPresent;
+ u_char FwVer[4];
+ u_short AgeOfFlash;
+ u_char ChipSet;
+ u_char DRAMSize;
+ u_char CacheFlushInterval;
+ u_char BiosVer[4];
+ u_char resvd[7];
X } mega_ADP_INFO;
X
-typedef struct _mega_LDRV_INFO
-{
- u_char NumLDrv;
- u_char resvd[3];
- u_long LDrvSize[MAX_LOGICAL_DRIVES];
- u_char LDrvProp[MAX_LOGICAL_DRIVES];
- u_char LDrvState[MAX_LOGICAL_DRIVES];
+typedef struct _mega_LDRV_INFO {
+ u_char NumLDrv;
+ u_char resvd[3];
+ u_long LDrvSize[MAX_LOGICAL_DRIVES];
+ u_char LDrvProp[MAX_LOGICAL_DRIVES];
+ u_char LDrvState[MAX_LOGICAL_DRIVES];
X } mega_LDRV_INFO;
X
-typedef struct _mega_PDRV_INFO
-{
- u_char PDrvState[MAX_PHYSICAL_DRIVES];
- u_char resvd;
+typedef struct _mega_PDRV_INFO {
+ u_char PDrvState[MAX_PHYSICAL_DRIVES];
+ u_char resvd;
X } mega_PDRV_INFO;
X
X // RAID inquiry: Mailbox command 0x5
-typedef struct _mega_RAIDINQ
-{
- mega_ADP_INFO AdpInfo;
- mega_LDRV_INFO LogdrvInfo;
- mega_PDRV_INFO PhysdrvInfo;
+typedef struct _mega_RAIDINQ {
+ mega_ADP_INFO AdpInfo;
+ mega_LDRV_INFO LogdrvInfo;
+ mega_PDRV_INFO PhysdrvInfo;
X } mega_RAIDINQ;
X
X // Passthrough command: Mailbox command 0x3
-typedef struct mega_passthru
-{
- u_char timeout:3; /* 0=6sec/1=60sec/2=10min/3=3hrs */
- u_char ars:1;
- u_char reserved:3;
- u_char islogical:1;
- u_char logdrv; /* if islogical == 1 */
- u_char channel; /* if islogical == 0 */
- u_char target; /* if islogical == 0 */
- u_char queuetag; /* unused */
- u_char queueaction; /* unused */
- u_char cdb[MAX_CDB_LEN];
- u_char cdblen;
- u_char reqsenselen;
- u_char reqsensearea[MAX_REQ_SENSE_LEN];
- u_char numsgelements;
- u_char scsistatus;
- u_long dataxferaddr;
- u_long dataxferlen;
+typedef struct mega_passthru {
+ u_char timeout:3; /* 0=6sec/1=60sec/2=10min/3=3hrs */
+ u_char ars:1;
+ u_char reserved:3;
+ u_char islogical:1;
+ u_char logdrv; /* if islogical == 1 */
+ u_char channel; /* if islogical == 0 */
+ u_char target; /* if islogical == 0 */
+ u_char queuetag; /* unused */
+ u_char queueaction; /* unused */
+ u_char cdb[MAX_CDB_LEN];
+ u_char cdblen;
+ u_char reqsenselen;
+ u_char reqsensearea[MAX_REQ_SENSE_LEN];
+ u_char numsgelements;
+ u_char scsistatus;
+ u_long dataxferaddr;
+ u_long dataxferlen;
X } mega_passthru;
X
-typedef struct _mega_mailbox
-{
- /* 0x0 */ u_char cmd;
- /* 0x1 */ u_char cmdid;
- /* 0x2 */ u_short numsectors;
- /* 0x4 */ u_long lba;
- /* 0x8 */ u_long xferaddr;
- /* 0xC */ u_char logdrv;
- /* 0xD */ u_char numsgelements;
- /* 0xE */ u_char resvd;
- /* 0xF */ u_char busy;
- /* 0x10*/ u_char numstatus;
- /* 0x11*/ u_char status;
- /* 0x12*/ u_char completed[46];
- u_char mraid_poll;
- u_char mraid_ack;
- u_char pad[16];
+typedef struct _mega_mailbox {
+ /* 0x0 */ u_char cmd;
+ /* 0x1 */ u_char cmdid;
+ /* 0x2 */ u_short numsectors;
+ /* 0x4 */ u_long lba;
+ /* 0x8 */ u_long xferaddr;
+ /* 0xC */ u_char logdrv;
+ /* 0xD */ u_char numsgelements;
+ /* 0xE */ u_char resvd;
+ /* 0xF */ u_char busy;
+ /* 0x10 */ u_char numstatus;
+ /* 0x11 */ u_char status;
+ /* 0x12 */ u_char completed[46];
+ u_char mraid_poll;
+ u_char mraid_ack;
+ u_char pad[16];
X } mega_mailbox;
X
-typedef struct _mega_sglist
-{
- u_long address;
- u_long length;
+typedef struct _mega_ioctl_mbox {
+ /* 0x0 */ u_char cmd;
+ /* 0x1 */ u_char cmdid;
+ /* 0x2 */ u_char channel;
+ /* 0x3 */ u_char param;
+ /* 0x4 */ u_char pad[4];
+ /* 0x8 */ u_long xferaddr;
+ /* 0xC */ u_char logdrv;
+ /* 0xD */ u_char numsgelements;
+ /* 0xE */ u_char resvd;
+ /* 0xF */ u_char busy;
+ /* 0x10 */ u_char numstatus;
+ /* 0x11 */ u_char status;
+ /* 0x12 */ u_char completed[46];
+ u_char mraid_poll;
+ u_char mraid_ack;
+ u_char malign[16];
+} mega_ioctl_mbox;
+
+typedef struct _mega_sglist {
+ u_long address;
+ u_long length;
X } mega_sglist;
X
X /* Queued command data */
X typedef struct _mega_scb mega_scb;
X
-struct _mega_scb
-{
- int idx;
- u_long flag;
- Scsi_Cmnd *SCpnt;
- u_char mboxData[16];
- mega_passthru pthru;
- mega_sglist *sgList;
- mega_scb *next;
+struct _mega_scb {
+ int idx;
+ u_long flag;
+ Scsi_Cmnd *SCpnt;
+ u_char mboxData[16];
+ mega_passthru pthru;
+ mega_sglist *sgList;
+ mega_scb *next;
X };
X
X /* Per-controller data */
-typedef struct _mega_host_config
-{
- u_char numldrv;
- u_long flag;
- u_long base;
-
- struct tq_struct megaTq;
-
- /* Host adapter parameters */
- u_char fwVer[7];
- u_char biosVer[7];
-
- struct Scsi_Host *host;
-
- /* The following must be DMA-able!! */
- volatile mega_mailbox *mbox;
- volatile mega_mailbox mailbox;
- volatile u_char mega_buffer[2*1024L];
+typedef struct _mega_host_config {
+ u_char numldrv;
+ u_long flag;
+ u_long base;
+
+ struct tq_struct megaTq;
+
+ /* Host adapter parameters */
+ u_char fwVer[7];
+ u_char biosVer[7];
+
+ struct Scsi_Host *host;
+
+ /* The following must be DMA-able!! */
+ volatile mega_mailbox *mbox;
+ volatile mega_mailbox mailbox;
+ volatile u_char mega_buffer[2 * 1024L];
X
- u_char max_cmds;
- mega_scb scbList[MAX_COMMANDS];
+ u_char max_cmds;
+ mega_scb scbList[MAX_COMMANDS];
X } mega_host_config;
X
X extern struct proc_dir_entry proc_scsi_megaraid;
X
-const char *megaraid_info( struct Scsi_Host * );
-int megaraid_detect( Scsi_Host_Template * );
-int megaraid_release(struct Scsi_Host *);
-int megaraid_command( Scsi_Cmnd * );
-int megaraid_abort( Scsi_Cmnd * );
-int megaraid_reset( Scsi_Cmnd *, unsigned int);
-int megaraid_queue( Scsi_Cmnd *, void (*done)(Scsi_Cmnd *) );
-int megaraid_biosparam( Disk *, kdev_t, int * );
-int megaraid_proc_info( char *buffer, char **start, off_t offset,
- int length, int hostno, int inout );
+const char *megaraid_info(struct Scsi_Host *);
+int megaraid_detect(Scsi_Host_Template *);
+int megaraid_release(struct Scsi_Host *);
+int megaraid_command(Scsi_Cmnd *);
+int megaraid_abort(Scsi_Cmnd *);
+int megaraid_reset(Scsi_Cmnd *, unsigned int);
+int megaraid_queue(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
+int megaraid_biosparam(Disk *, kdev_t, int *);
+int megaraid_proc_info(char *buffer, char **start, off_t offset,
+ int length, int hostno, int inout);
X
X #endif
diff -u --recursive --new-file v2.0.36/linux/drivers/scsi/ncr53c8xx.c linux/drivers/scsi/ncr53c8xx.c
--- v2.0.36/linux/drivers/scsi/ncr53c8xx.c Sun Nov 15 21:51:47 1998
+++ linux/drivers/scsi/ncr53c8xx.c Sun Jun 13 10:21:02 1999
@@ -63,11 +63,17 @@
X ** August 18 1997 by Cort <co...@cs.nmt.edu>:
X ** Support for Power/PC (Big Endian).
X **
+** June 20 1998 by Gerard Roudier <grou...@club-internet.fr>:
+** Support for up to 64 tags per lun.
+** O(1) everywhere (C and SCRIPTS) for normal cases.
+** Low PCI traffic for command handling when on-chip RAM is present.
+** Aggressive SCSI SCRIPTS optimizations.
+**
X *******************************************************************************


X */
X
X /*

-** 30 January 1998, version 2.5f.1
+** December 14 1998, version 3.1e
X **
X ** Supported SCSI-II features:
X ** Synchronous negotiation
@@ -92,9 +98,7 @@
X ** Shared IRQ (since linux-1.3.72)
X */
X
-#define SCSI_NCR_DEBUG_FLAGS (0)
-
-#define NCR_GETCC_WITHMSG
+#define SCSI_NCR_DEBUG_FLAGS (0)
X
X /*==========================================================
X **
@@ -112,11 +116,13 @@
X #include <asm/dma.h>
X #include <asm/io.h>
X #include <asm/system.h>
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,93)
+#include <asm/spinlock.h>
+#endif
X #include <linux/delay.h>
X #include <linux/signal.h>
X #include <linux/sched.h>
X #include <linux/errno.h>
-#include <linux/bios32.h>
X #include <linux/pci.h>
X #include <linux/string.h>
X #include <linux/malloc.h>
@@ -127,11 +133,7 @@
X #include <linux/stat.h>
X
X #include <linux/version.h>
-#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0)
X #include <linux/blk.h>
-#else
-#include "../block/blk.h"
-#endif
X
X #if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,35)
X #include <linux/init.h>
@@ -144,6 +146,10 @@


X #endif
X #endif
X

+#if LINUX_VERSION_CODE <= LinuxVersionCode(2,1,92)
+#include <linux/bios32.h>
+#endif
+
X #include "scsi.h"
X #include "hosts.h"
X #include "constants.h"
@@ -152,14 +158,180 @@
X #include <linux/types.h>
X
X /*
-** Define the BSD style u_int32 type
+** Define BITS_PER_LONG for earlier linux versions.
+*/
+#ifndef BITS_PER_LONG
+#if (~0UL) == 0xffffffffUL
+#define BITS_PER_LONG 32
+#else
+#define BITS_PER_LONG 64
+#endif
+#endif
+
+/*
+** Define the BSD style u_int32 and u_int64 type.
+** Are in fact u_int32_t and u_int64_t :-)
X */
X typedef u32 u_int32;
+typedef u64 u_int64;
X
X #include "ncr53c8xx.h"
X
X /*==========================================================
X **
+** A la VMS/CAM-3 queue management.
+** Implemented from linux list management.
+**
+**==========================================================
+*/
+
+typedef struct xpt_quehead {
+ struct xpt_quehead *flink; /* Forward pointer */
+ struct xpt_quehead *blink; /* Backward pointer */
+} XPT_QUEHEAD;
+
+#define xpt_que_init(ptr) do { \
+ (ptr)->flink = (ptr); (ptr)->blink = (ptr); \
+} while (0)
+
+static inline void __xpt_que_add(struct xpt_quehead * new,
+ struct xpt_quehead * blink,
+ struct xpt_quehead * flink)
+{
+ flink->blink = new;
+ new->flink = flink;
+ new->blink = blink;
+ blink->flink = new;
+}
+
+static inline void __xpt_que_del(struct xpt_quehead * blink,
+ struct xpt_quehead * flink)
+{
+ flink->blink = blink;
+ blink->flink = flink;
+}
+
+static inline int xpt_que_empty(struct xpt_quehead *head)
+{
+ return head->flink == head;
+}
+
+static inline void xpt_que_splice(struct xpt_quehead *list,
+ struct xpt_quehead *head)
+{
+ struct xpt_quehead *first = list->flink;
+
+ if (first != list) {
+ struct xpt_quehead *last = list->blink;
+ struct xpt_quehead *at = head->flink;
+
+ first->blink = head;
+ head->flink = first;
+
+ last->flink = at;
+ at->blink = last;
+ }
+}
+
+#define xpt_que_entry(ptr, type, member) \
+ ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
+
+
+#define xpt_insque(new, pos) __xpt_que_add(new, pos, (pos)->flink)
+
+#define xpt_remque(el) __xpt_que_del((el)->blink, (el)->flink)
+
+#define xpt_insque_head(new, head) __xpt_que_add(new, head, (head)->flink)
+
+static inline struct xpt_quehead *xpt_remque_head(struct xpt_quehead *head)
+{
+ struct xpt_quehead *elem = head->flink;
+
+ if (elem != head)
+ __xpt_que_del(head, elem->flink);
+ else
+ elem = 0;
+ return elem;
+}
+
+#define xpt_insque_tail(new, head) __xpt_que_add(new, (head)->blink, head)
+
+static inline struct xpt_quehead *xpt_remque_tail(struct xpt_quehead *head)
+{
+ struct xpt_quehead *elem = head->blink;
+
+ if (elem != head)
+ __xpt_que_del(elem->blink, head);
+ else
+ elem = 0;
+ return elem;
+}
+
+/*==========================================================
+**
+** The CCB done queue uses an array of CCB virtual
+** addresses. Empty entries are flagged using the bogus
+** virtual address 0xffffffff.
+**
+** Since PCI ensures that only aligned DWORDs are accessed
+** atomically, 64 bit little-endian architecture requires
+** to test the high order DWORD of the entry to determine
+** if it is empty or valid.
+**
+** BTW, I will make things differently as soon as I will
+** have a better idea, but this is simple and should work.
+**
+**==========================================================
+*/
+
+#define SCSI_NCR_CCB_DONE_SUPPORT
+#ifdef SCSI_NCR_CCB_DONE_SUPPORT
+
+#define MAX_DONE 24
+#define CCB_DONE_EMPTY 0xffffffffUL
+
+/* All 32 bit architectures */
+#if BITS_PER_LONG == 32
+#define CCB_DONE_VALID(cp) (((u_long) cp) != CCB_DONE_EMPTY)
+
+/* All > 32 bit (64 bit) architectures regardless endian-ness */
+#else
+#define CCB_DONE_VALID(cp) \
+ ((((u_long) cp) & 0xffffffff00000000ul) && \
+ (((u_long) cp) & 0xfffffffful) != CCB_DONE_EMPTY)
+#endif
+
+#endif /* SCSI_NCR_CCB_DONE_SUPPORT */
+
+/*==========================================================
+**
+** On x86 architecture, write buffers management does
+** not reorder writes to memory. So, using compiler
+** optimization barriers is enough to guarantee some
+** ordering when the CPU is writing data accessed by
+** the NCR.
+** On Alpha architecture, explicit memory barriers have
+** to be used.
+** Other architectures are defaulted to mb() macro if
+** defined, otherwise use compiler barrier.
+**
+**==========================================================
+*/
+
+#if defined(__i386__)
+#define MEMORY_BARRIER() barrier()
+#elif defined(__alpha__)
+#define MEMORY_BARRIER() mb()
+#else
+# ifdef mb
+# define MEMORY_BARRIER() mb()
+# else
+# define MEMORY_BARRIER() barrier()
+# endif
+#endif
+
+/*==========================================================
+**
X ** Configuration and Debugging
X **
X **==========================================================
@@ -181,13 +353,33 @@
X */
X
X #ifndef SCSI_NCR_MAX_TAGS
-#define SCSI_NCR_MAX_TAGS (4)
+#define SCSI_NCR_MAX_TAGS (8)
+#endif
+
+/*
+** TAGS are actually limited to 64 tags/lun.
+** We need to deal with power of 2, for alignment constraints.
+*/
+#if SCSI_NCR_MAX_TAGS > 64
+#undef SCSI_NCR_MAX_TAGS
+#define SCSI_NCR_MAX_TAGS (64)
+#endif
+
+#define NO_TAG (255)
+
+/*
+** Choose appropriate type for tag bitmap.
+*/
+#if SCSI_NCR_MAX_TAGS > 32
+typedef u_int64 tagmap_t;
+#else
+typedef u_int32 tagmap_t;


X #endif
X
X /*

X ** Number of targets supported by the driver.
X ** n permits target numbers 0..n-1.
-** Default is 7, meaning targets #0..#6.
+** Default is 16, meaning targets #0..#15.
X ** #7 .. is myself.
X */
X
@@ -233,10 +425,23 @@
X
X /*
X ** The maximum number of segments a transfer is split into.
+** We support up to 127 segments for both read and write.
+** The data scripts are broken into 2 sub-scripts.
+** 80 (MAX_SCATTERL) segments are moved from a sub-script
+** in on-chip RAM. This makes data transfers shorter than
+** 80k (assuming 1k fs) as fast as possible.
X */
X
X #define MAX_SCATTER (SCSI_NCR_MAX_SCATTER)
X
+#if (MAX_SCATTER > 80)
+#define MAX_SCATTERL 80
+#define MAX_SCATTERH (MAX_SCATTER - MAX_SCATTERL)
+#else
+#define MAX_SCATTERL (MAX_SCATTER-1)
+#define MAX_SCATTERH 1
+#endif
+
X /*
X ** Io mapped or memory mapped.
X */
@@ -266,7 +471,6 @@
X ** Obvious definitions
X */
X
-#define printf printk
X #define u_char unsigned char
X #define u_short unsigned short
X #define u_int unsigned int
@@ -275,27 +479,83 @@
X typedef u_long vm_offset_t;
X typedef int vm_size_t;
X
+#ifndef bcopy
X #define bcopy(s, d, n) memcpy((d), (s), (n))
+#endif
+#ifndef bzero
X #define bzero(d, n) memset((d), 0, (n))
-
+#endif
+
X #ifndef offsetof
X #define offsetof(t, m) ((size_t) (&((t *)0)->m))


X #endif
X
X /*

+** SMP threading.
+**
+** Assuming that SMP systems are generally high end systems and may
+** use several SCSI adapters, we are using one lock per controller
+** instead of some global one. For the moment (linux-2.1.95), driver's
+** entry points are called with the 'io_request_lock' lock held, so:
+** - We are uselessly loosing a couple of micro-seconds to lock the
+** controller data structure.
+** - But the driver is not broken by design for SMP and so can be
+** more resistant to bugs or bad changes in the IO sub-system code.
+** - A small advantage could be that the interrupt code is grained as
+** wished (e.g.: threaded by controller).
+*/
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,93)
+
+#if 0 /* not yet needed */
+static spinlock_t driver_lock;
+#define NCR_LOCK_DRIVER(flags) spin_lock_irqsave(&driver_lock, flags)
+#define NCR_UNLOCK_DRIVER(flags) spin_unlock_irqrestore(&driver_lock, flags)
+#endif
+
+#define NCR_INIT_LOCK_NCB(np) spin_lock_init(&np->smp_lock);
+#define NCR_LOCK_NCB(np, flags) spin_lock_irqsave(&np->smp_lock, flags)
+#define NCR_UNLOCK_NCB(np, flags) spin_unlock_irqrestore(&np->smp_lock, flags)
+
+# if LINUX_VERSION_CODE < LinuxVersionCode(2,3,99)
+
+# define NCR_LOCK_SCSI_DONE(np, flags) \
+ spin_lock_irqsave(&io_request_lock, flags)
+# define NCR_UNLOCK_SCSI_DONE(np, flags) \
+ spin_unlock_irqrestore(&io_request_lock, flags)
+
+# else
+
+# define NCR_LOCK_SCSI_DONE(np, flags) do {;} while (0)
+# define NCR_UNLOCK_SCSI_DONE(np, flags) do {;} while (0)
+
+# endif
+
+#else
+
+#if 0 /* not yet needed */
+#define NCR_LOCK_DRIVER(flags) do {;} while (0)
+#define NCR_UNLOCK_DRIVER(flags) do {;} while (0)
+#endif
+
+#define NCR_INIT_LOCK_NCB(np) do { } while (0)
+#define NCR_LOCK_NCB(np, flags) do { save_flags(flags); cli(); } while (0)
+#define NCR_UNLOCK_NCB(np, flags) do { restore_flags(flags); } while (0)
+
+#define NCR_LOCK_SCSI_DONE(np, flags) do {;} while (0)
+#define NCR_UNLOCK_SCSI_DONE(np, flags) do {;} while (0)
+
+#endif
+
+/*
X ** Address translation
X **
-** On Linux 1.3.X, virt_to_bus() must be used to translate
-** virtual memory addresses of the kernel data segment into
-** IO bus adresses.
-** On i386 architecture, IO bus addresses match the physical
-** addresses. But on other architectures they can be different.
-** In the original Bsd driver, vtophys() is called to translate
-** data addresses to IO bus addresses. In order to minimize
-** change, I decide to define vtophys() as virt_to_bus().
+** The driver has to provide physical memory addresses to
+** the script processor. Because some architectures use
+** different physical addresses from the PCI BUS, we must
+** use virt_to_bus instead of virt_to_phys.
X */
X
-#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0)
X #define vtophys(p) virt_to_bus(p)
X
X /*
@@ -309,20 +569,29 @@
X ** architecture.
X */
X
-#ifndef NCR_IOMAPPED
+#if LINUX_VERSION_CODE < LinuxVersionCode(2,1,0)


+#define ioremap vremap
+#define iounmap vfree
+#endif
+

+#if defined (__sparc__)
+#include <asm/irq.h>
+#elif defined (__alpha__)
+#define bus_dvma_to_mem(p) ((p) & 0xfffffffful)
+#else
+#define bus_dvma_to_mem(p) (p)
+#endif
+
+#if defined(__i386__) || !defined(NCR_IOMAPPED)
X __initfunc(
X static vm_offset_t remap_pci_mem(u_long base, u_long size)
X )
X {
X u_long page_base = ((u_long) base) & PAGE_MASK;
X u_long page_offs = ((u_long) base) - page_base;
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,0)
X u_long page_remapped = (u_long) ioremap(page_base, page_offs+size);
-#else
- u_long page_remapped = (u_long) vremap(page_base, page_offs+size);
-#endif
X
- return (vm_offset_t) (page_remapped ? (page_remapped + page_offs) : 0UL);
+ return (vm_offset_t) (page_remapped? (page_remapped + page_offs) : 0UL);
X }
X
X __initfunc(
@@ -330,51 +599,40 @@
X )
X {
X if (vaddr)
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,0)
X iounmap((void *) (vaddr & PAGE_MASK));
-#else
- vfree((void *) (vaddr & PAGE_MASK));
-#endif
X }
-#endif /* !NCR_IOMAPPED */
-
-#else /* linux-1.2.13 */
+#endif /* __i386__ || !NCR_IOMAPPED */
X
X /*
-** Linux 1.2.X assumes that addresses (virtual, physical, bus)
-** are the same.
-**
-** I have not found how to do MMIO. It seems that only processes can
-** map high physical pages to virtual (Xservers can do MMIO).
-*/
-
-#define vtophys(p) ((u_long) (p))
+** Insert a delay in micro-seconds and milli-seconds.
+** -------------------------------------------------
+** Under Linux, udelay() is restricted to delay < 1 milli-second.
+** In fact, it generally works for up to 1 second delay.
+** Since 2.1.105, the mdelay() function is provided for delays
+** in milli-seconds.
+** Under 2.0 kernels, udelay() is an inline function that is very
+** inaccurate on Pentium processors.
+*/
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,105)
+#define UDELAY udelay
+#define MDELAY mdelay
+#else
+static void UDELAY(long us) { udelay(us); }
+static void MDELAY(long ms) { while (ms--) UDELAY(1000); }


X #endif
X
X /*

-** Insert a delay in micro-seconds.
-*/
-
-static void DELAY(long us)
-{
- for (;us>1000;us-=1000) udelay(1000);
- if (us) udelay(us);
-}
-
-/*
X ** Internal data structure allocation.
X **
X ** Linux scsi memory poor pool is adjusted for the need of
X ** middle-level scsi driver.
X ** We allocate our control blocks in the kernel memory pool
X ** to avoid scsi pool shortage.
-** I notice that kmalloc() returns NULL during host attach under
-** Linux 1.2.13. But this ncr driver is reliable enough to
-** accomodate with this joke.
X **
-** kmalloc() only ensure 8 bytes boundary alignment.
+** kmalloc() only ensures 8 bytes boundary alignment.
X ** The NCR need better alignment for cache line bursting.
-** The global header is moved betewen the NCB and CCBs and need
+** The global header is moved between the NCB and CCBs and needs
X ** origin and destination addresses to have same lower four bits.
X **
X ** We use 32 boundary alignment for NCB and CCBs and offset multiple
@@ -384,17 +642,9 @@
X #define ALIGN_SIZE(shift) (1UL << shift)
X #define ALIGN_MASK(shift) (~(ALIGN_SIZE(shift)-1))
X
-#define NCB_ALIGN_SHIFT 5
-#define CCB_ALIGN_SHIFT 5
-#define LCB_ALIGN_SHIFT 5
-#define SCR_ALIGN_SHIFT 5
-
-#define NCB_ALIGN_SIZE ALIGN_SIZE(NCB_ALIGN_SHIFT)
-#define NCB_ALIGN_MASK ALIGN_MASK(NCB_ALIGN_SHIFT)
-#define CCB_ALIGN_SIZE ALIGN_SIZE(CCB_ALIGN_SHIFT)
-#define CCB_ALIGN_MASK ALIGN_MASK(CCB_ALIGN_SHIFT)
-#define SCR_ALIGN_SIZE ALIGN_SIZE(SCR_ALIGN_SHIFT)
-#define SCR_ALIGN_MASK ALIGN_MASK(SCR_ALIGN_SHIFT)
+#define CACHE_LINE_SHIFT 5
+#define CACHE_LINE_SIZE ALIGN_SIZE(CACHE_LINE_SHIFT)
+#define CACHE_LINE_MASK ALIGN_MASK(CACHE_LINE_SHIFT)
X
X static void *m_alloc(int size, int a_shift)
X {
@@ -448,11 +698,8 @@
X ** be able to transfer data in the direction choosen by the target.
X */
X
-#define XferNone 0
-#define XferIn 1
-#define XferOut 2
-#define XferBoth 3
-static int guess_xfer_direction(int opcode);
+#define XFER_IN (1)
+#define XFER_OUT (2)
X
X /*
X ** Head of list of NCR boards
@@ -470,45 +717,30 @@
X ** /proc directory entry and proc_info function
X */
X
-#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0)
X struct proc_dir_entry proc_scsi_ncr53c8xx = {
X PROC_SCSI_NCR53C8XX, 9, "ncr53c8xx",
X S_IFDIR | S_IRUGO | S_IXUGO, 2
X };
-# ifdef SCSI_NCR_PROC_INFO_SUPPORT
+#ifdef SCSI_NCR_PROC_INFO_SUPPORT
X int ncr53c8xx_proc_info(char *buffer, char **start, off_t offset,
X int length, int hostno, int func);
-# endif


X #endif
X
X /*

-** Table of target capabilities.
-**
-** This bitmap is anded with the byte 7 of inquiry data on completion of
-** INQUIRY command.
-** The driver never see zeroed bits and will ignore the corresponding
-** capabilities of the target.
-*/
-
-static struct {
- unsigned char and_map[MAX_TARGET];
-} target_capabilities[SCSI_NCR_MAX_HOST] = { NCR53C8XX_TARGET_CAPABILITIES };
-
-/*
X ** Driver setup.
X **
X ** This structure is initialized from linux config options.
X ** It can be overridden at boot-up by the boot command line.
X */
X struct ncr_driver_setup {
- unsigned master_parity : 1;
- unsigned scsi_parity : 1;
- unsigned disconnection : 1;
- unsigned special_features : 2;
- unsigned ultra_scsi : 2;
- unsigned force_sync_nego: 1;
- unsigned reverse_probe: 1;
- unsigned pci_fix_up: 4;
+ u_char master_parity;
+ u_char scsi_parity;
+ u_char disconnection;
+ u_char special_features;
+ u_char ultra_scsi;
+ u_char force_sync_nego;
+ u_char reverse_probe;
+ u_char pci_fix_up;
X u_char use_nvram;
X u_char verbose;
X u_char default_tags;
@@ -521,6 +753,7 @@
X u_char diff_support;
X u_char irqm;
X u_char bus_check;
+ char tag_ctrl[100];
X };
X
X static struct ncr_driver_setup
@@ -529,9 +762,12 @@
X #ifdef SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT
X static struct ncr_driver_setup
X driver_safe_setup __initdata = SCSI_NCR_DRIVER_SAFE_SETUP;
-#ifdef MODULE
+# ifdef MODULE
X char *ncr53c8xx = 0; /* command line passed by insmod */
-#endif
+# if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,30)
+MODULE_PARM(ncr53c8xx, "s");
+# endif
+# endif


X #endif
X
X /*

@@ -540,16 +776,9 @@
X
X #define ScsiResult(host_code, scsi_code) (((host_code) << 16) + ((scsi_code) & 0x7f))
X
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,0,0)
-static void ncr53c8xx_select_queue_depths(struct Scsi_Host *host, struct scsi_device *devlist);
-#endif
-
-#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,70)
+static void ncr53c8xx_select_queue_depths(
+ struct Scsi_Host *host, struct scsi_device *devlist);
X static void ncr53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs);
-#else
-static void ncr53c8xx_intr(int irq, struct pt_regs * regs);
-#endif
-
X static void ncr53c8xx_timeout(unsigned long np);
X
X #define initverbose (driver_setup.verbose)
@@ -576,6 +805,7 @@
X #define SYMBIOS_SCAM_ENABLE (1)
X #define SYMBIOS_PARITY_ENABLE (1<<1)
X #define SYMBIOS_VERBOSE_MSGS (1<<2)
+#define SYMBIOS_CHS_MAPPING (1<<3)
X u_short flags1;
X #define SYMBIOS_SCAN_HI_LO (1)
X u_short word10; /* 0x00 */
@@ -666,13 +896,13 @@
X typedef struct {
X int bus;
X u_char device_fn;
- u_int base;
- u_int base_2;
- u_int io_port;
+ u_long base;
+ u_long base_2;
+ u_long io_port;
X int irq;
X /* port and reg fields to use INB, OUTB macros */
- u_int port;
- volatile struct ncr_reg *reg;
+ u_long port;
+ volatile struct ncr_reg *reg;
X } ncr_slot;
X
X typedef struct {
@@ -745,7 +975,7 @@
X
X #define assert(expression) { \
X if (!(expression)) { \
- (void)printf(\
+ (void)printk(KERN_ERR \
X "assertion \"%s\" failed: file \"%s\", line %d\n", \
X #expression, \
X __FILE__, __LINE__); \
@@ -808,7 +1038,12 @@
X **
X ** Access to the controller chip.
X **
-** If NCR_IOMAPPED is defined, only IO are used by the driver.
+** If NCR_IOMAPPED is defined, the driver will use
+** normal IOs instead of the MEMORY MAPPED IO method
+** recommended by PCI specifications.
+** If all PCI bridges, host brigdes and architectures
+** would have been correctly designed for PCI, this
+** option would be useless.
X **
X **==========================================================
X */
@@ -928,15 +1163,31 @@
X #define HS_NEGOTIATE (2) /* sync/wide data transfer*/
X #define HS_DISCONNECT (3) /* Disconnected by target */
X
-#define HS_COMPLETE (4)
-#define HS_SEL_TIMEOUT (5) /* Selection timeout */
-#define HS_RESET (6) /* SCSI reset */
-#define HS_ABORTED (7) /* Transfer aborted */
-#define HS_TIMEOUT (8) /* Software timeout */
-#define HS_FAIL (9) /* SCSI or PCI bus errors */
-#define HS_UNEXPECTED (10) /* Unexpected disconnect */
+#define HS_DONEMASK (0x80)
+#define HS_COMPLETE (4|HS_DONEMASK)
+#define HS_SEL_TIMEOUT (5|HS_DONEMASK) /* Selection timeout */
+#define HS_RESET (6|HS_DONEMASK) /* SCSI reset */
+#define HS_ABORTED (7|HS_DONEMASK) /* Transfer aborted */
+#define HS_TIMEOUT (8|HS_DONEMASK) /* Software timeout */
+#define HS_FAIL (9|HS_DONEMASK) /* SCSI or PCI bus errors */
+#define HS_UNEXPECTED (10|HS_DONEMASK)/* Unexpected disconnect */
X
-#define HS_DONEMASK (0xfc)
+/*
+** Invalid host status values used by the SCRIPTS processor
+** when the nexus is not fully identified.
+** Shall never appear in a CCB.
+*/
+
+#define HS_INVALMASK (0x40)
+#define HS_SELECTING (0|HS_INVALMASK)
+#define HS_IN_RESELECT (1|HS_INVALMASK)
+#define HS_STARTING (2|HS_INVALMASK)
+
+/*
+** Flags set by the SCRIPT processor for commands
+** that have been skipped.
+*/
+#define HS_SKIPMASK (0x20)
X
X /*==========================================================
X **
@@ -945,21 +1196,24 @@
X **==========================================================
X */
X
-#define SIR_SENSE_RESTART (1)
-#define SIR_SENSE_FAILED (2)
-#define SIR_STALL_RESTART (3)
-#define SIR_STALL_QUEUE (4)
-#define SIR_NEGO_SYNC (5)
-#define SIR_NEGO_WIDE (6)
-#define SIR_NEGO_FAILED (7)
-#define SIR_NEGO_PROTO (8)
-#define SIR_REJECT_RECEIVED (9)
-#define SIR_REJECT_SENT (10)
-#define SIR_IGN_RESIDUE (11)
-#define SIR_MISSING_SAVE (12)
-#define SIR_DATA_IO_IS_OUT (13)
-#define SIR_DATA_IO_IS_IN (14)
-#define SIR_MAX (14)
+#define SIR_BAD_STATUS (1)
+#define SIR_XXXXXXXXXX (2)
+#define SIR_NEGO_SYNC (3)
+#define SIR_NEGO_WIDE (4)
+#define SIR_NEGO_FAILED (5)
+#define SIR_NEGO_PROTO (6)
+#define SIR_REJECT_RECEIVED (7)
+#define SIR_REJECT_SENT (8)
+#define SIR_IGN_RESIDUE (9)
+#define SIR_MISSING_SAVE (10)
+#define SIR_RESEL_NO_MSG_IN (11)
+#define SIR_RESEL_NO_IDENTIFY (12)
+#define SIR_RESEL_BAD_LUN (13)
+#define SIR_RESEL_BAD_TARGET (14)
+#define SIR_RESEL_BAD_I_T_L (15)
+#define SIR_RESEL_BAD_I_T_L_Q (16)
+#define SIR_DONE_OVERFLOW (17)
+#define SIR_MAX (17)
X
X /*==========================================================
X **
@@ -997,7 +1251,6 @@
X #define QUIRK_NOMSG (0x02)
X #define QUIRK_NOSYNC (0x10)
X #define QUIRK_NOWIDE16 (0x20)
-#define QUIRK_UPDATE (0x80)
X
X /*==========================================================
X **
@@ -1056,10 +1309,7 @@
X #define UC_SETWIDE 14
X #define UC_SETFLAG 15
X #define UC_CLEARPROF 16
-
-#ifdef SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
-#define UC_DEBUG_ERROR_RECOVERY 17
-#endif
+#define UC_SETVERBOSE 17
X
X #define UF_TRACE (0x01)
X #define UF_NODISC (0x02)
@@ -1072,10 +1322,11 @@
X **---------------------------------------
X */
X
+#ifdef SCSI_NCR_PROFILE_SUPPORT
+
X struct tstamp {
X u_long start;
X u_long end;
- u_long select;
X u_long command;
X u_long status;
X u_long disconnect;
@@ -1099,263 +1350,257 @@
X u_long ms_disc;
X u_long ms_post;
X };
+#endif
X
-/*==========================================================
+/*========================================================================
X **
X ** Declaration of structs: target control block
X **
-**==========================================================
+**========================================================================
X */
-
X struct tcb {
- /*
- ** during reselection the ncr jumps to this point
- ** with SFBR set to the encoded target number
- ** with bit 7 set.
+ /*----------------------------------------------------------------
+ ** During reselection the ncr jumps to this point with SFBR
+ ** set to the encoded target number with bit 7 set.
X ** if it's not this target, jump to the next.
X **
- ** JUMP IF (SFBR != #target#)
- ** @(next tcb)
+ ** JUMP IF (SFBR != #target#), @(next tcb)
+ **----------------------------------------------------------------
X */
-
X struct link jump_tcb;
X
- /*
- ** load the actual values for the sxfer and the scntl3
+ /*----------------------------------------------------------------
+ ** Load the actual values for the sxfer and the scntl3
X ** register (sync/wide mode).
X **
- ** SCR_COPY (1);
- ** @(sval field of this tcb)
- ** @(sxfer register)
- ** SCR_COPY (1);
- ** @(wval field of this tcb)
- ** @(scntl3 register)
+ ** SCR_COPY (1), @(sval field of this tcb), @(sxfer register)
+ ** SCR_COPY (1), @(wval field of this tcb), @(scntl3 register)
+ **----------------------------------------------------------------
X */
-
X ncrcmd getscr[6];
X
- /*
- ** if next message is "identify"
- ** then load the message to SFBR,
- ** else load 0 to SFBR.
+ /*----------------------------------------------------------------
+ ** Get the IDENTIFY message and load the LUN to SFBR.
X **
- ** CALL
- ** <RESEL_LUN>
+ ** CALL, <RESEL_LUN>
+ **----------------------------------------------------------------
X */
-
X struct link call_lun;
X
- /*
- ** now look for the right lun.
+ /*----------------------------------------------------------------
+ ** Now look for the right lun.
X **
- ** JUMP
- ** @(first ccb of this lun)
- */
-
- struct link jump_lcb;
-
- /*
- ** pointer to interrupted getcc ccb
- */
-
- ccb_p hold_cp;
-
- /*
- ** pointer to ccb used for negotiating.
- ** Avoid to start a nego for all queued commands
+ ** For i = 0 to 3
+ ** SCR_JUMP ^ IFTRUE(MASK(i, 3)), @(first lcb mod. i)
+ **
+ ** Recent chips will prefetch the 4 JUMPS using only 1 burst.
+ ** It is kind of hashcoding.
+ **----------------------------------------------------------------
+ */
+ struct link jump_lcb[4]; /* JUMPs for reselection */
+ lcb_p lp[MAX_LUN]; /* The lcb's of this tcb */
+ u_char inq_done; /* Target capabilities received */
+ u_char inq_byte7; /* Contains these capabilities */
+
+ /*----------------------------------------------------------------
+ ** Pointer to the ccb used for negotiation.
+ ** Prevent from starting a negotiation for all queued commands
X ** when tagged command queuing is enabled.
+ **----------------------------------------------------------------
X */
-
X ccb_p nego_cp;
X
- /*
+ /*----------------------------------------------------------------
X ** statistical data
+ **----------------------------------------------------------------
X */
-
X u_long transfers;
X u_long bytes;
X
- /*
- ** user settable limits for sync transfer
- ** and tagged commands.
- ** These limits are read from the NVRAM if present.
- */
-
- u_char usrsync;
- u_char usrwide;
- u_char usrtags;
- u_char usrflag;
-
- u_char numtags;
- u_char maxtags;
- u_short num_good;
-
- /*
- ** negotiation of wide and synch transfer.
- ** device quirks.
+ /*----------------------------------------------------------------
+ ** negotiation of wide and synch transfer and device quirks.
+ **----------------------------------------------------------------
X */
-
X /*0*/ u_char minsync;
X /*1*/ u_char sval;
X /*2*/ u_short period;
X /*0*/ u_char maxoffs;
-
X /*1*/ u_char quirks;
-
X /*2*/ u_char widedone;
X /*3*/ u_char wval;
- /*
- ** inquire data
- */
-#define MAX_INQUIRE 36
- u_char inqdata[MAX_INQUIRE];
X
- /*
- ** the lcb's of this tcb
+ /*----------------------------------------------------------------
+ ** User settable limits and options.
+ ** These limits are read from the NVRAM if present.
+ **----------------------------------------------------------------
X */
-
- lcb_p lp[MAX_LUN];
+ u_char usrsync;
+ u_char usrwide;
+ u_char usrtags;
+ u_char usrflag;
X };
X
-/*==========================================================
+/*========================================================================
X **
X ** Declaration of structs: lun control block
X **
-**==========================================================
+**========================================================================
X */
-
X struct lcb {
- /*
- ** during reselection the ncr jumps to this point
+ /*----------------------------------------------------------------
+ ** During reselection the ncr jumps to this point
X ** with SFBR set to the "Identify" message.
X ** if it's not this lun, jump to the next.
X **
- ** JUMP IF (SFBR != #lun#)
- ** @(next lcb of this target)
- */
-
- struct link jump_lcb;
-
- /*
- ** if next message is "simple tag",
- ** then load the tag to SFBR,
- ** else load 0 to SFBR.
+ ** JUMP IF (SFBR != #lun#), @(next lcb of this target)
X **
- ** CALL
- ** <RESEL_TAG>
- */
-
- struct link call_tag;
-
- /*
- ** now look for the right ccb.
+ ** It is this lun. Load TEMP with the nexus jumps table
+ ** address and jump to RESEL_TAG (or RESEL_NOTAG).
X **
- ** JUMP
- ** @(first ccb of this lun)
- */
-
- struct link jump_ccb;
-
- /*
- ** start of the ccb chain
- */
-
- ccb_p next_ccb;
-
- /*
- ** Control of tagged queueing
- */
-
- u_char reqccbs;
- u_char actccbs;
- u_char reqlink;
- u_char actlink;
- u_char usetags;
- u_char lasttag;
-
- /*
- ** Linux specific fields:
- ** Number of active commands and current credit.
- ** Should be managed by the generic scsi driver
+ ** SCR_COPY (4), p_jump_ccb, TEMP,
+ ** SCR_JUMP, <RESEL_TAG>
+ **----------------------------------------------------------------
X */
+ struct link jump_lcb;
+ ncrcmd load_jump_ccb[3];
+ struct link jump_tag;
+ ncrcmd p_jump_ccb; /* Jump table bus address */
+
+ /*----------------------------------------------------------------
+ ** Jump table used by the script processor to directly jump
+ ** to the CCB corresponding to the reselected nexus.
+ ** Address is allocated on 256 bytes boundary in order to
+ ** allow 8 bit calculation of the tag jump entry for up to
+ ** 64 possible tags.
+ **----------------------------------------------------------------
+ */
+ u_int32 jump_ccb_0; /* Default table if no tags */
+ u_int32 *jump_ccb; /* Virtual address */
+
+ /*----------------------------------------------------------------
+ ** CCB queue management.
+ **----------------------------------------------------------------
+ */
+ XPT_QUEHEAD free_ccbq; /* Queue of available CCBs */
+ XPT_QUEHEAD busy_ccbq; /* Queue of busy CCBs */
+ XPT_QUEHEAD wait_ccbq; /* Queue of waiting for IO CCBs */
+ XPT_QUEHEAD skip_ccbq; /* Queue of skipped CCBs */
+ u_char actccbs; /* Number of allocated CCBs */
+ u_char busyccbs; /* CCBs busy for this lun */
+ u_char queuedccbs; /* CCBs queued to the controller*/
+ u_char queuedepth; /* Queue depth for this lun */
+ u_char scdev_depth; /* SCSI device queue depth */
+ u_char maxnxs; /* Max possible nexuses */
+
+ /*----------------------------------------------------------------
+ ** Control of tagged command queuing.
+ ** Tags allocation is performed using a circular buffer.
+ ** This avoids using a loop for tag allocation.
+ **----------------------------------------------------------------
+ */
+ u_char ia_tag; /* Allocation index */
+ u_char if_tag; /* Freeing index */
+ u_char cb_tags[SCSI_NCR_MAX_TAGS]; /* Circular tags buffer */
+ u_char usetags; /* Command queuing is active */
+ u_char maxtags; /* Max nr of tags asked by user */
+ u_char numtags; /* Current number of tags */
+ u_char inq_byte7; /* Store unit CmdQ capabitility */
+
+ /*----------------------------------------------------------------


SHAR_EOF
true || echo 'restore of patch-2.0.37 failed'
fi

echo 'End of part 29'
echo 'File patch-2.0.37 is continued in part 30'
echo 30 > _shar_seq_.tmp
exit 0

Thomas...@ciw.uni-karlsruhe.de

unread,
Jun 16, 1999, 3:00:00 AM6/16/99
to
Archive-name: v2.0/patch-2.0.37/part32

#!/bin/sh
# this is part 32 of a 45 - part archive


# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.0.37 continued
if test ! -r _shar_seq_.tmp; then
echo 'Please unpack part 1 first!'
exit 1
fi
(read Scheck

if test "$Scheck" != 32; then


echo Please unpack part "$Scheck" next!
exit 1
else
exit 0
fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.0.37'
else
echo 'x - continuing with patch-2.0.37'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.0.37' &&

X **
X **==========================================================
X */

-static void ncr_start_reset(ncb_p np, int settle_delay)
+static void ncr_start_reset(ncb_p np)
X {
- u_long flags;
-
- save_flags(flags); cli();
-
X if (!np->settle_time) {
- (void) ncr_reset_scsi_bus(np, 1, settle_delay);
- }
- restore_flags(flags);
-}
-
+ (void) ncr_reset_scsi_bus(np, 1, driver_setup.settle_delay);
+ }
+ }
+
X static int ncr_reset_scsi_bus(ncb_p np, int enab_int, int settle_delay)
X {
X u_int32 term;
@@ -5234,13 +5340,14 @@
X np->settle_time = jiffies + settle_delay * HZ;
X
X if (bootverbose > 1)
- printf("%s: resetting, "
+ printk("%s: resetting, "
X "command processing suspended for %d seconds\n",
X ncr_name(np), settle_delay);
X
X OUTB (nc_istat, SRST);
- DELAY (1000);
+ UDELAY (100);
X OUTB (nc_istat, 0);
+ UDELAY (2000); /* The 895 needs time for the bus mode to settle */
X if (enab_int)
X OUTW (nc_sien, RST);
X /*
@@ -5250,7 +5357,7 @@
X OUTB (nc_stest3, TE);
X OUTB (nc_dcntl, (np->rv_dcntl & IRQM));
X OUTB (nc_scntl1, CRST);
- DELAY (100);
+ UDELAY (200);
X
X if (!driver_setup.bus_check)
X goto out;
@@ -5270,9 +5377,9 @@
X term &= 0x3ffff;
X
X if (term != (2<<7)) {
- printf("%s: suspicious SCSI data while resetting the BUS.\n",
+ printk("%s: suspicious SCSI data while resetting the BUS.\n",
X ncr_name(np));
- printf("%s: %sdp0,d7-0,rst,req,ack,bsy,sel,atn,msg,c/d,i/o = "
+ printk("%s: %sdp0,d7-0,rst,req,ack,bsy,sel,atn,msg,c/d,i/o = "
X "0x%lx, expecting 0x%lx\n",
X ncr_name(np),
X (np->features & FE_WIDE) ? "dp1,d15-8," : "",
@@ -5294,27 +5401,16 @@


X **
X **==========================================================
X */

-int ncr_reset_bus (Scsi_Cmnd *cmd, int sync_reset)
+int ncr_reset_bus (ncb_p np, Scsi_Cmnd *cmd, int sync_reset)
X {
- struct Scsi_Host *host = cmd->host;
X /* Scsi_Device *device = cmd->device; */
- struct host_data *host_data = (struct host_data *) host->hostdata;
- ncb_p np = host_data->ncb;
X ccb_p cp;
- u_long flags;
X int found;
X
-#ifdef SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
- if (np->stalling)
- np->stalling = 0;
-#endif
-
- save_flags(flags); cli();
X /*
X * Return immediately if reset is in progress.
X */
X if (np->settle_time) {
- restore_flags(flags);
X return SCSI_RESET_PUNT;
X }
X /*
@@ -5323,7 +5419,7 @@
X * Commands will now be queued in the waiting list until a settle
X * delay of 2 seconds will be completed.
X */
- ncr_start_reset(np, driver_setup.settle_delay);
+ ncr_start_reset(np);
X /*
X * First, look in the wakeup list
X */
@@ -5358,11 +5454,9 @@
X */
X if (!found && sync_reset && !retrieve_from_waiting_list(0, np, cmd)) {
X cmd->result = ScsiResult(DID_RESET, 0);
- cmd->scsi_done(cmd);
+ ncr_queue_done_cmd(np, cmd);
X }
X
- restore_flags(flags);
-
X return SCSI_RESET_SUCCESS;
X }
X
@@ -5375,30 +5469,19 @@


X **
X **==========================================================
X */

-static int ncr_abort_command (Scsi_Cmnd *cmd)
+static int ncr_abort_command (ncb_p np, Scsi_Cmnd *cmd)
X {
- struct Scsi_Host *host = cmd->host;
X /* Scsi_Device *device = cmd->device; */
- struct host_data *host_data = (struct host_data *) host->hostdata;
- ncb_p np = host_data->ncb;
X ccb_p cp;
- u_long flags;
X int found;
X int retv;
X
-#ifdef SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
- if (np->stalling == 2)
- np->stalling = 0;
-#endif
-
- save_flags(flags); cli();
X /*
X * First, look for the scsi command in the waiting list
X */
X if (remove_from_waiting_list(np, cmd)) {
X cmd->result = ScsiResult(DID_ABORT, 0);
- cmd->scsi_done(cmd);
- restore_flags(flags);
+ ncr_queue_done_cmd(np, cmd);
X return SCSI_ABORT_SUCCESS;
X }
X
@@ -5417,45 +5500,45 @@
X }
X
X if (!found) {
- restore_flags(flags);
X return SCSI_ABORT_NOT_RUNNING;
X }
X
X if (np->settle_time) {
- restore_flags(flags);


X return SCSI_ABORT_SNOOZE;
X }
X
X /*

- ** Disable reselect.
- ** Remove it from startqueue.
- ** Set cp->tlimit to 0. The ncr_timeout() handler will use
- ** this condition in order to complete the canceled command
- ** after the script skipped the ccb, if necessary.
- */
- cp->jump_ccb.l_cmd = cpu_to_scr(SCR_JUMP);
- if (cp->phys.header.launch.l_paddr ==
- cpu_to_scr(NCB_SCRIPT_PHYS (np, select))) {
- printf ("%s: abort ccb=%p (skip)\n", ncr_name (np), cp);
- cp->phys.header.launch.l_paddr =
- cpu_to_scr(NCB_SCRIPT_PHYS (np, skip));
- }
+ ** If the CCB is active, patch schedule jumps for the
+ ** script to abort the command.
+ */
X
X cp->tlimit = 0;
- retv = SCSI_ABORT_PENDING;
+ switch(cp->host_status) {
+ case HS_BUSY:
+ case HS_NEGOTIATE:
+ printk ("%s: abort ccb=%p (cancel)\n", ncr_name (np), cp);
+ cp->start.schedule.l_paddr =
+ cpu_to_scr(NCB_SCRIPTH_PHYS (np, cancel));
+ retv = SCSI_ABORT_PENDING;
+ break;
+ case HS_DISCONNECT:
+ cp->restart.schedule.l_paddr =
+ cpu_to_scr(NCB_SCRIPTH_PHYS (np, abort));
+ retv = SCSI_ABORT_PENDING;
+ break;
+ default:
+ retv = SCSI_ABORT_NOT_RUNNING;
+ break;
+
+ }
X
X /*
X ** If there are no requests, the script
X ** processor will sleep on SEL_WAIT_RESEL.
X ** Let's wake it up, since it may have to work.
X */
-#ifdef SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
- if (!np->stalling)
-#endif
X OUTB (nc_istat, SIGP);
X
- restore_flags(flags);
-
X return retv;
X }
X
@@ -5479,7 +5562,7 @@
X int target, lun;
X int i;
X
- printf("%s: releasing host resources\n", ncr_name(np));
+ printk("%s: releasing host resources\n", ncr_name(np));
X
X /*
X ** Stop the ncr_timeout process
@@ -5487,12 +5570,12 @@
X */
X
X #ifdef DEBUG_NCR53C8XX
- printf("%s: stopping the timer\n", ncr_name(np));
+ printk("%s: stopping the timer\n", ncr_name(np));
X #endif
X np->release_stage = 1;
- for (i = 50 ; i && np->release_stage != 2 ; i--) DELAY(100000);
+ for (i = 50 ; i && np->release_stage != 2 ; i--) MDELAY (100);
X if (np->release_stage != 2)
- printf("%s: the timer seems to be already stopped\n", ncr_name(np));
+ printk("%s: the timer seems to be already stopped\n", ncr_name(np));
X else np->release_stage = 2;
X
X /*
@@ -5500,7 +5583,7 @@
X */
X
X #ifdef DEBUG_NCR53C8XX
- printf("%s: disabling chip interrupts\n", ncr_name(np));
+ printk("%s: disabling chip interrupts\n", ncr_name(np));
X #endif
X OUTW (nc_sien , 0);
X OUTB (nc_dien , 0);
@@ -5510,22 +5593,22 @@
X */
X
X #ifdef DEBUG_NCR53C8XX
- printf("%s: freeing irq %d\n", ncr_name(np), np->irq);
-#endif
-#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,70)
- free_irq(np->irq, np);
+#ifdef __sparc__
+ printk("%s: freeing irq %s\n", ncr_name(np), __irq_itoa(np->irq));
X #else
- free_irq(np->irq);
+ printk("%s: freeing irq %d\n", ncr_name(np), np->irq);
X #endif
+#endif
+ free_irq(np->irq, np);
X
X /*
X ** Reset NCR chip
X ** Restore bios setting for automatic clock detection.
X */
X
- printf("%s: resetting chip\n", ncr_name(np));
+ printk("%s: resetting chip\n", ncr_name(np));
X OUTB (nc_istat, SRST);
- DELAY (1000);
+ UDELAY (100);
X OUTB (nc_istat, 0 );
X
X OUTB(nc_dmode, np->sv_dmode);
@@ -5544,17 +5627,13 @@
X
X #ifndef NCR_IOMAPPED
X #ifdef DEBUG_NCR53C8XX
- printf("%s: releasing memory mapped IO region %lx[%d]\n", ncr_name(np), (u_long) np->vaddr, 128);
+ printk("%s: releasing memory mapped IO region %lx[%d]\n", ncr_name(np), (u_long) np->vaddr, 128);
X #endif
X unmap_pci_mem((vm_offset_t) np->vaddr, (u_long) 128);
-#ifdef DEBUG_NCR53C8XX
- printf("%s: releasing memory mapped IO region %lx[%d]\n", ncr_name(np), (u_long) np->vaddr2, 4096);
-#endif
- unmap_pci_mem((vm_offset_t) np->vaddr2, (u_long) 4096);
-#endif
+#endif /* !NCR_IOMAPPED */
X
X #ifdef DEBUG_NCR53C8XX
- printf("%s: releasing IO region %x[%d]\n", ncr_name(np), np->port, 128);
+ printk("%s: releasing IO region %x[%d]\n", ncr_name(np), np->port, 128);
X #endif
X release_region(np->port, 128);
X
@@ -5565,11 +5644,11 @@
X while ((cp=np->ccb->link_ccb) != NULL) {
X np->ccb->link_ccb = cp->link_ccb;
X if (cp->host_status) {
- printf("%s: shall free an active ccb (host_status=%d)\n",
+ printk("%s: shall free an active ccb (host_status=%d)\n",
X ncr_name(np), cp->host_status);
X }
X #ifdef DEBUG_NCR53C8XX
- printf("%s: freeing ccb (%lx)\n", ncr_name(np), (u_long) cp);
+ printk("%s: freeing ccb (%lx)\n", ncr_name(np), (u_long) cp);
X #endif
X m_free(cp, sizeof(*cp));
X }
@@ -5584,14 +5663,16 @@
X lp = tp->lp[lun];
X if (lp) {
X #ifdef DEBUG_NCR53C8XX
- printf("%s: freeing lp (%lx)\n", ncr_name(np), (u_long) lp);
+ printk("%s: freeing lp (%lx)\n", ncr_name(np), (u_long) lp);
X #endif
+ if (lp->jump_ccb != &lp->jump_ccb_0)
+ m_free(lp->jump_ccb, 256);
X m_free(lp, sizeof(*lp));
X }
X }
X }
X
- printf("%s: host resources successfully released\n", ncr_name(np));
+ printk("%s: host resources successfully released\n", ncr_name(np));
X
X return 1;
X }
@@ -5617,20 +5698,8 @@
X ** Sanity check
X */
X
- if (!cp || (cp->magic!=CCB_MAGIC) || !cp->cmd) return;
- cp->magic = 1;
- cp->tlimit= 0;
- cmd = cp->cmd;
-
- /*
- ** No Reselect anymore.
- */
- cp->jump_ccb.l_cmd = cpu_to_scr(SCR_JUMP);
-
- /*
- ** No starting.
- */
- cp->phys.header.launch.l_paddr = cpu_to_scr(NCB_SCRIPT_PHYS (np, idle));
+ if (!cp || cp->magic != CCB_MAGIC || !cp->cmd)
+ return;
X
X /*
X ** timestamp
@@ -5641,9 +5710,13 @@
X #endif
X
X if (DEBUG_FLAGS & DEBUG_TINY)
- printf ("CCB=%lx STAT=%x/%x\n", (unsigned long)cp & 0xfff,
+ printk ("CCB=%lx STAT=%x/%x\n", (unsigned long)cp & 0xfff,
X cp->host_status,cp->scsi_status);
X
+ /*
+ ** Get command, target and lun pointers.
+ */
+
X cmd = cp->cmd;
X cp->cmd = NULL;
X tp = &np->target[cmd->target];
@@ -5659,17 +5732,32 @@
X tp->nego_cp = 0;
X
X /*
+ ** If auto-sense performed, change scsi status.
+ */
+ if (cp->auto_sense) {
+ cp->scsi_status = cp->auto_sense;
+ }
+
+ /*
+ ** If we were recovering from queue full or performing
+ ** auto-sense, requeue skipped CCBs to the wait queue.
+ */
+
+ if (lp && lp->held_ccb) {
+ if (cp == lp->held_ccb) {
+ xpt_que_splice(&lp->skip_ccbq, &lp->wait_ccbq);
+ xpt_que_init(&lp->skip_ccbq);
+ lp->held_ccb = 0;
+ }
+ }
+
+ /*
X ** Check for parity errors.
X */
X
- if (cp->parity_status) {
+ if (cp->parity_status > 1) {
X PRINT_ADDR(cmd);
- printf ("%d parity error(s), fallback.\n", cp->parity_status);
- /*
- ** fallback to asynch transfer.
- */
- tp->usrsync=255;
- tp->period = 0;
+ printk ("%d parity error(s).\n",cp->parity_status);
X }
X
X /*
@@ -5680,13 +5768,13 @@
X PRINT_ADDR(cmd);
X switch (cp->xerr_status) {
X case XE_EXTRA_DATA:
- printf ("extraneous data discarded.\n");
+ printk ("extraneous data discarded.\n");
X break;
X case XE_BAD_PHASE:
- printf ("illegal scsi phase (4/5).\n");
+ printk ("illegal scsi phase (4/5).\n");
X break;
X default:
- printf ("extended error %d.\n", cp->xerr_status);
+ printk ("extended error %d.\n", cp->xerr_status);
X break;
X }
X if (cp->host_status==HS_COMPLETE)
@@ -5694,95 +5782,70 @@
X }
X
X /*
+ ** Print out any error for debugging purpose.
+ */
+ if (DEBUG_FLAGS & (DEBUG_RESULT|DEBUG_TINY)) {
+ if (cp->host_status!=HS_COMPLETE || cp->scsi_status!=S_GOOD) {
+ PRINT_ADDR(cmd);
+ printk ("ERROR: cmd=%x host_status=%x scsi_status=%x\n",
+ cmd->cmnd[0], cp->host_status, cp->scsi_status);


+ }
+ }
+
+ /*

X ** Check the status.
X */
X if ( (cp->host_status == HS_COMPLETE)
X && (cp->scsi_status == S_GOOD ||
X cp->scsi_status == S_COND_MET)) {
- /*
+ /*
X ** All went well (GOOD status).
X ** CONDITION MET status is returned on
- ** `Pre-Fetch' or `Search data' success.
- */
+ ** `Pre-Fetch' or `Search data' success.
+ */
X cmd->result = ScsiResult(DID_OK, cp->scsi_status);
X
X /*
- ** if (cp->phys.header.lastp != cp->phys.header.goalp)...
- **
X ** @RESID@
X ** Could dig out the correct value for resid,
X ** but it would be quite complicated.
- **
- ** The ah1542.c driver sets it to 0 too ...
X */
+ /* if (cp->phys.header.lastp != cp->phys.header.goalp) */
X
X /*
- ** Try to assign a ccb to this nexus
+ ** Allocate the lcb if not yet.
X */
- ncr_alloc_ccb (np, cmd->target, cmd->lun);
+ if (!lp)
+ ncr_alloc_lcb (np, cmd->target, cmd->lun);
X
X /*
- ** On inquire cmd (0x12) save some data.
- ** Clear questionnable capacities.
+ ** On standard INQUIRY response (EVPD and CmDt
+ ** not set), setup logical unit according to
+ ** announced capabilities (we need the 1rst 7 bytes).
X */
- if (cmd->lun == 0 && cmd->cmnd[0] == 0x12) {
- if (np->unit < SCSI_NCR_MAX_HOST) {
- if (driver_setup.force_sync_nego)
- ((char *) cmd->request_buffer)[7] |= INQ7_SYNC;
- else
- ((char *) cmd->request_buffer)[7] &=
- (target_capabilities[np->unit].and_map[cmd->target]);
- }
- bcopy ( cmd->request_buffer,
- &tp->inqdata,
- sizeof (tp->inqdata));
-
- /*
- ** set number of tags
- */
- ncr_setmaxtags (np, tp, driver_setup.default_tags);
- /*
- ** prepare negotiation of synch and wide.
- */
- ncr_negotiate (np, tp);
-
- /*
- ** force quirks update before next command start
- */
- tp->quirks |= QUIRK_UPDATE;
+ if (cmd->cmnd[0] == 0x12 && !(cmd->cmnd[1] & 0x3) &&
+ cmd->cmnd[4] >= 7) {
+ ncr_setup_lcb (np, cmd->target, cmd->lun,
+ (char *) cmd->request_buffer);
X }
X
- /*
- ** Announce changes to the generic driver.
- */
- if (lp) {
- ncr_settags (tp, lp);
- if (lp->reqlink != lp->actlink)
- ncr_opennings (np, lp, cmd);
- };
-
X tp->bytes += cp->data_len;
X tp->transfers ++;
X
X /*
X ** If tags was reduced due to queue full,
- ** increase tags if 100 good status received.
+ ** increase tags if 1000 good status received.
X */
- if (tp->numtags < tp->maxtags) {
- ++tp->num_good;
- if (tp->num_good >= 100) {
- tp->num_good = 0;
- ++tp->numtags;
- if (tp->numtags == 1) {
- PRINT_ADDR(cmd);
- printf("tagged command queueing resumed\n");
- }
+ if (lp && lp->usetags && lp->numtags < lp->maxtags) {
+ ++lp->num_good;
+ if (lp->num_good >= 1000) {
+ lp->num_good = 0;
+ ++lp->numtags;
+ ncr_setup_tags (np, cmd->target, cmd->lun);
X }
X }
X } else if ((cp->host_status == HS_COMPLETE)
- && (cp->scsi_status == (S_SENSE|S_GOOD) ||
- cp->scsi_status == (S_SENSE|S_CHECK_COND))) {
-
+ && (cp->scsi_status == S_CHECK_COND)) {
X /*
X ** Check condition code
X */
@@ -5791,43 +5854,21 @@
X if (DEBUG_FLAGS & (DEBUG_RESULT|DEBUG_TINY)) {
X u_char * p = (u_char*) & cmd->sense_buffer;
X int i;
- printf ("\n%s: sense data:", ncr_name (np));
- for (i=0; i<14; i++) printf (" %x", *p++);
- printf (".\n");
+ PRINT_ADDR(cmd);
+ printk ("sense data:");
+ for (i=0; i<14; i++) printk (" %x", *p++);
+ printk (".\n");
X }
X
X } else if ((cp->host_status == HS_COMPLETE)
X && (cp->scsi_status == S_BUSY ||
- cp->scsi_status == S_CONFLICT)) {
+ cp->scsi_status == S_QUEUE_FULL)) {
X
X /*
X ** Target is busy.
X */
X cmd->result = ScsiResult(DID_OK, cp->scsi_status);
X
- } else if ((cp->host_status == HS_COMPLETE)
- && (cp->scsi_status == S_QUEUE_FULL)) {
-
- /*
- ** Target is stuffed.
- */
- cmd->result = ScsiResult(DID_OK, cp->scsi_status);
-
- /*
- ** Suspend tagged queuing and start good status counter.
- ** Announce changes to the generic driver.
- */
- if (tp->numtags) {
- PRINT_ADDR(cmd);
- printf("QUEUE FULL! suspending tagged command queueing\n");
- tp->numtags = 0;
- tp->num_good = 0;
- if (lp) {
- ncr_settags (tp, lp);
- if (lp->reqlink != lp->actlink)
- ncr_opennings (np, lp, cmd);
- };
- }
X } else if ((cp->host_status == HS_SEL_TIMEOUT)
X || (cp->host_status == HS_TIMEOUT)) {
X
@@ -5856,7 +5897,7 @@
X ** Other protocol messes
X */
X PRINT_ADDR(cmd);
- printf ("COMMAND FAILED (%x %x) @%p.\n",
+ printk ("COMMAND FAILED (%x %x) @%p.\n",
X cp->host_status, cp->scsi_status, cp);
X
X cmd->result = ScsiResult(DID_ERROR, cp->scsi_status);
@@ -5870,43 +5911,51 @@
X u_char * p;
X int i;
X PRINT_ADDR(cmd);
- printf (" CMD:");
+ printk (" CMD:");
X p = (u_char*) &cmd->cmnd[0];
- for (i=0; i<cmd->cmd_len; i++) printf (" %x", *p++);
+ for (i=0; i<cmd->cmd_len; i++) printk (" %x", *p++);
X
X if (cp->host_status==HS_COMPLETE) {
X switch (cp->scsi_status) {
X case S_GOOD:
- printf (" GOOD");
+ printk (" GOOD");
X break;
X case S_CHECK_COND:
- printf (" SENSE:");
+ printk (" SENSE:");
X p = (u_char*) &cmd->sense_buffer;
X for (i=0; i<14; i++)
- printf (" %x", *p++);
+ printk (" %x", *p++);
X break;
X default:
- printf (" STAT: %x\n", cp->scsi_status);
+ printk (" STAT: %x\n", cp->scsi_status);
X break;
X }
- } else printf (" HOSTERROR: %x", cp->host_status);
- printf ("\n");
+ } else printk (" HOSTERROR: %x", cp->host_status);
+ printk ("\n");
X }
X
X /*
X ** Free this ccb
X */
- ncr_free_ccb (np, cp, cmd->target, cmd->lun);
+ ncr_free_ccb (np, cp);
+
+ /*
+ ** requeue awaiting scsi commands for this lun.
+ */
+ if (lp && lp->queuedccbs < lp->queuedepth &&
+ !xpt_que_empty(&lp->wait_ccbq))
+ ncr_start_next_ccb(np, lp, 2);
X
X /*
- ** requeue awaiting scsi commands
+ ** requeue awaiting scsi commands for this controller.
X */
- if (np->waiting_list) requeue_waiting_list(np);
+ if (np->waiting_list)
+ requeue_waiting_list(np);
X
X /*
X ** signal completion to generic driver.
X */
- cmd->scsi_done (cmd);
+ ncr_queue_done_cmd(np, cmd);
X }
X
X /*==========================================================
@@ -5918,41 +5967,92 @@


X **==========================================================
X */
X

-void ncr_wakeup (ncb_p np, u_long code)
+/*
+** This CCB has been skipped by the NCR.
+** Queue it in the correponding unit queue.
+*/
+void ncr_ccb_skipped(ncb_p np, ccb_p cp)
X {
- /*
- ** Starting at the default ccb and following
- ** the links, complete all jobs with a
- ** host_status greater than "disconnect".
- **
- ** If the "code" parameter is not zero,
- ** complete all jobs that are not IDLE.
- */
+ tcb_p tp = &np->target[cp->target];
+ lcb_p lp = tp->lp[cp->lun];
X
- ccb_p cp = np->ccb;
- while (cp) {
- switch (cp->host_status) {
+ if (lp && cp != np->ccb) {
+ cp->host_status &= ~HS_SKIPMASK;
+ cp->start.schedule.l_paddr =
+ cpu_to_scr(NCB_SCRIPT_PHYS (np, select));
+ xpt_remque(&cp->link_ccbq);
+ xpt_insque_tail(&cp->link_ccbq, &lp->skip_ccbq);
+ if (cp->queued) {
+ --lp->queuedccbs;
+ }
+ }
+ if (cp->queued) {
+ --np->queuedccbs;
+ cp->queued = 0;
+ }
+}
+
+/*
+** The NCR has completed CCBs.
+** Look at the DONE QUEUE if enabled, otherwise scan all CCBs
+*/
+void ncr_wakeup_done (ncb_p np)
+{
+ ccb_p cp;
+#ifdef SCSI_NCR_CCB_DONE_SUPPORT
+ int i, j;
X
- case HS_IDLE:
+ i = np->ccb_done_ic;
+ while (1) {
+ j = i+1;
+ if (j >= MAX_DONE)
+ j = 0;
+
+ cp = np->ccb_done[j];
+ if (!CCB_DONE_VALID(cp))
X break;
X
- case HS_DISCONNECT:
- if(DEBUG_FLAGS & DEBUG_TINY) printf ("D");
- /* fall through */
-
- case HS_BUSY:
- case HS_NEGOTIATE:
- if (!code) break;
- cp->host_status = code;
+ np->ccb_done[j] = (ccb_p) CCB_DONE_EMPTY;
+ np->scripth->done_queue[5*j + 4] =
+ cpu_to_scr(NCB_SCRIPT_PHYS (np, done_plug));
+ MEMORY_BARRIER();
+ np->scripth->done_queue[5*i + 4] =
+ cpu_to_scr(NCB_SCRIPT_PHYS (np, done_end));
X
- /* fall through */
+ if (cp->host_status & HS_DONEMASK)
+ ncr_complete (np, cp);
+ else if (cp->host_status & HS_SKIPMASK)
+ ncr_ccb_skipped (np, cp);
X
- default:
+ i = j;
+ }
+ np->ccb_done_ic = i;
+#else
+ cp = np->ccb;
+ while (cp) {
+ if (cp->host_status & HS_DONEMASK)
X ncr_complete (np, cp);
- break;
- };
- cp = cp -> link_ccb;
- };
+ else if (cp->host_status & HS_SKIPMASK)
+ ncr_ccb_skipped (np, cp);
+ cp = cp->link_ccb;


+ }
+#endif
+}
+
+/*

+** Complete all active CCBs.
+*/
+void ncr_wakeup (ncb_p np, u_long code)
+{
+ ccb_p cp = np->ccb;
+
+ while (cp) {
+ if (cp->host_status != HS_IDLE) {
+ cp->host_status = code;
+ ncr_complete (np, cp);
+ }
+ cp = cp->link_ccb;
+ }
X }
X
X /*==========================================================
@@ -5966,38 +6066,57 @@
X
X void ncr_init (ncb_p np, int reset, char * msg, u_long code)
X {
- int i;
+ int i;
X
- /*
+ /*
X ** Reset chip if asked, otherwise just clear fifos.
- */
+ */
+
X if (reset) {
X OUTB (nc_istat, SRST);
- DELAY (10000);
+ UDELAY (100);
X }
X else {
X OUTB (nc_stest3, TE|CSF);
X OUTONB (nc_ctest3, CLF);
X }
-
+
X /*
X ** Message.
X */
X
- if (msg) printf (KERN_INFO "%s: restart (%s).\n", ncr_name (np), msg);
+ if (msg) printk (KERN_INFO "%s: restart (%s).\n", ncr_name (np), msg);
X
X /*
X ** Clear Start Queue
X */
- for (i=0;i<MAX_START;i++)
- np -> squeue [i] = cpu_to_scr(NCB_SCRIPT_PHYS (np, idle));
+ np->queuedepth = MAX_START - 1; /* 1 entry needed as end marker */
+ for (i = 1; i < MAX_START + MAX_START; i += 2)
+ np->scripth0->tryloop[i] =
+ cpu_to_scr(NCB_SCRIPT_PHYS (np, idle));
X
X /*
X ** Start at first entry.
X */
X np->squeueput = 0;
X np->script0->startpos[0] = cpu_to_scr(NCB_SCRIPTH_PHYS (np, tryloop));
- np->script0->start0 [0] = cpu_to_scr(SCR_INT ^ IFFALSE (0));
+
+ /*
+ ** Clear Done Queue
+ */
+ for (i = 0; i < MAX_DONE; i++) {
+ np->ccb_done[i] = (ccb_p) CCB_DONE_EMPTY;
+ np->scripth0->done_queue[5*i + 4] =
+ cpu_to_scr(NCB_SCRIPT_PHYS (np, done_end));
+ }
+
+ /*
+ ** Start at first entry.
+ */
+ np->script0->done_pos[0] = cpu_to_scr(NCB_SCRIPTH_PHYS (np,done_queue));
+ np->ccb_done_ic = MAX_DONE-1;
+ np->scripth0->done_queue[5*(MAX_DONE-1) + 4] =
+ cpu_to_scr(NCB_SCRIPT_PHYS (np, done_plug));
X
X /*
X ** Wakeup all pending jobs.
@@ -6009,6 +6128,8 @@
X */
X
X OUTB (nc_istat, 0x00 ); /* Remove Reset, abort */
+ UDELAY (2000); /* The 895 needs time for the bus mode to settle */
+
X OUTB (nc_scntl0, np->rv_scntl0 | 0xc0);
X /* full arb., ena parity, par->ATN */
X OUTB (nc_scntl1, 0x00); /* odd parity, and remove CRST!! */
@@ -6027,7 +6148,7 @@
X
X OUTB (nc_stest2, EXT|np->rv_stest2); /* Extended Sreq/Sack filtering */
X OUTB (nc_stest3, TE); /* TolerANT enable */
- OUTB (nc_stime0, 0x0d ); /* HTH disabled STO 0.4 sec. */
+ OUTB (nc_stime0, 0x0c ); /* HTH disabled STO 0.25 sec */
X
X /*
X ** Disable disconnects.
@@ -6044,23 +6165,10 @@
X }
X
X /*
- ** Upload the script into on-board RAM
- */
- if (np->vaddr2) {
- if (bootverbose)
- printf ("%s: copying script fragments into the on-board RAM ...\n", ncr_name(np));
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,0,0)
- memcpy_toio(np->script, np->script0, sizeof(struct script));
-#else
- memcpy(np->script, np->script0, sizeof(struct script));
-#endif
- }
-
- /*
X ** enable ints
X */
X
- OUTW (nc_sien , STO|HTH|MA|SGE|UDC|RST);
+ OUTW (nc_sien , STO|HTH|MA|SGE|UDC|RST|PAR);
X OUTB (nc_dien , MDPE|BF|ABRT|SSI|SIR|IID);
X
X /*
@@ -6072,6 +6180,18 @@
X }
X
X /*
+ ** DEL 441 - 53C876 Rev 5 - Part Number 609-0392787/2788 - ITEM 2.
+ ** Disable overlapped arbitration.
+ ** The 896 Rev 1 is also affected by this errata.
+ */
+ if (np->device_id == PCI_DEVICE_ID_NCR_53C875 &&
+ np->revision_id >= 0x10 && np->revision_id <= 0x15)
+ OUTB (nc_ctest0, (1<<5));
+ else if (np->device_id == PCI_DEVICE_ID_NCR_53C896 &&
+ np->revision_id <= 0x1)
+ OUTB (nc_ccntl0, DPR);
+
+ /*
X ** Fill in target structure.
X ** Reinitialize usrsync.
X ** Reinitialize usrwide.
@@ -6103,8 +6223,16 @@
X /*
X ** Start script processor.
X */
-
- OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, start));
+ MEMORY_BARRIER();
+ if (np->paddr2) {
+ if (bootverbose)
+ printk ("%s: Downloading SCSI SCRIPTS.\n",
+ ncr_name(np));
+ OUTL (nc_scratcha, vtophys(np->script0));
+ OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, start_ram));
+ }
+ else
+ OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, start));
X }
X
X /*==========================================================
@@ -6132,14 +6260,6 @@
X }
X
X /*
- ** if not scsi 2
- ** don't believe FAST!
- */
-
- if ((minsync < 50) && (tp->inqdata[2] & 0x0f) < 2)
- minsync=50;
-
- /*
X ** our limit ..
X */
X
@@ -6215,7 +6335,7 @@
X /*
X ** Why not to try the immediate lower divisor and to choose
X ** the one that allows the fastest output speed ?
- ** We don't want input speed too much greater than output speed.
+ ** We dont want input speed too much greater than output speed.
X */
X if (div >= 1 && fak < 8) {
X u_long fak2, per2;
@@ -6266,8 +6386,12 @@
X for (cp = np->ccb; cp; cp = cp->link_ccb) {
X if (!cp->cmd) continue;
X if (cp->cmd->target != target) continue;
+#if 0
X cp->sync_status = tp->sval;
X cp->wide_status = tp->wval;
+#endif
+ cp->phys.select.sel_scntl3 = tp->wval;
+ cp->phys.select.sel_sxfer = tp->sval;
X };
X }
X
@@ -6282,15 +6406,15 @@
X {
X Scsi_Cmnd *cmd;
X tcb_p tp;
- u_char target = INB (nc_ctest0) & 0x0f;
+ u_char target = INB (nc_sdid) & 0x0f;
X u_char idiv;
X
- assert (cp);
+ assert (cp && cp->cmd);
X if (!cp) return;
X
X cmd = cp->cmd;
- assert (cmd);
X if (!cmd) return;
+
X assert (target == (cmd->target & 0xf));
X
X tp = &np->target[target];
@@ -6320,7 +6444,7 @@
X /*
X ** Bells and whistles ;-)
X */
- PRINT_ADDR(cmd);
+ PRINT_TARGET(np, target);
X if (sxfer & 0x01f) {
X unsigned f10 = 100000 << (tp->widedone ? tp->widedone -1 : 0);
X unsigned mb10 = (f10 + tp->period/2) / tp->period;
@@ -6339,11 +6463,11 @@
X else if (tp->period < 2000) scsi = "FAST-10";
X else scsi = "FAST-5";
X
- printf ("%s %sSCSI %d.%d MB/s (%d ns, offset %d)\n", scsi,
+ printk ("%s %sSCSI %d.%d MB/s (%d ns, offset %d)\n", scsi,
X tp->widedone > 1 ? "WIDE " : "",
X mb10 / 10, mb10 % 10, tp->period / 10, sxfer & 0x1f);
X } else
- printf ("%sasynchronous.\n", tp->widedone > 1 ? "wide " : "");
+ printk ("%sasynchronous.\n", tp->widedone > 1 ? "wide " : "");
X
X /*
X ** set actual value and sync_status
@@ -6365,17 +6489,17 @@
X static void ncr_setwide (ncb_p np, ccb_p cp, u_char wide, u_char ack)
X {
X Scsi_Cmnd *cmd;
- u_short target = INB (nc_ctest0) & 0x0f;
+ u_short target = INB (nc_sdid) & 0x0f;
X tcb_p tp;
X u_char scntl3;
X u_char sxfer;
X
- assert (cp);
+ assert (cp && cp->cmd);
X if (!cp) return;
X
X cmd = cp->cmd;
- assert (cmd);
X if (!cmd) return;
+
X assert (target == (cmd->target & 0xf));
X
X tp = &np->target[target];
@@ -6395,11 +6519,11 @@
X ** Bells and whistles ;-)
X */
X if (bootverbose >= 2) {
- PRINT_ADDR(cmd);
+ PRINT_TARGET(np, target);
X if (scntl3 & EWS)
- printf ("WIDE SCSI (16 bit) enabled.\n");
+ printk ("WIDE SCSI (16 bit) enabled.\n");
X else
- printf ("WIDE SCSI disabled.\n");
+ printk ("WIDE SCSI disabled.\n");
X }
X
X /*
@@ -6416,73 +6540,91 @@


X **==========================================================
X */
X

-static void ncr_setmaxtags (ncb_p np, tcb_p tp, u_long numtags)
+static void ncr_setup_tags (ncb_p np, u_char tn, u_char ln)
X {
- int l;
- if (numtags > tp->usrtags)
- numtags = tp->usrtags;
- tp->numtags = numtags;
- tp->maxtags = numtags;
-
- for (l=0; l<MAX_LUN; l++) {
- lcb_p lp;
- u_char wastags;
+ tcb_p tp = &np->target[tn];
+ lcb_p lp = tp->lp[ln];
+ u_char reqtags, maxdepth;
X
- if (!tp) break;
- lp=tp->lp[l];
- if (!lp) continue;
-
- wastags = lp->usetags;
- ncr_settags (tp, lp);
-
- if (numtags > 1 && lp->reqccbs > 1) {
- PRINT_LUN(np, tp - np->target, l);
- printf("using tagged command queueing, up to %ld cmds/lun\n", numtags);
- }
- else if (numtags <= 1 && wastags) {
- PRINT_LUN(np, tp - np->target, l);
- printf("disabling tagged command queueing\n");
- }
- };
-}
+ /*
+ ** Just in case ...
+ */
+ if ((!tp) || (!lp))
+ return;
X
-static void ncr_settags (tcb_p tp, lcb_p lp)
-{
- u_char reqtags, tmp;
+ /*
+ ** If SCSI device queue depth is not yet set, leave here.
+ */
+ if (!lp->scdev_depth)
+ return;
X
- if ((!tp) || (!lp)) return;
+ /*
+ ** Donnot allow more tags than the SCSI driver can queue
+ ** for this device.
+ ** Donnot allow more tags than we can handle.
+ */
+ maxdepth = lp->scdev_depth;
+ if (maxdepth > lp->maxnxs) maxdepth = lp->maxnxs;
+ if (lp->maxtags > maxdepth) lp->maxtags = maxdepth;
+ if (lp->numtags > maxdepth) lp->numtags = maxdepth;
X
X /*
X ** only devices conformant to ANSI Version >= 2
- ** only devices capable of tagges commands
- ** only disk devices
+ ** only devices capable of tagged commands
X ** only if enabled by user ..
X */
- if (( tp->inqdata[2] & 0x7) >= 2 &&
- ( tp->inqdata[7] & INQ7_QUEUE) && ((tp->inqdata[0] & 0x1f)==0x00)
- && tp->numtags > 1) {
- reqtags = tp->numtags;
- if (lp->actlink <= 1)
- lp->usetags=reqtags;
- } else {
- reqtags = 1;
- if (lp->actlink <= 1)
- lp->usetags=0;
- };
+ if ((lp->inq_byte7 & INQ7_QUEUE) && lp->numtags > 1) {
+ reqtags = lp->numtags;
+ } else {
+ reqtags = 1;
+ };
+
+ /*
+ ** Update max number of tags
+ */
+ lp->numtags = reqtags;
+ if (lp->numtags > lp->maxtags)
+ lp->maxtags = lp->numtags;
+
+ /*
+ ** If we want to switch tag mode, we must wait
+ ** for no CCB to be active.
+ */
+ if (reqtags > 1 && lp->usetags) { /* Stay in tagged mode */
+ if (lp->queuedepth == reqtags) /* Already announced */
+ return;
+ lp->queuedepth = reqtags;
+ }
+ else if (reqtags <= 1 && !lp->usetags) { /* Stay in untagged mode */
+ lp->queuedepth = reqtags;
+ return;
+ }
+ else { /* Want to switch tag mode */
+ if (lp->busyccbs) /* If not yet safe, return */
+ return;
+ lp->queuedepth = reqtags;
+ lp->usetags = reqtags > 1 ? 1 : 0;
+ }
X
X /*
- ** don't announce more than available.
+ ** Patch the lun mini-script, according to tag mode.
X */
- tmp = lp->actccbs;
- if (tmp > reqtags) tmp = reqtags;
- lp->reqlink = tmp;
+ lp->jump_tag.l_paddr = lp->usetags?
+ cpu_to_scr(NCB_SCRIPT_PHYS(np, resel_tag)) :
+ cpu_to_scr(NCB_SCRIPT_PHYS(np, resel_notag));
X
X /*
- ** don't discard if announced.
+ ** Announce change to user.
X */
- tmp = lp->actlink;
- if (tmp < reqtags) tmp = reqtags;
- lp->reqccbs = tmp;
+ if (bootverbose) {
+ PRINT_LUN(np, tn, ln);
+ if (lp->usetags) {
+ printk("tagged command queue depth set to %d\n", reqtags);
+ }
+ else {
+ printk("tagged command queueing disabled\n");
+ }
+ }
X }
X
X /*----------------------------------------------------
@@ -6513,13 +6655,18 @@
X break;
X
X case UC_SETTAGS:
- if (np->user.data > SCSI_NCR_MAX_TAGS)
- np->user.data = SCSI_NCR_MAX_TAGS;
X for (t=0; t<MAX_TARGET; t++) {
+ int ln;
X if (!((np->user.target>>t)&1)) continue;
X np->target[t].usrtags = np->user.data;
- ncr_setmaxtags (np, &np->target[t], np->user.data);
- };
+ for (ln = 0; ln < MAX_LUN; ln++) {
+ lcb_p lp = np->target[t].lp[ln];
+ if (!lp)
+ continue;
+ lp->maxtags = lp->numtags = np->user.data;
+ ncr_setup_tags (np, t, ln);
+ }
+ };
X break;
X
X case UC_SETDEBUG:
@@ -6532,6 +6679,10 @@
X np->order = np->user.data;
X break;
X
+ case UC_SETVERBOSE:
+ np->verbose = np->user.data;
+ break;
+
X case UC_SETWIDE:
X for (t=0; t<MAX_TARGET; t++) {
X u_long size;
@@ -6552,110 +6703,16 @@
X };
X break;
X
+#ifdef SCSI_NCR_PROFILE_SUPPORT
X case UC_CLEARPROF:
X bzero(&np->profile, sizeof(np->profile));
X break;
-#ifdef UC_DEBUG_ERROR_RECOVERY
- case UC_DEBUG_ERROR_RECOVERY:
- np->debug_error_recovery = np->user.data;
- break;
X #endif
X }
X np->user.cmd=0;


X }
X #endif
X
-

-/*=====================================================================
-**
-** Embedded error recovery debugging code.
-**
-**=====================================================================
-**
-** This code is conditionned by SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT.
-** It only can be enabled after boot-up with a control command.
-**
-** Every 30 seconds the timer handler of the driver decides to
-** change the behaviour of the driver in order to trigger errors.
-**
-** If last command was "debug_error_recovery sge", the driver
-** sets sync offset of all targets that use sync transfers to 2,
-** and so hopes a SCSI gross error at the next read operation.
-**
-** If last command was "debug_error_recovery abort", the driver
-** does not signal new scsi commands to the script processor, until
-** it is asked to abort or reset a command by the mid-level driver.
-**
-** If last command was "debug_error_recovery reset", the driver
-** does not signal new scsi commands to the script processor, until
-** it is asked to reset a command by the mid-level driver.
-**
-** If last command was "debug_error_recovery parity", the driver
-** will assert ATN on the next DATA IN phase mismatch, and so will
-** behave as if a parity error had been detected.
-**
-** The command "debug_error_recovery none" makes the driver behave
-** normaly.
-**
-**=====================================================================
-*/
-
-#ifdef SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
-static void ncr_trigger_errors (ncb_p np)
-{
- /*
- ** If np->debug_error_recovery is not zero, we want to
- ** simulate common errors in order to test error recovery.
- */
- do {
- static u_long last = 0l;
-
- if (!np->debug_error_recovery)
- break;
- if (!last)
- last = jiffies;
- else if (jiffies < last + 30*HZ)
- break;
- last = jiffies;
- /*
- * This one triggers SCSI gross errors.
- */
- if (np->debug_error_recovery == 1) {
- int i;
- printf("%s: testing error recovery from SCSI gross error...\n", ncr_name(np));
- for (i = 0 ; i < MAX_TARGET ; i++) {
- if (np->target[i].sval & 0x1f) {
- np->target[i].sval &= ~0x1f;
- np->target[i].sval += 2;


- }
- }
- }
- /*

- * This one triggers abort from the mid-level driver.
- */
- else if (np->debug_error_recovery == 2) {
- printf("%s: testing error recovery from mid-level driver abort()...\n", ncr_name(np));
- np->stalling = 2;
- }
- /*
- * This one triggers reset from the mid-level driver.
- */
- else if (np->debug_error_recovery == 3) {
- printf("%s: testing error recovery from mid-level driver reset()...\n", ncr_name(np));
- np->stalling = 3;
- }
- /*
- * This one set ATN on phase mismatch in DATA IN phase and so
- * will behave as on scsi parity error detected.
- */
- else if (np->debug_error_recovery == 4) {
- printf("%s: testing data in parity error...\n", ncr_name(np));
- np->assert_atn = 1;
- }
- } while (0);
-}
-#endif
-
X /*==========================================================
X **
X **
@@ -6673,9 +6730,6 @@
X static void ncr_timeout (ncb_p np)
X {
X u_long thistime = jiffies;
- u_long count = 0;
- ccb_p cp;
- u_long flags;
X
X /*
X ** If release process in progress, let's go
@@ -6688,18 +6742,9 @@
X return;
X }
X
- np->timer.expires =
-#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0)
- jiffies +
-#endif
- SCSI_NCR_TIMER_INTERVAL;
-
+ np->timer.expires = jiffies + SCSI_NCR_TIMER_INTERVAL;
X add_timer(&np->timer);
X
-#ifdef SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
- ncr_trigger_errors (np);
-#endif
-
X /*
X ** If we are resetting the ncr, wait for settle_time before
X ** clearing it. Then command processing will be resumed.
@@ -6707,12 +6752,10 @@
X if (np->settle_time) {
X if (np->settle_time <= thistime) {
X if (bootverbose > 1)
- printf("%s: command processing resumed\n", ncr_name(np));
- save_flags(flags); cli();
+ printk("%s: command processing resumed\n", ncr_name(np));
X np->settle_time = 0;
X np->disc = 1;
X requeue_waiting_list(np);
- restore_flags(flags);
X }
X return;
X }
@@ -6722,99 +6765,20 @@
X ** to perform abort of a command, we must look at ccbs about
X ** every 0.25 second.
X */
- if (np->lasttime + (HZ>>2) <= thistime) {
+ if (np->lasttime + 4*HZ < thistime) {
X /*
X ** block ncr interrupts
X */
- save_flags(flags); cli();
-
X np->lasttime = thistime;
X
+#ifdef SCSI_NCR_PROFILE_SUPPORT
X /*
X ** Reset profile data to avoid ugly overflow
X ** (Limited to 1024 GB for 32 bit architecture)
X */
X if (np->profile.num_kbytes > (~0UL >> 2))
X bzero(&np->profile, sizeof(np->profile));
-
- /*----------------------------------------------------
- **
- ** handle ncr chip timeouts
- **
- ** Assumption:
- ** We have a chance to arbitrate for the
- ** SCSI bus at least every 10 seconds.
- **
- **----------------------------------------------------
- */
-#if 0
- if (thistime < np->heartbeat + HZ + HZ)
- np->latetime = 0;
- else
- np->latetime++;
X #endif
-
- /*----------------------------------------------------
- **
- ** handle ccb timeouts
- **
- **----------------------------------------------------
- */
-
- for (cp=np->ccb; cp; cp=cp->link_ccb) {
- /*
- ** look for timed out ccbs.
- */
- if (!cp->host_status) continue;
- count++;
- /*
- ** Have to force ordered tag to avoid timeouts
- */
- if (cp->cmd && cp->tlimit && cp->tlimit <=
- thistime + NCR_TIMEOUT_INCREASE + SCSI_NCR_TIMEOUT_ALERT) {
- lcb_p lp;
- lp = np->target[cp->cmd->target].lp[cp->cmd->lun];
- if (lp && !lp->force_ordered_tag) {
- lp->force_ordered_tag = 1;
- }
- }
- /*
- ** ncr_abort_command() cannot complete canceled
- ** commands immediately. It sets tlimit to zero
- ** and ask the script to skip the scsi process if
- ** necessary. We have to complete this work here.
- */
-
- if (cp->tlimit) continue;
-
- switch (cp->host_status) {
-
- case HS_BUSY:
- case HS_NEGOTIATE:
- /*
- ** still in start queue ?
- */
- if (cp->phys.header.launch.l_paddr ==
- cpu_to_scr(NCB_SCRIPT_PHYS (np, skip)))
- continue;
-
- /* fall through */
- case HS_DISCONNECT:
- cp->host_status=HS_ABORTED;
- };
- cp->tag = 0;
-
- /*
- ** wakeup this ccb.
- */
- ncr_complete (np, cp);
-
-#ifdef SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
- if (!np->stalling)
-#endif
- OUTB (nc_istat, SIGP);
- }
- restore_flags(flags);
X }
X
X #ifdef SCSI_NCR_BROKEN_INTR
@@ -6823,11 +6787,9 @@
X /*
X ** Process pending interrupts.
X */
- save_flags(flags); cli();
- if (DEBUG_FLAGS & DEBUG_TINY) printf ("{");
+ if (DEBUG_FLAGS & DEBUG_TINY) printk ("{");
X ncr_exception (np);
- if (DEBUG_FLAGS & DEBUG_TINY) printf ("}");
- restore_flags(flags);
+ if (DEBUG_FLAGS & DEBUG_TINY) printk ("}");
X }
X #endif /* SCSI_NCR_BROKEN_INTR */
X }
@@ -6876,14 +6838,14 @@
X if (dsp > np->p_script && dsp <= np->p_script + sizeof(struct script)) {
X script_ofs = dsp - np->p_script;
X script_size = sizeof(struct script);
- script_base = (u_char *) np->script;
+ script_base = (u_char *) np->script0;
X script_name = "script";
X }
X else if (np->p_scripth < dsp &&
X dsp <= np->p_scripth + sizeof(struct scripth)) {
X script_ofs = dsp - np->p_scripth;
X script_size = sizeof(struct scripth);
- script_base = (u_char *) np->scripth;
+ script_base = (u_char *) np->scripth0;
X script_name = "scripth";
X } else {
X script_ofs = dsp;
@@ -6892,22 +6854,22 @@
X script_name = "mem";
X }
X
- printf ("%s:%d: ERROR (%x:%x) (%x-%x-%x) (%x/%x) @ (%s %x:%08x).\n",
- ncr_name (np), (unsigned)INB (nc_ctest0)&0x0f, dstat, sist,
+ printk ("%s:%d: ERROR (%x:%x) (%x-%x-%x) (%x/%x) @ (%s %x:%08x).\n",
+ ncr_name (np), (unsigned)INB (nc_sdid)&0x0f, dstat, sist,
X (unsigned)INB (nc_socl), (unsigned)INB (nc_sbcl), (unsigned)INB (nc_sbdl),
X (unsigned)INB (nc_sxfer),(unsigned)INB (nc_scntl3), script_name, script_ofs,
X (unsigned)INL (nc_dbc));
X
X if (((script_ofs & 3) == 0) &&
X (unsigned)script_ofs < script_size) {
- printf ("%s: script cmd = %08x\n", ncr_name(np),
- (int) *(ncrcmd *)(script_base + script_ofs));
+ printk ("%s: script cmd = %08x\n", ncr_name(np),
+ scr_to_cpu((int) *(ncrcmd *)(script_base + script_ofs)));
X }
X
- printf ("%s: regdump:", ncr_name(np));
+ printk ("%s: regdump:", ncr_name(np));
X for (i=0; i<16;i++)
- printf (" %02x", (unsigned)INB_OFF(i));
- printf (".\n");
+ printk (" %02x", (unsigned)INB_OFF(i));
+ printk (".\n");
X }
X
X /*============================================================
@@ -6953,23 +6915,25 @@
X ** Since the global header may be copied back to a CCB
X ** using a posted PCI memory write, the last operation on
X ** the istat register is a READ in order to flush posted
- ** PCI commands (Btw, the 'do' loop is probably useless).
+ ** PCI write commands.
X */
X istat = INB (nc_istat);
X if (istat & INTF) {
- do {
- OUTB (nc_istat, (istat & SIGP) | INTF);
- istat = INB (nc_istat);
- } while (istat & INTF);
- if (DEBUG_FLAGS & DEBUG_TINY) printf ("F ");
+ OUTB (nc_istat, (istat & SIGP) | INTF);
+ istat = INB (nc_istat);
+ if (DEBUG_FLAGS & DEBUG_TINY) printk ("F ");
+#ifdef SCSI_NCR_PROFILE_SUPPORT
X np->profile.num_fly++;
- ncr_wakeup (np, 0);
+#endif
+ ncr_wakeup_done (np);
X };
X
X if (!(istat & (SIP|DIP)))
X return;
X
+#ifdef SCSI_NCR_PROFILE_SUPPORT
X np->profile.num_int++;
+#endif
X
X if (istat & CABRT)
X OUTB (nc_istat, CABRT);
@@ -6983,7 +6947,7 @@
X dstat = (istat & DIP) ? INB (nc_dstat) : 0;
X
X if (DEBUG_FLAGS & DEBUG_TINY)
- printf ("<%d|%x:%x|%x:%x>",
+ printk ("<%d|%x:%x|%x:%x>",
X (int)INB(nc_scr0),
X dstat,sist,
X (unsigned)INL(nc_dsp),
@@ -7020,12 +6984,11 @@
X ** DEL 397 - 53C875 Rev 3 - Part Number 609-0392410 - ITEM 2.
X */
X if (!(sist & (SBMC|PAR)) && !(dstat & SSI)) {
- printf( "%s: unknown interrupt(s) ignored, "
+ printk( "%s: unknown interrupt(s) ignored, "
X "ISTAT=%x DSTAT=%x SIST=%x\n",
X ncr_name(np), istat, dstat, sist);
X return;
X }
-
X OUTONB (nc_dcntl, (STD|NOCOM));
X return;
X };
@@ -7083,29 +7046,26 @@
X
X ncr_log_hard_error(np, sist, dstat);
X
- printf ("%s: have to clear fifos.\n", ncr_name (np));
+ printk ("%s: have to clear fifos.\n", ncr_name (np));
X OUTB (nc_stest3, TE|CSF);
X OUTONB (nc_ctest3, CLF);
X
X if ((sist & (SGE)) ||
X (dstat & (MDPE|BF|ABORT|IID))) {
- ncr_start_reset(np, driver_setup.settle_delay);
+ ncr_start_reset(np);
X return;
X };
X
X if (sist & HTH) {
- printf ("%s: handshake timeout\n", ncr_name(np));
- ncr_start_reset(np, driver_setup.settle_delay);
+ printk ("%s: handshake timeout\n", ncr_name(np));
+ ncr_start_reset(np);
X return;
X };
X
X if (sist & UDC) {
- printf ("%s: unexpected disconnect\n", ncr_name(np));
- if (INB (nc_scr1) != 0xff) {
- OUTB (nc_scr1, HS_UNEXPECTED);
- OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, cleanup));
- };
- ncr_start_reset(np, driver_setup.settle_delay);
+ printk ("%s: unexpected disconnect\n", ncr_name(np));
+ OUTB (HS_PRT, HS_UNEXPECTED);
+ OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, cleanup));
X return;
X };
X
@@ -7114,7 +7074,7 @@
X ** Print a message. The timeout will do the real work.
X **=========================================================
X */
- printf ("%s: unknown interrupt\n", ncr_name(np));
+ printk ("%s: unknown interrupt\n", ncr_name(np));
X }
X
X /*==========================================================
@@ -7135,9 +7095,9 @@
X
X void ncr_int_sto (ncb_p np)
X {
- u_long dsa, scratcha, diff;
+ u_long dsa;
X ccb_p cp;
- if (DEBUG_FLAGS & DEBUG_TINY) printf ("T");
+ if (DEBUG_FLAGS & DEBUG_TINY) printk ("T");
X
X /*
X ** look for ccb and set the status.
@@ -7154,21 +7114,11 @@
X };
X
X /*
- ** repair start queue
+ ** repair start queue and jump to start point.
X */
X
- scratcha = INL (nc_scratcha);
- diff = scratcha - NCB_SCRIPTH_PHYS (np, tryloop);
-
-/* assert ((diff <= MAX_START * 20) && !(diff % 20));*/
-
- if ((diff <= MAX_START * 20) && !(diff % 20)) {
- np->script->startpos[0] = cpu_to_scr(scratcha);
- OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, start));
- return;
- };
- ncr_init (np, 1, "selection timeout", HS_FAIL);
- np->disc = 1;
+ OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, sto_restart));
+ return;
X }
X
X /*==========================================================
@@ -7192,19 +7142,22 @@
X {
X u_char scsi_mode = INB (nc_stest4) & SMODE;
X
- printf("%s: SCSI bus mode change from %x to %x.\n",
- ncr_name(np), np->scsi_mode, scsi_mode);
+ if (scsi_mode != np->scsi_mode) {
+ printk("%s: SCSI bus mode change from %x to %x.\n",
+ ncr_name(np), np->scsi_mode, scsi_mode);
X
- np->scsi_mode = scsi_mode;
+ np->scsi_mode = scsi_mode;
X
- /*
- ** Suspend command processing for 1 second and
- ** reinitialize all except the chip.
- */
- np->settle_time = jiffies + HZ;
- ncr_init (np, 0, bootverbose ? "scsi mode change" : NULL, HS_RESET);
X
- return 1;
+ /*
+ ** Suspend command processing for 1 second and
+ ** reinitialize all except the chip.
+ */
+ np->settle_time = jiffies + HZ;
+ ncr_init (np, 0, bootverbose ? "scsi mode change" : NULL, HS_RESET);
+ return 1;
+ }


+ return 0;
X }
X

X /*==========================================================
@@ -7213,16 +7166,73 @@
X **
X **==========================================================
X **
-** SCSI parity errors are handled by the SCSI script.
-** So, we just print some message.
X **
X **----------------------------------------------------------
X */
X
X static int ncr_int_par (ncb_p np)
X {
- printf("%s: SCSI parity error detected\n", ncr_name(np));
- return 0;
+ u_char hsts = INB (HS_PRT);
+ u_int32 dbc = INL (nc_dbc);
+ u_char sstat1 = INB (nc_sstat1);
+ int phase = -1;
+ int msg = -1;
+ u_int32 jmp;
+
+ printk("%s: SCSI parity error detected: SCR1=%d DBC=%x SSTAT1=%x\n",
+ ncr_name(np), hsts, dbc, sstat1);
+
+ /*
+ * Ignore the interrupt if the NCR is not connected
+ * to the SCSI bus, since the right work should have
+ * been done on unexpected disconnection handling.
+ */
+ if (!(INB (nc_scntl1) & ISCON))
+ return 0;
+
+ /*
+ * If the nexus is not clearly identified, reset the bus.
+ * We will try to do better later.
+ */
+ if (hsts & HS_INVALMASK)
+ goto reset_all;
+
+ /*
+ * If the SCSI parity error occurs in MSG IN phase, prepare a
+ * MSG PARITY message. Otherwise, prepare a INITIATOR DETECTED
+ * ERROR message and let the device decide to retry the command
+ * or to terminate with check condition. If we were in MSG IN
+ * phase waiting for the response of a negotiation, we will
+ * get SIR_NEGO_FAILED at dispatch.
+ */
+ if (!(dbc & 0xc0000000))
+ phase = (dbc >> 24) & 7;
+ if (phase == 7)
+ msg = M_PARITY;
+ else
+ msg = M_ID_ERROR;
+
+ /*
+ * If the NCR stopped on a MOVE ^ DATA_IN, we jump to a
+ * script that will ignore all data in bytes until phase
+ * change, since we are not sure the chip will wait the phase
+ * change prior to delivering the interrupt.
+ */
+ if (phase == 1)
+ jmp = NCB_SCRIPTH_PHYS (np, par_err_data_in);
+ else
+ jmp = NCB_SCRIPTH_PHYS (np, par_err_other);
+
+ OUTONB (nc_ctest3, CLF ); /* clear dma fifo */
+ OUTB (nc_stest3, TE|CSF); /* clear scsi fifo */
+
+ np->msgout[0] = msg;
+ OUTL (nc_dsp, jmp);
+ return 1;
+
+reset_all:
+ ncr_start_reset(np);
+ return 1;
X }
X
X /*==========================================================
@@ -7292,72 +7302,89 @@
X if (ss2 & ORF1) rest++;
X };
X
- OUTONB (nc_ctest3, CLF ); /* clear dma fifo */
- OUTB (nc_stest3, TE|CSF); /* clear scsi fifo */
-
X if (DEBUG_FLAGS & (DEBUG_TINY|DEBUG_PHASE))
- printf ("P%x%x RL=%d D=%d SS0=%x ", cmd&7, sbcl&7,
+ printk ("P%x%x RL=%d D=%d SS0=%x ", cmd&7, sbcl&7,
X (unsigned) rest, (unsigned) delta, ss0);
X
X } else {
X if (DEBUG_FLAGS & (DEBUG_TINY|DEBUG_PHASE))
- printf ("P%x%x RL=%d ", cmd&7, sbcl&7, rest);
- if ((cmd & 7) != 1) {
- OUTONB (nc_ctest3, CLF );
- OUTB (nc_stest3, TE|CSF);
- }
+ printk ("P%x%x RL=%d ", cmd&7, sbcl&7, rest);
X }
X
X /*
- ** locate matching cp
+ ** Clear fifos.
X */
- dsa = INL (nc_dsa);
- cp = np->ccb;
- while (cp && (CCB_PHYS (cp, phys) != dsa))
- cp = cp->link_ccb;
+ OUTONB (nc_ctest3, CLF ); /* clear dma fifo */
+ OUTB (nc_stest3, TE|CSF); /* clear scsi fifo */
X
- if (!cp) {
- printf ("%s: SCSI phase error fixup: CCB already dequeued (0x%08lx)\n",
- ncr_name (np), (u_long) np->header.cp);
- return;
- }
- if (cp != np->header.cp) {
- printf ("%s: SCSI phase error fixup: CCB address mismatch (0x%08lx != 0x%08lx)\n",
- ncr_name (np), (u_long) cp, (u_long) np->header.cp);
-/* return;*/
+ /*
+ ** locate matching cp.
+ ** if the interrupted phase is DATA IN or DATA OUT,
+ ** trust the global header.
+ */
+ dsa = INL (nc_dsa);
+ if (!(cmd & 6)) {
+ cp = np->header.cp;
+ if (CCB_PHYS(cp, phys) != dsa)
+ cp = 0;
+ } else {
+ cp = np->ccb;
+ while (cp && (CCB_PHYS (cp, phys) != dsa))
+ cp = cp->link_ccb;
X }
X
X /*
- ** find the interrupted script command,
+ ** try to find the interrupted script command,
X ** and the address at which to continue.
X */
-
- if (dsp == vtophys (&cp->patch[2])) {
- vdsp = &cp->patch[0];
- nxtdsp = vdsp[3];
- } else if (dsp == vtophys (&cp->patch[6])) {
- vdsp = &cp->patch[4];
- nxtdsp = vdsp[3];
- } else if (dsp > np->p_script && dsp <= np->p_script + sizeof(struct script)) {
- vdsp = (u_int32 *) ((char*)np->script - np->p_script + dsp -8);
+ vdsp = 0;
+ nxtdsp = 0;
+ if (dsp > np->p_script &&
+ dsp <= np->p_script + sizeof(struct script)) {
+ vdsp = (u_int32 *)((char*)np->script0 + (dsp-np->p_script-8));
X nxtdsp = dsp;
- } else {
- vdsp = (u_int32 *) ((char*)np->scripth - np->p_scripth + dsp -8);
+ }
+ else if (dsp > np->p_scripth &&
+ dsp <= np->p_scripth + sizeof(struct scripth)) {
+ vdsp = (u_int32 *)((char*)np->scripth0 + (dsp-np->p_scripth-8));
X nxtdsp = dsp;
- };
+ }
+ else if (cp) {
+ if (dsp == vtophys (&cp->patch[2])) {
+ vdsp = &cp->patch[0];
+ nxtdsp = scr_to_cpu(vdsp[3]);
+ }
+ else if (dsp == vtophys (&cp->patch[6])) {
+ vdsp = &cp->patch[4];
+ nxtdsp = scr_to_cpu(vdsp[3]);
+ }
+ }
X
X /*
X ** log the information
X */
X
X if (DEBUG_FLAGS & DEBUG_PHASE) {
- printf ("\nCP=%p CP2=%p DSP=%x NXT=%x VDSP=%p CMD=%x ",
+ printk ("\nCP=%p CP2=%p DSP=%x NXT=%x VDSP=%p CMD=%x ",
X cp, np->header.cp,
X (unsigned)dsp,
X (unsigned)nxtdsp, vdsp, cmd);
X };
X
X /*
+ ** cp=0 means that the DSA does not point to a valid control
+ ** block. This should not happen since we donnot use multi-byte
+ ** move while we are being reselected ot after command complete.
+ ** We are not able to recover from such a phase error.
+ */
+ if (!cp) {
+ printk ("%s: SCSI phase error fixup: "
+ "CCB already dequeued (0x%08lx)\n",
+ ncr_name (np), (u_long) np->header.cp);
+ goto reset_all;
+ }
+
+ /*
X ** get old startaddress and old length.
X */
X
@@ -7373,7 +7400,7 @@
X };
X
X if (DEBUG_FLAGS & DEBUG_PHASE) {
- printf ("OCMD=%x\nTBLP=%p OLEN=%x OADR=%x\n",
+ printk ("OCMD=%x\nTBLP=%p OLEN=%x OADR=%x\n",
X (unsigned) (scr_to_cpu(vdsp[0]) >> 24),
X tblp,
X (unsigned) olen,
@@ -7386,18 +7413,23 @@
X
X if (cmd != (scr_to_cpu(vdsp[0]) >> 24)) {
X PRINT_ADDR(cp->cmd);
- printf ("internal error: cmd=%02x != %02x=(vdsp[0] >> 24)\n",
+ printk ("internal error: cmd=%02x != %02x=(vdsp[0] >> 24)\n",
X (unsigned)cmd, (unsigned)scr_to_cpu(vdsp[0]) >> 24);
-
- return;
+
+ goto reset_all;
X }
X
-#ifdef SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
- if ((cmd & 7) == 1 && np->assert_atn) {
- np->assert_atn = 0;
- OUTONB(nc_socl, CATN);
+ /*
+ ** cp != np->header.cp means that the header of the CCB
+ ** currently being processed has not yet been copied to
+ ** the global header area. That may happen if the device did
+ ** not accept all our messages after having been selected.
+ */
+ if (cp != np->header.cp) {
+ printk ("%s: SCSI phase error fixup: "
+ "CCB address mismatch (0x%08lx != 0x%08lx)\n",
+ ncr_name (np), (u_long) cp, (u_long) np->header.cp);
X }
-#endif
X
X /*
X ** if old phase not dataphase, leave here.
@@ -7405,52 +7437,261 @@
X
X if (cmd & 0x06) {
X PRINT_ADDR(cp->cmd);
- printf ("phase change %x-%x %d@%08x resid=%d.\n",
+ printk ("phase change %x-%x %d@%08x resid=%d.\n",
X cmd&7, sbcl&7, (unsigned)olen,
X (unsigned)oadr, (unsigned)rest);
+ goto unexpected_phase;
+ };
+
+ /*
+ ** choose the correct patch area.
+ ** if savep points to one, choose the other.
+ */
+
+ newcmd = cp->patch;
+ if (cp->phys.header.savep == cpu_to_scr(vtophys (newcmd))) newcmd+=4;
+
+ /*
+ ** fillin the commands
+ */
+
+ newcmd[0] = cpu_to_scr(((cmd & 0x0f) << 24) | rest);
+ newcmd[1] = cpu_to_scr(oadr + olen - rest);
+ newcmd[2] = cpu_to_scr(SCR_JUMP);
+ newcmd[3] = cpu_to_scr(nxtdsp);
+
+ if (DEBUG_FLAGS & DEBUG_PHASE) {
+ PRINT_ADDR(cp->cmd);
+ printk ("newcmd[%d] %x %x %x %x.\n",
+ (int) (newcmd - cp->patch),
+ (unsigned)scr_to_cpu(newcmd[0]),
+ (unsigned)scr_to_cpu(newcmd[1]),
+ (unsigned)scr_to_cpu(newcmd[2]),
+ (unsigned)scr_to_cpu(newcmd[3]));
+ }
+ /*
+ ** fake the return address (to the patch).
+ ** and restart script processor at dispatcher.
+ */
+#ifdef SCSI_NCR_PROFILE_SUPPORT
+ np->profile.num_break++;
+#endif
+ OUTL (nc_temp, vtophys (newcmd));
+ OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, dispatch));
+ return;
+
+ /*
+ ** Unexpected phase changes that occurs when the current phase
+ ** is not a DATA IN or DATA OUT phase are due to error conditions.
+ ** Such event may only happen when the SCRIPTS is using a
+ ** multibyte SCSI MOVE.
+ **
+ ** Phase change Some possible cause
+ **
+ ** COMMAND --> MSG IN SCSI parity error detected by target.
+ ** COMMAND --> STATUS Bad command or refused by target.
+ ** MSG OUT --> MSG IN Message rejected by target.
+ ** MSG OUT --> COMMAND Bogus target that discards extended
+ ** negotiation messages.
+ **
+ ** The code below does not care of the new phase and so
+ ** trusts the target. Why to annoy it ?
+ ** If the interrupted phase is COMMAND phase, we restart at
+ ** dispatcher.
+ ** If a target does not get all the messages after selection,
+ ** the code assumes blindly that the target discards extended
+ ** messages and clears the negotiation status.
+ ** If the target does not want all our response to negotiation,
+ ** we force a SIR_NEGO_PROTO interrupt (it is a hack that avoids
+ ** bloat for such a should_not_happen situation).
+ ** In all other situation, we reset the BUS.
+ ** Are these assumptions reasonnable ? (Wait and see ...)
+ */
+unexpected_phase:
+ dsp -= 8;
+ nxtdsp = 0;
+
+ switch (cmd & 7) {
+ case 2: /* COMMAND phase */
+ nxtdsp = NCB_SCRIPT_PHYS (np, dispatch);
+ break;
+#if 0
+ case 3: /* STATUS phase */
+ nxtdsp = NCB_SCRIPT_PHYS (np, dispatch);
+ break;
+#endif
+ case 6: /* MSG OUT phase */
+ np->scripth->nxtdsp_go_on[0] = cpu_to_scr(dsp + 8);
+ if (dsp == NCB_SCRIPT_PHYS (np, send_ident)) {
+ cp->host_status = HS_BUSY;
+ nxtdsp = NCB_SCRIPTH_PHYS (np, clratn_go_on);
+ }
+ else if (dsp == NCB_SCRIPTH_PHYS (np, send_wdtr) ||
+ dsp == NCB_SCRIPTH_PHYS (np, send_sdtr)) {
+ nxtdsp = dsp - 8; /* Should raise SIR_NEGO_PROTO */
+ }
+ break;
+#if 0
+ case 7: /* MSG IN phase */
+ nxtdsp = NCB_SCRIPT_PHYS (np, clrack);
+ break;
+#endif
+ }
+
+ if (nxtdsp) {
+ OUTL (nc_dsp, nxtdsp);
+ return;
+ }
+
+reset_all:
+ ncr_start_reset(np);
+}
+
+
+static void ncr_sir_to_redo(ncb_p np, int num, ccb_p cp)
+{
+ Scsi_Cmnd *cmd = cp->cmd;
+ tcb_p tp = &np->target[cmd->target];
+ lcb_p lp = tp->lp[cmd->lun];
+ XPT_QUEHEAD *qp;
+ ccb_p cp2;
+ int disc_cnt = 0;
+ int busy_cnt = 0;
+ u_int32 startp;
+ u_char s_status = INB (SS_PRT);
+
+ /*
+ ** Let the SCRIPTS processor skip all not yet started CCBs,
+ ** and count disconnected CCBs. Since the busy queue is in
+ ** the same order as the chip start queue, disconnected CCBs
+ ** are before cp and busy ones after.
+ */
+ if (lp) {
+ qp = lp->busy_ccbq.blink;
+ while (qp != &lp->busy_ccbq) {
+ cp2 = xpt_que_entry(qp, struct ccb, link_ccbq);
+ qp = qp->blink;
+ ++busy_cnt;
+ if (cp2 == cp)
+ break;
+ cp2->start.schedule.l_paddr =
+ cpu_to_scr(NCB_SCRIPTH_PHYS (np, skip));
+ }
+ lp->held_ccb = cp; /* Requeue when this one completes */
+ disc_cnt = lp->queuedccbs - busy_cnt;
+ }
+
+ switch(s_status) {
+ default: /* Just for safety, should never happen */
+ case S_QUEUE_FULL:
+ /*
+ ** Decrease number of tags to the number of
+ ** disconnected commands.
+ */
+ if (!lp)
+ goto out;
+ if (bootverbose >= 1) {
+ PRINT_ADDR(cmd);
+ printk ("QUEUE FULL! %d busy, %d disconnected CCBs\n",
+ busy_cnt, disc_cnt);
+ }
+ if (disc_cnt < lp->numtags) {
+ lp->numtags = disc_cnt > 2 ? disc_cnt : 2;
+ lp->num_good = 0;
+ ncr_setup_tags (np, cmd->target, cmd->lun);
+ }
+ /*
+ ** Requeue the command to the start queue.
+ ** If any disconnected commands,
+ ** Clear SIGP.
+ ** Jump to reselect.
+ */
+ cp->phys.header.savep = cp->startp;
+ cp->host_status = HS_BUSY;
+ cp->scsi_status = S_ILLEGAL;
+
+ ncr_put_start_queue(np, cp);
+ if (disc_cnt)
+ INB (nc_ctest2); /* Clear SIGP */
+ OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, reselect));
+ return;
+ case S_TERMINATED:
+ case S_CHECK_COND:
+ /*
+ ** If we were requesting sense, give up.
+ */
+ if (cp->auto_sense)
+ goto out;
+
+ /*
+ ** Device returned CHECK CONDITION status.
+ ** Prepare all needed data strutures for getting
+ ** sense data.
+ **
+ ** identify message
+ */
+ cp->scsi_smsg2[0] = M_IDENTIFY | cmd->lun;
+ cp->phys.smsg.addr = cpu_to_scr(CCB_PHYS (cp, scsi_smsg2));
+ cp->phys.smsg.size = cpu_to_scr(1);
+
+ /*
+ ** sense command
+ */
+ cp->phys.cmd.addr = cpu_to_scr(CCB_PHYS (cp, sensecmd));
+ cp->phys.cmd.size = cpu_to_scr(6);
+
+ /*
+ ** patch requested size into sense command
+ */
+ cp->sensecmd[0] = 0x03;
+ cp->sensecmd[1] = cmd->lun << 5;
+ cp->sensecmd[4] = sizeof(cmd->sense_buffer);
+
+ /*
+ ** sense data
+ */
+ cp->phys.sense.addr =
+ cpu_to_scr(vtophys (&cmd->sense_buffer[0]));
+ cp->phys.sense.size =
+ cpu_to_scr(sizeof(cmd->sense_buffer));
X
- OUTONB (nc_dcntl, (STD|NOCOM));
- return;
- };
+ /*
+ ** requeue the command.


SHAR_EOF
true || echo 'restore of patch-2.0.37 failed'
fi

echo 'End of part 32'
echo 'File patch-2.0.37 is continued in part 33'
echo 33 > _shar_seq_.tmp
exit 0

Thomas...@ciw.uni-karlsruhe.de

unread,
Jun 16, 1999, 3:00:00 AM6/16/99
to
Archive-name: v2.0/patch-2.0.37/part27

#!/bin/sh
# this is part 27 of a 45 - part archive


# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.0.37 continued
if test ! -r _shar_seq_.tmp; then
echo 'Please unpack part 1 first!'
exit 1
fi
(read Scheck

if test "$Scheck" != 27; then


echo Please unpack part "$Scheck" next!
exit 1
else
exit 0
fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.0.37'
else
echo 'x - continuing with patch-2.0.37'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.0.37' &&
+

+ if (pSRB == NULL) {
+ printk("pSRB is NULL\n");
+ }
+ pSRB->scsi_done(pSRB); /* Notify system DONE */
+ if ((pSRB = i91uPopSRBFromQueue(pHCB)) != NULL)
+ /* Find the next pending SRB */
+ { /* Assume resend will success */
+ /* Reuse old SCB */
+ i91uBuildSCB(pHCB, pSCB, pSRB); /* Create corresponding SCB */
+


+ tul_exec_scb(pHCB, pSCB); /* Start execute SCB */

+ } else { /* No Pending SRB */


+ tul_release_scb(pHCB, pSCB); /* Release SCB for current channel */
+ }

+ return;
+}
+
+/*

+ * Interrupts handler (main routine of the driver)


+ */
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)

+static void i91u_intr0(int irqno, void *dev_id, struct pt_regs *regs)
+#else
+static void i91u_intr0(int irqno, struct pt_regs *regs)
+#endif
+{
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+ unsigned long flags;
+#endif
+
+ if (tul_hcs[0].HCS_Intr != irqno)
+ return;


+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)

+ spin_lock_irqsave(&io_request_lock, flags);
+#endif
+
+ tul_isr(&tul_hcs[0]);


+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)

+ spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
+}
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
+static void i91u_intr1(int irqno, void *dev_id, struct pt_regs *regs)
+#else
+static void i91u_intr1(int irqno, struct pt_regs *regs)
+#endif
+{
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+ unsigned long flags;
+#endif
+
+ if (tul_hcs[1].HCS_Intr != irqno)
+ return;


+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)

+ spin_lock_irqsave(&io_request_lock, flags);
+#endif
+
+ tul_isr(&tul_hcs[1]);


+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)

+ spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
+}
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
+static void i91u_intr2(int irqno, void *dev_id, struct pt_regs *regs)
+#else
+static void i91u_intr2(int irqno, struct pt_regs *regs)
+#endif
+{
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+ unsigned long flags;
+#endif
+
+ if (tul_hcs[2].HCS_Intr != irqno)
+ return;


+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)

+ spin_lock_irqsave(&io_request_lock, flags);
+#endif
+
+ tul_isr(&tul_hcs[2]);


+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)

+ spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
+}
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
+static void i91u_intr3(int irqno, void *dev_id, struct pt_regs *regs)
+#else
+static void i91u_intr3(int irqno, struct pt_regs *regs)
+#endif
+{
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+ unsigned long flags;
+#endif
+
+ if (tul_hcs[3].HCS_Intr != irqno)
+ return;


+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)

+ spin_lock_irqsave(&io_request_lock, flags);
+#endif
+
+ tul_isr(&tul_hcs[3]);


+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)

+ spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
+}
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
+static void i91u_intr4(int irqno, void *dev_id, struct pt_regs *regs)
+#else
+static void i91u_intr4(int irqno, struct pt_regs *regs)
+#endif
+{
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+ unsigned long flags;
+#endif
+
+ if (tul_hcs[4].HCS_Intr != irqno)
+ return;


+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)

+ spin_lock_irqsave(&io_request_lock, flags);
+#endif
+
+ tul_isr(&tul_hcs[4]);


+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)

+ spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
+}
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
+static void i91u_intr5(int irqno, void *dev_id, struct pt_regs *regs)
+#else
+static void i91u_intr5(int irqno, struct pt_regs *regs)
+#endif
+{
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+ unsigned long flags;
+#endif
+
+ if (tul_hcs[5].HCS_Intr != irqno)
+ return;


+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)

+ spin_lock_irqsave(&io_request_lock, flags);
+#endif
+
+ tul_isr(&tul_hcs[5]);


+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)

+ spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
+}
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
+static void i91u_intr6(int irqno, void *dev_id, struct pt_regs *regs)
+#else
+static void i91u_intr6(int irqno, struct pt_regs *regs)
+#endif
+{
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+ unsigned long flags;
+#endif
+
+ if (tul_hcs[6].HCS_Intr != irqno)
+ return;


+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)

+ spin_lock_irqsave(&io_request_lock, flags);
+#endif
+
+ tul_isr(&tul_hcs[6]);


+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)

+ spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
+}
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
+static void i91u_intr7(int irqno, void *dev_id, struct pt_regs *regs)
+#else
+static void i91u_intr7(int irqno, struct pt_regs *regs)
+#endif
+{
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+ unsigned long flags;
+#endif
+
+ if (tul_hcs[7].HCS_Intr != irqno)
+ return;


+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)

+ spin_lock_irqsave(&io_request_lock, flags);
+#endif
+
+ tul_isr(&tul_hcs[7]);


+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)

+ spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
+}
+
+/*
+ * Dump the current driver status and panic...
+ */
+static void i91u_panic(char *msg)
+{
+ printk("\ni91u_panic: %s\n", msg);
+ panic("i91u panic");
+}
diff -u --recursive --new-file v2.0.36/linux/drivers/scsi/ini9100u.h linux/drivers/scsi/ini9100u.h
--- v2.0.36/linux/drivers/scsi/ini9100u.h Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/ini9100u.h Sun Jun 13 10:21:02 1999
@@ -0,0 +1,345 @@


+/**************************************************************************
+ * Initio 9100 device driver for Linux.
+ *
+ * Copyright (c) 1994-1998 Initio Corporation

+ * Module: ini9100u.h
+ * Description: INI-9100U/UW LINUX device driver header
+ * Revision History:
+ * 06/18/96 Harry Chen, Initial Version 1.00A (Beta)
+ * 06/23/98 hc - v1.01k


+ * - Get it work for kernel version >= 2.1.75

+ * 12/09/98 bv - v1.03a
+ * - Removed unused code
+ * 12/13/98 bv - v1.03b

+ * - Add spinlocks to HCS structure.


+ * 21/01/99 bv - v1.03e

+ * - Added PCI_ID structure
+ **************************************************************************/
+
+#ifndef CVT_LINUX_VERSION
+#define CVT_LINUX_VERSION(V,P,S) (((V) * 65536) + ((P) * 256) + (S))
+#endif


+
+#ifndef LINUX_VERSION_CODE
+#include <linux/version.h>
+#endif
+

+#include "sd.h"
+
+extern int i91u_detect(Scsi_Host_Template *);
+extern int i91u_command(Scsi_Cmnd *);
+extern int i91u_queue(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
+extern int i91u_abort(Scsi_Cmnd *);
+extern int i91u_reset(Scsi_Cmnd *, unsigned int);
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1, 3, 0)
+extern int i91u_biosparam(Scsi_Disk *, kdev_t, int *); /*for linux v2.0 */
+extern struct proc_dir_entry proc_scsi_ini9100u;
+#else
+extern int i91u_biosparam(Disk *, int, int *); /*for linux v1.13 */
+#endif
+
+#define i91u_REVID "Initio INI-9X00U/UW SCSI device driver; Revision: 1.03f"
+
+#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(1, 3, 0)
+#define INI9100U { \
+ NULL, \
+ NULL, \
+ i91u_REVID, \
+ i91u_detect, \
+ NULL, \
+ NULL, \
+ i91u_command, \
+ i91u_queue, \
+ i91u_abort, \
+ i91u_reset, \
+ NULL, \
+ i91u_biosparam, \
+ 1, \
+ 7, \
+ SG_ALL, \
+ 1, \
+ 0, \
+ 0, \
+ ENABLE_CLUSTERING \
+}
+#else
+
+#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2, 1, 75)
+#define INI9100U { \
+ NULL, \
+ NULL, \
+ &proc_scsi_ini9100u, \
+ NULL, \
+ i91u_REVID, \
+ i91u_detect, \
+ NULL, \
+ NULL, \
+ i91u_command, \
+ i91u_queue, \
+ i91u_abort, \
+ i91u_reset, \
+ NULL, \
+ i91u_biosparam, \
+ 1, \
+ 7, \
+ SG_ALL, \
+ 1, \
+ 0, \
+ 0, \
+ ENABLE_CLUSTERING \
+}
+#else /* Version >= 2.1.75 */
+#define INI9100U { \
+ next: NULL, \
+ module: NULL, \
+ proc_dir: &proc_scsi_ini9100u, \
+ proc_info: NULL, \
+ name: i91u_REVID, \
+ detect: i91u_detect, \
+ release: NULL, \
+ info: NULL, \
+ command: i91u_command, \
+ queuecommand: i91u_queue, \
+ eh_strategy_handler: NULL, \
+ eh_abort_handler: NULL, \
+ eh_device_reset_handler: NULL, \
+ eh_bus_reset_handler: NULL, \
+ eh_host_reset_handler: NULL, \
+ abort: i91u_abort, \
+ reset: i91u_reset, \
+ slave_attach: NULL, \
+ bios_param: i91u_biosparam, \
+ can_queue: 1, \
+ this_id: 1, \
+ sg_tablesize: SG_ALL, \
+ cmd_per_lun: 1, \
+ present: 0, \
+ unchecked_isa_dma: 0, \
+ use_clustering: ENABLE_CLUSTERING, \
+ use_new_eh_code: 0 \
+}
+#endif
+#endif
+
+
+#define VIRT_TO_BUS(i) (unsigned int) virt_to_bus((void *)(i))
+#define ULONG unsigned long
+#define USHORT unsigned short
+#define UCHAR unsigned char
+#define BYTE unsigned char
+#define WORD unsigned short
+#define DWORD unsigned long
+#define UBYTE unsigned char
+#define UWORD unsigned short
+#define UDWORD unsigned long
+#ifdef ALPHA
+#define U32 unsigned int
+#else
+#define U32 unsigned long
+#endif
+
+#ifndef NULL
+#define NULL 0 /* zero */
+#endif
+#ifndef TRUE
+#define TRUE (1) /* boolean true */
+#endif
+#ifndef FALSE
+#define FALSE (0) /* boolean false */
+#endif
+#ifndef FAILURE
+#define FAILURE (-1)
+#endif
+
+#define i91u_MAXQUEUE 2
+#define TOTAL_SG_ENTRY 32
+#define MAX_TARGETS 16
+#define SENSE_SIZE 14
+
+#define INI_VENDOR_ID 0x1101 /* Initio's PCI vendor ID */
+#define DMX_VENDOR_ID 0x134a /* Domex's PCI vendor ID */
+#define I950_DEVICE_ID 0x9500 /* Initio's inic-950 product ID */
+#define I940_DEVICE_ID 0x9400 /* Initio's inic-940 product ID */
+#define I935_DEVICE_ID 0x9401 /* Initio's inic-935 product ID */
+#define I920_DEVICE_ID 0x0002 /* Initio's other product ID */
+
+/************************************************************************/
+/* Vendor ID/Device ID Pair Structure */
+/************************************************************************/
+typedef struct PCI_ID_Struc {
+ unsigned short vendor_id;
+ unsigned short device_id;
+} PCI_ID;


+
+/************************************************************************/
+/* Scatter-Gather Element Structure */
+/************************************************************************/
+typedef struct SG_Struc {
+ U32 SG_Ptr; /* Data Pointer */
+ U32 SG_Len; /* Data Length */
+} SG;
+
+/***********************************************************************
+ SCSI Control Block
+************************************************************************/
+typedef struct Scsi_Ctrl_Blk {

+ U32 SCB_InitioReserved[9]; /* 0 */


+
+ UBYTE SCB_Opcode; /*24 SCB command code */
+ UBYTE SCB_Flags; /*25 SCB Flags */
+ UBYTE SCB_Target; /*26 Target Id */
+ UBYTE SCB_Lun; /*27 Lun */
+ U32 SCB_BufPtr; /*28 Data Buffer Pointer */
+ U32 SCB_BufLen; /*2C Data Allocation Length */
+ UBYTE SCB_SGLen; /*30 SG list # */
+ UBYTE SCB_SenseLen; /*31 Sense Allocation Length */
+ UBYTE SCB_HaStat; /*32 */
+ UBYTE SCB_TaStat; /*33 */
+ UBYTE SCB_CDBLen; /*34 CDB Length */
+ UBYTE SCB_Ident; /*35 Identify */
+ UBYTE SCB_TagMsg; /*36 Tag Message */
+ UBYTE SCB_TagId; /*37 Queue Tag */
+ UBYTE SCB_CDB[12]; /*38 */
+ U32 SCB_SGPAddr; /*44 SG List/Sense Buf phy. Addr. */
+ U32 SCB_SensePtr; /*48 Sense data pointer */
+ void (*SCB_Post) (BYTE *, BYTE *); /*4C POST routine */

+ Scsi_Cmnd *SCB_Srb; /*50 SRB Pointer */


+ SG SCB_SGList[TOTAL_SG_ENTRY]; /*54 Start of SG list */
+} SCB;
+

+/* Opcodes of SCB_Opcode */
+#define ExecSCSI 0x1
+#define BusDevRst 0x2
+#define AbortCmd 0x3
+

+/* Bit Definition for SCB_Flags */
+#define SCF_DONE 0x01
+#define SCF_POST 0x02
+#define SCF_SENSE 0x04
+#define SCF_DIR 0x18
+#define SCF_NO_DCHK 0x00
+#define SCF_DIN 0x08
+#define SCF_DOUT 0x10
+#define SCF_NO_XF 0x18

+#define SCF_POLL 0x40
+#define SCF_SG 0x80
+
+/* Error Codes for SCB_HaStat */
+#define HOST_SEL_TOUT 0x11
+#define HOST_DO_DU 0x12
+#define HOST_BUS_FREE 0x13
+#define HOST_BAD_PHAS 0x14
+#define HOST_INV_CMD 0x16

+#define HOST_SCSI_RST 0x1B
+#define HOST_DEV_RST 0x1C
+
+/* Error Codes for SCB_TaStat */
+#define TARGET_CHKCOND 0x02
+#define TARGET_BUSY 0x08

+
+/* Queue tag msg: Simple_quque_tag, Head_of_queue_tag, Ordered_queue_tag */
+#define MSG_STAG 0x20
+#define MSG_HTAG 0x21
+#define MSG_OTAG 0x22
+

+/***********************************************************************
+ Target Device Control Structure
+**********************************************************************/
+
+typedef struct Tar_Ctrl_Struc {

+ ULONG TCS_InitioReserved; /* 0 */


+
+ UWORD TCS_DrvFlags; /* 4 */
+ UBYTE TCS_DrvHead; /* 6 */
+ UBYTE TCS_DrvSector; /* 7 */
+} TCS;
+
+/***********************************************************************
+ Target Device Control Structure
+**********************************************************************/

+/* Bit Definition for TCF_DrvFlags */

+#define TCF_DRV_255_63 0x0400


+
+/***********************************************************************
+ Host Adapter Control Structure
+************************************************************************/
+typedef struct Ha_Ctrl_Struc {
+ UWORD HCS_Base; /* 00 */
+ UWORD HCS_BIOS; /* 02 */
+ UBYTE HCS_Intr; /* 04 */
+ UBYTE HCS_SCSI_ID; /* 05 */
+ UBYTE HCS_MaxTar; /* 06 */
+ UBYTE HCS_NumScbs; /* 07 */
+
+ UBYTE HCS_Flags; /* 08 */
+ UBYTE HCS_Index; /* 09 */

+ UBYTE HCS_Reserved[2]; /* 0a */
+ ULONG HCS_InitioReserved[27]; /* 0C */
+ TCS HCS_Tcs[16]; /* 78 -> 16 Targets */
+ Scsi_Cmnd *pSRB_head; /* SRB save queue header */
+ Scsi_Cmnd *pSRB_tail; /* SRB save queue tail */


+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+ spinlock_t HCS_AvailLock;
+ spinlock_t HCS_SemaphLock;
+ spinlock_t pSRB_lock;

+#endif
+} HCS;
+
+/* Bit Definition for HCB_Flags */
+#define HCF_EXPECT_RESET 0x10


+
+/* SCSI related definition */
+#define DISC_NOT_ALLOW 0x80 /* Disconnect is not allowed */
+#define DISC_ALLOW 0xC0 /* Disconnect is allowed */

diff -u --recursive --new-file v2.0.36/linux/drivers/scsi/inia100.c linux/drivers/scsi/inia100.c
--- v2.0.36/linux/drivers/scsi/inia100.c Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/inia100.c Sun Jun 13 10:21:02 1999
@@ -0,0 +1,953 @@
+/**************************************************************************
+ * Initio A100 device driver for Linux.


+ *
+ * Copyright (c) 1994-1998 Initio Corporation

+ **************************************************************************
+ *
+ * module: inia100.c
+ * DESCRIPTION:
+ * This is the Linux low-level SCSI driver for Initio INIA100 SCSI host
+ * adapters
+ * 09/24/98 hl - v1.02 initial production release.
+ * 12/19/98 bv - v1.02a Use spinlocks for 2.1.95 and up.


+ **************************************************************************/
+
+#define CVT_LINUX_VERSION(V,P,S) (V * 65536 + P * 256 + S)
+
+#ifndef LINUX_VERSION_CODE
+#include <linux/version.h>
+#endif
+
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
+#include <stdarg.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>

+#include <linux/delay.h>
+#include <linux/sched.h>


+#if LINUX_VERSION_CODE <= CVT_LINUX_VERSION(2,1,92)
+#include <linux/bios32.h>
+#endif

+#include <linux/pci.h>
+#include <linux/proc_fs.h>
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,23)
+#include <linux/init.h>
+#endif
+#include <linux/blk.h>
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+#include <asm/spinlock.h>
+#endif
+#include "sd.h"
+#include "scsi.h"
+#include "hosts.h"

+#include "inia100.h"


+#include <linux/stat.h>
+#include <linux/malloc.h>
+#include <linux/config.h>
+
+
+#else
+
+#include <linux/kernel.h>
+#include <linux/head.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include "../block/blk.h"
+#include "scsi.h"
+#include "sd.h"
+#include "hosts.h"
+#include <linux/malloc.h>

+#include "inia100.h"
+#endif
+
+#ifdef MODULE
+Scsi_Host_Template driver_template = INIA100;
+#include "scsi_module.c"
+#endif
+
+#define ORC_RDWORD(x,y) (short)(inl((int)((ULONG)((ULONG)x+(UCHAR)y)) ))
+
+char *inia100_Copyright = "Copyright (C) 1998-99";
+char *inia100_InitioName = "by Initio Corporation";
+char *inia100_ProductName = "INI-A100U2W";
+char *inia100_Version = "v1.02a";


+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)

+struct proc_dir_entry proc_scsi_inia100 =
+{
+ PROC_SCSI_INIA100, 7, "INIA100",


+ S_IFDIR | S_IRUGO | S_IXUGO, 2,
+ 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+};
+#endif
+

+/* set by inia100_setup according to the command line */


+static int setup_called = 0;

+static int orc_num_ch = MAX_SUPPORTED_ADAPTERS; /* Maximum 4 adapters */
+
+/* ---- INTERNAL VARIABLES ---- */
+#define NUMBER(arr) (sizeof(arr) / sizeof(arr[0]))


+static char *setup_str = (char *) NULL;
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)

+static void inia100_intr0(int irq, void *dev_id, struct pt_regs *);
+static void inia100_intr1(int irq, void *dev_id, struct pt_regs *);
+static void inia100_intr2(int irq, void *dev_id, struct pt_regs *);
+static void inia100_intr3(int irq, void *dev_id, struct pt_regs *);
+static void inia100_intr4(int irq, void *dev_id, struct pt_regs *);
+static void inia100_intr5(int irq, void *dev_id, struct pt_regs *);
+static void inia100_intr6(int irq, void *dev_id, struct pt_regs *);
+static void inia100_intr7(int irq, void *dev_id, struct pt_regs *);
+#else
+static void inia100_intr0(int irq, struct pt_regs *);
+static void inia100_intr1(int irq, struct pt_regs *);
+static void inia100_intr2(int irq, struct pt_regs *);
+static void inia100_intr3(int irq, struct pt_regs *);
+static void inia100_intr4(int irq, struct pt_regs *);
+static void inia100_intr5(int irq, struct pt_regs *);
+static void inia100_intr6(int irq, struct pt_regs *);
+static void inia100_intr7(int irq, struct pt_regs *);
+#endif
+
+static void inia100_panic(char *msg);
+void inia100SCBPost(BYTE * pHcb, BYTE * pScb);
+
+/* ---- EXTERNAL VARIABLES ---- */
+extern int Addinia100_into_Adapter_table(WORD, WORD, BYTE, BYTE, BYTE);
+extern void init_inia100Adapter_table(void);
+extern ORC_SCB *orc_alloc_scb(ORC_HCS * hcsp);
+extern void orc_exec_scb(ORC_HCS * hcsp, ORC_SCB * scbp);
+extern void orc_release_scb(ORC_HCS * hcsp, ORC_SCB * scbp);
+extern void orc_interrupt(ORC_HCS * hcsp);
+extern int orc_device_reset(ORC_HCS * pHCB, ULONG SCpnt, unsigned int target, unsigned int ResetFlags);
+extern int orc_reset_scsi_bus(ORC_HCS * pHCB);
+extern int abort_SCB(ORC_HCS * hcsp, ORC_SCB * pScb);
+extern int orc_abort_srb(ORC_HCS * hcsp, ULONG SCpnt);
+extern void get_orcPCIConfig(ORC_HCS * pCurHcb, int ch_idx);
+extern int init_orchid(ORC_HCS * hcsp);
+
+extern int orc_num_scb;
+extern ORC_HCS orc_hcs[];
+
+/*****************************************************************************
+ Function name : inia100AppendSRBToQueue


+ Description : This function will push current request into save list
+ Input : pSRB - Pointer to SCSI request block.
+ pHCB - Pointer to host adapter structure
+ Output : None.
+ Return : None.
+*****************************************************************************/

+static void inia100AppendSRBToQueue(ORC_HCS * pHCB, Scsi_Cmnd * pSRB)
+{
+ ULONG flags;


+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+ spin_lock_irqsave(&(pHCB->pSRB_lock), flags);
+#else
+ save_flags(flags);
+ cli();
+#endif
+

+ pSRB->next = NULL; /* Pointer to next */
+ if (pHCB->pSRB_head == NULL)
+ pHCB->pSRB_head = pSRB;
+ else
+ pHCB->pSRB_tail->next = pSRB; /* Pointer to next */
+ pHCB->pSRB_tail = pSRB;

+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+ spin_unlock_irqrestore(&(pHCB->pSRB_lock), flags);
+#else
+ restore_flags(flags);
+#endif
+ return;
+}
+
+/*****************************************************************************

+ Function name : inia100PopSRBFromQueue


+ Description : This function will pop current request from save list
+ Input : pHCB - Pointer to host adapter structure
+ Output : None.
+ Return : pSRB - Pointer to SCSI request block.
+*****************************************************************************/

+static Scsi_Cmnd *inia100PopSRBFromQueue(ORC_HCS * pHCB)


+{
+ Scsi_Cmnd *pSRB;
+ ULONG flags;

+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+ spin_lock_irqsave(&(pHCB->pSRB_lock), flags);
+#else
+ save_flags(flags);
+ cli();
+#endif
+

+ if ((pSRB = (Scsi_Cmnd *) pHCB->pSRB_head) != NULL) {


+ pHCB->pSRB_head = pHCB->pSRB_head->next;
+ pSRB->next = NULL;
+ }
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+ spin_unlock_irqrestore(&(pHCB->pSRB_lock), flags);
+#else
+ restore_flags(flags);
+#endif

+ return (pSRB);
+}
+
+/*****************************************************************************
+ Function name : inia100_setup
+ Description :

+ Input : pHCB - Pointer to host adapter structure
+ Output : None.
+ Return : pSRB - Pointer to SCSI request block.
+*****************************************************************************/

+void inia100_setup(char *str, int *ints)
+{
+ if (setup_called)
+ inia100_panic("inia100: inia100_setup called twice.\n");


+
+ setup_called = ints[0];
+ setup_str = str;
+}

+
+/*****************************************************************************
+ Function name : orc_ReturnNumberOfAdapters


+ Description : This function will scan PCI bus to get all Orchid card
+ Input : None.
+ Output : None.
+ Return : SUCCESSFUL - Successful scan
+ ohterwise - No drives founded
+*****************************************************************************/

+int orc_ReturnNumberOfAdapters(void)


+{
+ unsigned int i, iAdapters;
+

+ iAdapters = 0;
+ /*
+ * PCI-bus probe.
+ */
+ if (pcibios_present()) {

+ struct {
+ unsigned short vendor_id;
+ unsigned short device_id;
+ } const inia100_pci_devices[] =
+ {
+ {ORC_VENDOR_ID, I920_DEVICE_ID},
+ {ORC_VENDOR_ID, ORC_DEVICE_ID}
+ };
+


+ unsigned int dRegValue;
+ unsigned short command;
+ WORD wBIOS, wBASE;
+ BYTE bPCIBusNum, bInterrupt, bPCIDeviceNum;
+

+#ifdef MMAPIO
+ unsigned long page_offset, base;
+#endif
+

+#if LINUX_VERSION_CODE > CVT_LINUX_VERSION(2,1,92)
+ struct pci_dev *pdev = NULL;
+#else


+ int index;
+ unsigned char pci_bus, pci_devfn;

+#endif


+
+ bPCIBusNum = 0;
+ bPCIDeviceNum = 0;

+ init_inia100Adapter_table();
+ for (i = 0; i < NUMBER(inia100_pci_devices); i++) {
+#if LINUX_VERSION_CODE > CVT_LINUX_VERSION(2,1,92)
+ pdev = NULL;
+ while ((pdev = pci_find_device(inia100_pci_devices[i].vendor_id,
+ inia100_pci_devices[i].device_id,
+ pdev)))
+#else
+ index = 0;
+ while (!(pcibios_find_device(inia100_pci_devices[i].vendor_id,
+ inia100_pci_devices[i].device_id,
+ index++, &pci_bus, &pci_devfn)))
+#endif
+ {
+ if (iAdapters >= MAX_SUPPORTED_ADAPTERS)
+ break; /* Never greater than maximum */
+
+ if (i == 0) {
+ /*
+ printk("inia100: The RAID controller is not supported by\n");
+ printk("inia100: this driver, we are ignoring it.\n");
+ */


+ } else {
+ /*
+ * Read sundry information from PCI BIOS.
+ */

+#if LINUX_VERSION_CODE > CVT_LINUX_VERSION(2,1,92)
+ bPCIBusNum = pdev->bus->number;
+ bPCIDeviceNum = pdev->devfn;
+ dRegValue = pdev->base_address[0];


+ if (dRegValue == -1) { /* Check return code */

+ printk("\n\rinia100: orchid read configuration error.\n");


+ return (0); /* Read configuration space error */
+ }
+ /* <02> read from base address + 0x50 offset to get the wBIOS balue. */
+ wBASE = (WORD) dRegValue;
+
+ /* Now read the interrupt line */

+ dRegValue = pdev->irq;


+ bInterrupt = dRegValue & 0xFF; /* Assign interrupt line */

+ pci_read_config_word(pdev, PCI_COMMAND, &command);
+ pci_write_config_word(pdev, PCI_COMMAND,


+ command | PCI_COMMAND_MASTER | PCI_COMMAND_IO);
+

+#else


+ bPCIBusNum = pci_bus;
+ bPCIDeviceNum = pci_devfn;
+ pcibios_read_config_dword(pci_bus, pci_devfn, PCI_BASE_ADDRESS_0,
+ &dRegValue);
+ if (dRegValue == -1) { /* Check return code */

+ printk("\n\rinia100: Orchid read configuration error.\n");


+ return (0); /* Read configuration space error */
+ }
+ /* <02> read from base address + 0x50 offset to get the wBIOS balue. */
+ wBASE = (WORD) dRegValue;
+
+ /* Now read the interrupt line */
+ pcibios_read_config_dword(pci_bus, pci_devfn, PCI_INTERRUPT_LINE,
+ &dRegValue);
+ bInterrupt = dRegValue & 0xFF; /* Assign interrupt line */
+ pcibios_read_config_word(pci_bus, pci_devfn, PCI_COMMAND, &command);
+ pcibios_write_config_word(pci_bus, pci_devfn, PCI_COMMAND,
+ command | PCI_COMMAND_MASTER | PCI_COMMAND_IO);

+#endif
+ wBASE &= PCI_BASE_ADDRESS_IO_MASK;
+ wBIOS = ORC_RDWORD(wBASE, 0x50);


+
+#ifdef MMAPIO
+ base = wBASE & PAGE_MASK;
+ page_offset = wBASE - base;
+
+ /*
+ * replace the next line with this one if you are using 2.1.x:
+ * temp_p->maddr = ioremap(base, page_offset + 256);
+ */
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,0)
+ wBASE = ioremap(base, page_offset + 256);
+#else
+ wBASE = (WORD) vremap(base, page_offset + 256);
+#endif
+ if (wBASE) {
+ wBASE += page_offset;
+ }
+#endif
+

+ if (Addinia100_into_Adapter_table(wBIOS, wBASE, bInterrupt, bPCIBusNum,
+ bPCIDeviceNum) == SUCCESSFUL)


+ iAdapters++;
+ }
+ } /* while(pdev=....) */
+ } /* for PCI_DEVICES */
+ } /* PCI BIOS present */
+ return (iAdapters);
+}

+
+/*****************************************************************************
+ Function name : inia100_detect
+ Description :

+ Input : pHCB - Pointer to host adapter structure
+ Output : None.
+ Return : pSRB - Pointer to SCSI request block.
+*****************************************************************************/

+int inia100_detect(Scsi_Host_Template * tpnt)
+{
+ ORC_HCS *pHCB;
+ struct Scsi_Host *hreg;
+ U32 sz;
+ U32 i; /* 01/14/98 */


+ int ok = 0, iAdapters;
+ ULONG dBiosAdr;
+ BYTE *pbBiosAdr;
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)

+ tpnt->proc_dir = &proc_scsi_inia100;
+#endif
+ if (setup_called) {
+ /* Setup by inia100_setup */
+ printk("inia100: processing commandline: ");


+ }
+ /* Get total number of adapters in the motherboard */

+ iAdapters = orc_ReturnNumberOfAdapters();
+
+ /* printk("inia100: Total Initio Adapters = %d\n", iAdapters); */
+ if (iAdapters == 0) /* If no orc founded, return */
+ return (0);
+
+ orc_num_ch = (iAdapters > orc_num_ch) ? orc_num_ch : iAdapters;
+ orc_num_scb = ORC_MAXQUEUE;
+
+ /* clear the memory needed for HCS */
+ i = orc_num_ch * sizeof(ORC_HCS);
+ memset((unsigned char *) &orc_hcs[0], 0, i); /* Initialize orc_hcs 0 */
+
+#if 0
+ printk("orc_num_scb= %x orc_num_ch= %x hcsize= %x scbsize= %x escbsize= %x\n",
+ orc_num_scb, orc_num_ch, sizeof(ORC_HCS), sizeof(ORC_SCB), sizeof(ESCB));
+#endif
+
+ for (i = 0, pHCB = &orc_hcs[0]; /* Get pointer for control block */
+ i < orc_num_ch;
+ i++, pHCB++) {
+


+ pHCB->pSRB_head = NULL; /* Initial SRB save queue */
+ pHCB->pSRB_tail = NULL; /* Initial SRB save queue */
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+ pHCB->pSRB_lock = SPIN_LOCK_UNLOCKED; /* SRB save queue lock */
+#endif

+ /* Get total memory needed for SCB */

+ sz = orc_num_scb * sizeof(ORC_SCB);
+ if ((pHCB->HCS_virScbArray = (PVOID) kmalloc(sz, GFP_ATOMIC | GFP_DMA)) == NULL) {
+ printk("inia100: SCB memory allocation error\n");
+ return (0);
+ }
+ memset((unsigned char *) pHCB->HCS_virScbArray, 0, sz);
+ pHCB->HCS_physScbArray = (U32) VIRT_TO_BUS(pHCB->HCS_virScbArray);
+
+ /* Get total memory needed for ESCB */
+ sz = orc_num_scb * sizeof(ESCB);
+ if ((pHCB->HCS_virEscbArray = (PVOID) kmalloc(sz, GFP_ATOMIC | GFP_DMA)) == NULL) {
+ printk("inia100: ESCB memory allocation error\n");
+ return (0);
+ }
+ memset((unsigned char *) pHCB->HCS_virEscbArray, 0, sz);
+ pHCB->HCS_physEscbArray = (U32) VIRT_TO_BUS(pHCB->HCS_virEscbArray);
+
+ request_region(pHCB->HCS_Base, 0x100, "inia100"); /* Register */
+ get_orcPCIConfig(pHCB, i);


+
+ dBiosAdr = pHCB->HCS_BIOS;
+ dBiosAdr = (dBiosAdr << 4);
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
+ pbBiosAdr = phys_to_virt(dBiosAdr);
+#endif
+

+ if (init_orchid(pHCB)) { /* Initial orchid chip */
+ printk("inia100: initial orchid fail!!\n");
+ return (0);
+ }
+ hreg = scsi_register(tpnt, sizeof(ORC_HCS));
+ if (hreg == NULL) {
+ printk("Invalid scsi_register pointer.\n");
+ }


+ hreg->io_port = pHCB->HCS_Base;
+ hreg->n_io_port = 0xff;

+ hreg->can_queue = orc_num_scb; /* 03/05/98 */


+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)

+ hreg->unique_id = pHCB->HCS_Base;
+ hreg->max_id = pHCB->HCS_MaxTar;
+#endif
+
+ hreg->max_lun = 32; /* 10/21/97 */

+/*
+ hreg->max_lun = 8;
+ hreg->max_channel = 1;
+ */


+ hreg->irq = pHCB->HCS_Intr;
+ hreg->this_id = pHCB->HCS_SCSI_ID; /* Assign HCS index */
+ hreg->base = (UCHAR *) pHCB;
+

+#if 1


+ hreg->sg_tablesize = TOTAL_SG_ENTRY; /* Maximun support is 32 */

+#else
+ hreg->sg_tablesize = SG_NONE; /* No SG */
+#endif
+
+ /* Initial orc chip */


+ switch (i) {
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
+ case 0:

+ ok = request_irq(pHCB->HCS_Intr, inia100_intr0, SA_INTERRUPT | SA_SHIRQ, "inia100", NULL);


+ break;
+ case 1:

+ ok = request_irq(pHCB->HCS_Intr, inia100_intr1, SA_INTERRUPT | SA_SHIRQ, "inia100", NULL);


+ break;
+ case 2:

+ ok = request_irq(pHCB->HCS_Intr, inia100_intr2, SA_INTERRUPT | SA_SHIRQ, "inia100", NULL);


+ break;
+ case 3:

+ ok = request_irq(pHCB->HCS_Intr, inia100_intr3, SA_INTERRUPT | SA_SHIRQ, "inia100", NULL);


+ break;
+ case 4:

+ ok = request_irq(pHCB->HCS_Intr, inia100_intr4, SA_INTERRUPT | SA_SHIRQ, "inia100", NULL);


+ break;
+ case 5:

+ ok = request_irq(pHCB->HCS_Intr, inia100_intr5, SA_INTERRUPT | SA_SHIRQ, "inia100", NULL);


+ break;
+ case 6:

+ ok = request_irq(pHCB->HCS_Intr, inia100_intr6, SA_INTERRUPT | SA_SHIRQ, "inia100", NULL);


+ break;
+ case 7:

+ ok = request_irq(pHCB->HCS_Intr, inia100_intr7, SA_INTERRUPT | SA_SHIRQ, "inia100", NULL);
+ break;
+ default:
+ inia100_panic("inia100: Too many host adapters\n");


+ break;
+ }
+
+ if (ok < 0) {
+ if (ok == -EINVAL) {

+ printk("inia100: bad IRQ %d.\n", pHCB->HCS_Intr);


+ printk(" Contact author.\n");

+ } else {
+ if (ok == -EBUSY)
+ printk("inia100: IRQ %d already in use. Configure another.\n", pHCB->HCS_Intr);
+ else {
+ printk("\ninia100: Unexpected error code on requesting IRQ %d.\n",


+ pHCB->HCS_Intr);
+ printk(" Contact author.\n");
+ }
+ }

+ inia100_panic("inia100: driver needs an IRQ.\n");


+ }
+#endif
+ }
+
+ tpnt->this_id = -1;
+ tpnt->can_queue = 1;

+ return 1;
+}
+
+/*****************************************************************************
+ Function name : inia100BuildSCB
+ Description :

+ Input : pHCB - Pointer to host adapter structure
+ Output : None.
+ Return : pSRB - Pointer to SCSI request block.
+*****************************************************************************/

+static void inia100BuildSCB(ORC_HCS * pHCB, ORC_SCB * pSCB, Scsi_Cmnd * SCpnt)


+{ /* Create corresponding SCB */
+ struct scatterlist *pSrbSG;

+ ORC_SG *pSG; /* Pointer to SG list */
+ int i;
+ U32 TotalLen;
+ ESCB *pEScb;
+
+ pEScb = pSCB->SCB_EScb;
+ pEScb->SCB_Srb = SCpnt;
+ pSG = NULL;
+
+ pSCB->SCB_Opcode = ORC_EXECSCSI;
+ pSCB->SCB_Flags = SCF_NO_DCHK; /* Clear done bit */


+ pSCB->SCB_Target = SCpnt->target;
+ pSCB->SCB_Lun = SCpnt->lun;

+ pSCB->SCB_Reserved0 = 0;
+ pSCB->SCB_Reserved1 = 0;


+ pSCB->SCB_SGLen = 0;
+

+ if ((pSCB->SCB_XferLen = (U32) SCpnt->request_bufflen)) {
+ pSG = (ORC_SG *) & pEScb->ESCB_SGList[0];
+ if (SCpnt->use_sg) {
+ TotalLen = 0;
+ pSCB->SCB_SGLen = (U32) (SCpnt->use_sg * 8);


+ pSrbSG = (struct scatterlist *) SCpnt->request_buffer;

+ for (i = 0; i < SCpnt->use_sg; i++, pSG++, pSrbSG++) {
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
+ pSG->SG_Ptr = (U32) (VIRT_TO_BUS(pSrbSG->address));
+#else
+ pSG->SG_Ptr = (U32) pSrbSG->address;
+#endif
+ pSG->SG_Len = (U32) pSrbSG->length;
+ TotalLen += (U32) pSrbSG->length;
+ }


+ } else { /* Non SG */

+ pSCB->SCB_SGLen = 0x8;
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
+ pSG->SG_Ptr = (U32) (VIRT_TO_BUS(SCpnt->request_buffer));
+#else
+ pSG->SG_PTR = (U32) SCpnt->request_buffer;
+#endif
+ pSG->SG_Len = (U32) SCpnt->request_bufflen;
+ }
+ }
+ pSCB->SCB_SGPAddr = (U32) pSCB->SCB_SensePAddr;


+ pSCB->SCB_HaStat = 0;
+ pSCB->SCB_TaStat = 0;

+ pSCB->SCB_Link = 0xFF;


+ pSCB->SCB_SenseLen = SENSE_SIZE;
+ pSCB->SCB_CDBLen = SCpnt->cmd_len;

+ if (pSCB->SCB_CDBLen >= IMAX_CDB) {
+ printk("max cdb length= %x\b", SCpnt->cmd_len);
+ pSCB->SCB_CDBLen = IMAX_CDB;
+ }


+ pSCB->SCB_Ident = SCpnt->lun | DISC_ALLOW;

+ if (SCpnt->device->tagged_supported) { /* Tag Support */
+ pSCB->SCB_TagMsg = SIMPLE_QUEUE_TAG; /* Do simple tag only */
+ } else {
+ pSCB->SCB_TagMsg = 0; /* No tag support */
+ }

+ memcpy(&pSCB->SCB_CDB[0], &SCpnt->cmnd, pSCB->SCB_CDBLen);


+ return;
+}
+
+/*****************************************************************************

+ Function name : inia100_queue
+ Description : Queue a command and setup interrupts for a free bus.


+ Input : pHCB - Pointer to host adapter structure
+ Output : None.
+ Return : pSRB - Pointer to SCSI request block.
+*****************************************************************************/

+int inia100_queue(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
+{
+ register ORC_SCB *pSCB;
+ ORC_HCS *pHCB; /* Point to Host adapter control block */


+
+ if (SCpnt->lun > 16) {

+ SCpnt->result = (DID_TIME_OUT << 16);
+ done(SCpnt); /* Notify system DONE */
+ return (0);
+ }

+ pHCB = (ORC_HCS *) SCpnt->host->base;


+ SCpnt->scsi_done = done;
+ /* Get free SCSI control block */

+ if ((pSCB = orc_alloc_scb(pHCB)) == NULL) {
+ inia100AppendSRBToQueue(pHCB, SCpnt); /* Buffer this request */
+ /* printk("inia100_entry: can't allocate SCB\n"); */
+ return (0);
+ }
+ inia100BuildSCB(pHCB, pSCB, SCpnt);
+ orc_exec_scb(pHCB, pSCB); /* Start execute SCB */
+


+ return (0);
+}
+

+/*****************************************************************************
+ Function name : inia100_command
+ Description : We only support command in interrupt-driven fashion


+ Input : pHCB - Pointer to host adapter structure
+ Output : None.
+ Return : pSRB - Pointer to SCSI request block.
+*****************************************************************************/

+int inia100_command(Scsi_Cmnd * SCpnt)
+{
+ printk("inia100: interrupt driven driver; use inia100_queue()\n");


+ return -1;
+}
+

+/*****************************************************************************
+ Function name : inia100_abort
+ Description : Abort a queued command.
+ (commands that are on the bus can't be aborted easily)


+ Input : pHCB - Pointer to host adapter structure
+ Output : None.
+ Return : pSRB - Pointer to SCSI request block.
+*****************************************************************************/

+int inia100_abort(Scsi_Cmnd * SCpnt)
+{
+ ORC_HCS *hcsp;
+
+ hcsp = (ORC_HCS *) SCpnt->host->base;
+ return orc_abort_srb(hcsp, (ULONG) SCpnt);
+}
+
+/*****************************************************************************
+ Function name : inia100_reset
+ Description : Reset registers, reset a hanging bus and
+ kill active and disconnected commands for target w/o soft reset


+ Input : pHCB - Pointer to host adapter structure
+ Output : None.
+ Return : pSRB - Pointer to SCSI request block.
+*****************************************************************************/

+int inia100_reset(Scsi_Cmnd * SCpnt, unsigned int reset_flags)


+{ /* I need Host Control Block Information */

+ ORC_HCS *pHCB;
+ pHCB = (ORC_HCS *) SCpnt->host->base;


+
+ if (reset_flags & (SCSI_RESET_SUGGEST_BUS_RESET | SCSI_RESET_SUGGEST_HOST_RESET))

+ return orc_reset_scsi_bus(pHCB);
+ else
+ return orc_device_reset(pHCB, (ULONG) SCpnt, SCpnt->target, reset_flags);
+
+}
+
+/*****************************************************************************
+ Function name : inia100SCBPost
+ Description : This is callback routine be called when orc finish one


+ SCSI command.
+ Input : pHCB - Pointer to host adapter control block.
+ pSCB - Pointer to SCSI control block.
+ Output : None.
+ Return : None.
+*****************************************************************************/

+void inia100SCBPost(BYTE * pHcb, BYTE * pScb)


+{
+ Scsi_Cmnd *pSRB; /* Pointer to SCSI request block */

+ ORC_HCS *pHCB;
+ ORC_SCB *pSCB;
+ ESCB *pEScb;
+
+ pHCB = (ORC_HCS *) pHcb;
+ pSCB = (ORC_SCB *) pScb;
+ pEScb = pSCB->SCB_EScb;
+ if ((pSRB = (Scsi_Cmnd *) pEScb->SCB_Srb) == 0) {
+ printk("inia100SCBPost: SRB pointer is empty\n");
+ orc_release_scb(pHCB, pSCB); /* Release SCB for current channel */
+ return;
+ }
+ pEScb->SCB_Srb = NULL;

+ case 0x16: /* Invalid CCB Operation Code-The first byte of the CCB was invalid. */
+
+ default:
+ printk("inia100: %x %x\n", pSCB->SCB_HaStat, pSCB->SCB_TaStat);


+ pSCB->SCB_HaStat = DID_ERROR; /* Couldn't find any better */
+ break;
+ }
+

+ if (pSCB->SCB_TaStat == 2) { /* Check condition */
+ memcpy((unsigned char *) &pSRB->sense_buffer[0],
+ (unsigned char *) &pEScb->ESCB_SGList[0], SENSE_SIZE);


+ }
+ pSRB->result = pSCB->SCB_TaStat | (pSCB->SCB_HaStat << 16);

+ pSRB->scsi_done(pSRB); /* Notify system DONE */
+
+ /* Find the next pending SRB */
+ if ((pSRB = inia100PopSRBFromQueue(pHCB)) != NULL) { /* Assume resend will success */
+ /* Reuse old SCB */
+ inia100BuildSCB(pHCB, pSCB, pSRB); /* Create corresponding SCB */
+ orc_exec_scb(pHCB, pSCB); /* Start execute SCB */
+ } else { /* No Pending SRB */
+ orc_release_scb(pHCB, pSCB); /* Release SCB for current channel */
+ }


+ return;
+}
+
+/*****************************************************************************

+ Function name : inia100_biosparam
+ Description : Return the "logical geometry"


+ Input : pHCB - Pointer to host adapter structure
+ Output : None.
+ Return : pSRB - Pointer to SCSI request block.
+*****************************************************************************/

+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
+int inia100_biosparam(Scsi_Disk * disk, kdev_t dev, int *info_array)
+#else
+int inia100_biosparam(Scsi_Disk * disk, int dev, int *info_array)
+#endif
+{
+ ORC_HCS *pHcb; /* Point to Host adapter control block */
+ ORC_TCS *pTcb;
+
+ pHcb = (ORC_HCS *) disk->device->host->base;


+ pTcb = &pHcb->HCS_Tcs[disk->device->id];
+
+ if (pTcb->TCS_DrvHead) {
+ info_array[0] = pTcb->TCS_DrvHead;
+ info_array[1] = pTcb->TCS_DrvSector;
+ info_array[2] = disk->capacity / pTcb->TCS_DrvHead / pTcb->TCS_DrvSector;
+ } else {
+ if (pTcb->TCS_DrvFlags & TCF_DRV_255_63) {
+ info_array[0] = 255;
+ info_array[1] = 63;
+ info_array[2] = disk->capacity / 255 / 63;
+ } else {
+ info_array[0] = 64;
+ info_array[1] = 32;
+ info_array[2] = disk->capacity >> 11;
+ }
+ }

+ return 0;
+}
+
+
+static void subIntr(ORC_HCS * pHCB, int irqno)


+{
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)

+ unsigned long flags;
+

+ spin_lock_irqsave(&io_request_lock, flags);
+#endif
+
+ if (pHCB->HCS_Intr != irqno) {
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+ spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
+ return;
+ }
+ orc_interrupt(pHCB);


+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)

+ spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
+}
+
+/*
+ * Interrupts handler (main routine of the driver)


+ */
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)

+static void inia100_intr0(int irqno, void *dev_id, struct pt_regs *regs)
+#else
+static void inia100_intr0(int irqno, struct pt_regs *regs)
+#endif
+{
+ subIntr(&orc_hcs[0], irqno);
+}
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
+static void inia100_intr1(int irqno, void *dev_id, struct pt_regs *regs)
+#else
+static void inia100_intr1(int irqno, struct pt_regs *regs)
+#endif
+{
+ subIntr(&orc_hcs[1], irqno);
+}
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
+static void inia100_intr2(int irqno, void *dev_id, struct pt_regs *regs)
+#else
+static void inia100_intr2(int irqno, struct pt_regs *regs)
+#endif
+{
+ subIntr(&orc_hcs[2], irqno);
+}
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
+static void inia100_intr3(int irqno, void *dev_id, struct pt_regs *regs)
+#else
+static void inia100_intr3(int irqno, struct pt_regs *regs)
+#endif
+{
+ subIntr(&orc_hcs[3], irqno);
+}
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
+static void inia100_intr4(int irqno, void *dev_id, struct pt_regs *regs)
+#else
+static void inia100_intr4(int irqno, struct pt_regs *regs)
+#endif
+{
+ subIntr(&orc_hcs[4], irqno);
+}
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
+static void inia100_intr5(int irqno, void *dev_id, struct pt_regs *regs)
+#else
+static void inia100_intr5(int irqno, struct pt_regs *regs)
+#endif
+{
+ subIntr(&orc_hcs[5], irqno);
+}
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
+static void inia100_intr6(int irqno, void *dev_id, struct pt_regs *regs)
+#else
+static void inia100_intr6(int irqno, struct pt_regs *regs)
+#endif
+{
+ subIntr(&orc_hcs[6], irqno);
+}
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
+static void inia100_intr7(int irqno, void *dev_id, struct pt_regs *regs)
+#else
+static void inia100_intr7(int irqno, struct pt_regs *regs)
+#endif
+{
+ subIntr(&orc_hcs[7], irqno);
+}
+
+/*
+ * Dump the current driver status and panic...
+ */
+static void inia100_panic(char *msg)
+{
+ printk("\ninia100_panic: %s\n", msg);
+ panic("inia100 panic");
+}
+
+/*#include "inia100scsi.c" */
diff -u --recursive --new-file v2.0.36/linux/drivers/scsi/inia100.h linux/drivers/scsi/inia100.h
--- v2.0.36/linux/drivers/scsi/inia100.h Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/inia100.h Sun Jun 13 10:21:02 1999
@@ -0,0 +1,503 @@
+/**************************************************************************
+ * Initio A100 device driver for Linux.


+ *
+ * Copyright (c) 1994-1998 Initio Corporation

+ **************************************************************************
+ *
+ * Module: inia100.h
+ * Description: INI-A100U2W LINUX device driver header
+ * Revision History:
+ * 06/18/98 HL, Initial production Version 1.02
+ * 12/19/98 bv, Use spinlocks for 2.1.95 and up
+ ****************************************************************************/
+
+#ifndef CVT_LINUX_VERSION
+#define CVT_LINUX_VERSION(V,P,S) (((V) * 65536) + ((P) * 256) + (S))
+#endif


+
+#ifndef LINUX_VERSION_CODE
+#include <linux/version.h>
+#endif
+

+#include "sd.h"
+
+extern int inia100_detect(Scsi_Host_Template *);
+extern int inia100_command(Scsi_Cmnd *);
+extern int inia100_queue(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
+extern int inia100_abort(Scsi_Cmnd *);
+extern int inia100_reset(Scsi_Cmnd *, unsigned int);
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1, 3, 0)
+extern int inia100_biosparam(Scsi_Disk *, kdev_t, int *); /*for linux v2.0 */
+extern struct proc_dir_entry proc_scsi_inia100;
+#else
+extern int inia100_biosparam(Disk *, int, int *); /*for linux v1.13 */
+#endif
+
+#define inia100_REVID "Initio INI-A100U2W SCSI device driver; Revision: 1.02a"
+
+#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(1, 3, 0)
+#define INIA100 { \
+ NULL, \
+ NULL, \
+ inia100_REVID, \
+ inia100_detect, \
+ NULL, \
+ NULL, \
+ inia100_command, \
+ inia100_queue, \
+ inia100_abort, \
+ inia100_reset, \
+ NULL, \
+ inia100_biosparam, \
+ 1, \
+7, \
+SG_ALL, \
+1, \
+0, \
+0, \
+ENABLE_CLUSTERING \
+}
+
+#else
+
+#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2, 1, 75)
+#define INIA100 { \
+ NULL, \
+ NULL, \
+ &proc_scsi_inia100, \
+ NULL, \
+ inia100_REVID, \
+ inia100_detect, \
+ NULL, \
+ NULL, \
+ inia100_command, \
+ inia100_queue, \
+ inia100_abort, \
+ inia100_reset, \
+ NULL, \
+ inia100_biosparam, \
+ 1, \
+ 7, \
+ 0, \
+ 1, \
+ 0, \
+ 0, \
+ ENABLE_CLUSTERING \
+}
+#else /* Version >= 2.1.75 */
+#define INIA100 { \
+ next: NULL, \
+ module: NULL, \
+ proc_dir: &proc_scsi_inia100, \
+ proc_info: NULL, \
+ name: inia100_REVID, \
+ detect: inia100_detect, \
+ release: NULL, \
+ info: NULL, \
+ command: inia100_command, \
+ queuecommand: inia100_queue, \
+ eh_strategy_handler: NULL, \
+ eh_abort_handler: NULL, \
+ eh_device_reset_handler: NULL, \
+ eh_bus_reset_handler: NULL, \
+ eh_host_reset_handler: NULL, \
+ abort: inia100_abort, \
+ reset: inia100_reset, \
+ slave_attach: NULL, \
+ bios_param: inia100_biosparam, \
+ can_queue: 1, \
+ this_id: 1, \
+ sg_tablesize: SG_ALL, \
+ cmd_per_lun: 1, \
+ present: 0, \
+ unchecked_isa_dma: 0, \
+ use_clustering: ENABLE_CLUSTERING, \
+ use_new_eh_code: 0 \
+}
+#endif
+#endif
+
+#define VIRT_TO_BUS(i) (unsigned int) virt_to_bus((void *)(i))
+#define ULONG unsigned long
+#define PVOID void *
+#define USHORT unsigned short
+#define UCHAR unsigned char
+#define BYTE unsigned char
+#define WORD unsigned short
+#define DWORD unsigned long
+#define UBYTE unsigned char
+#define UWORD unsigned short
+#define UDWORD unsigned long
+#ifdef ALPHA
+#define U32 unsigned int
+#else
+#define U32 unsigned long
+#endif
+
+#ifndef NULL
+#define NULL 0 /* zero */
+#endif
+#ifndef TRUE
+#define TRUE (1) /* boolean true */
+#endif
+#ifndef FALSE
+#define FALSE (0) /* boolean false */
+#endif
+#ifndef FAILURE
+#define FAILURE (-1)
+#endif
+#if 1
+#define ORC_MAXQUEUE 245
+#else
+#define ORC_MAXQUEUE 25
+#endif
+
+#define TOTAL_SG_ENTRY 32
+#define MAX_TARGETS 16
+#define IMAX_CDB 15
+#define SENSE_SIZE 14
+#define MAX_SUPPORTED_ADAPTERS 4
+#define SUCCESSFUL 0x00
+
+#define I920_DEVICE_ID 0x0002 /* Initio's inic-950 product ID */


+
+/************************************************************************/
+/* Scatter-Gather Element Structure */
+/************************************************************************/

+typedef struct ORC_SG_Struc {


+ U32 SG_Ptr; /* Data Pointer */
+ U32 SG_Len; /* Data Length */

+} ORC_SG;
+


+
+/* SCSI related definition */
+#define DISC_NOT_ALLOW 0x80 /* Disconnect is not allowed */
+#define DISC_ALLOW 0xC0 /* Disconnect is allowed */
+

+
+#define ORC_OFFSET_SCB 16
+#define ORC_MAX_SCBS 250
+#define MAX_CHANNELS 2
+#define MAX_ESCB_ELE 64
+#define TCF_DRV_255_63 0x0400
+
+/********************************************************/
+/* Orchid Configuration Register Set */
+/********************************************************/
+#define ORC_PVID 0x00 /* Vendor ID */
+#define ORC_VENDOR_ID 0x1101 /* Orchid vendor ID */
+#define ORC_PDID 0x02 /* Device ID */
+#define ORC_DEVICE_ID 0x1060 /* Orchid device ID */


SHAR_EOF
true || echo 'restore of patch-2.0.37 failed'
fi

echo 'End of part 27'
echo 'File patch-2.0.37 is continued in part 28'
echo 28 > _shar_seq_.tmp

Thomas...@ciw.uni-karlsruhe.de

unread,
Jun 16, 1999, 3:00:00 AM6/16/99
to
Archive-name: v2.0/patch-2.0.37/part33

#!/bin/sh
# this is part 33 of a 45 - part archive


# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.0.37 continued
if test ! -r _shar_seq_.tmp; then
echo 'Please unpack part 1 first!'
exit 1
fi
(read Scheck

if test "$Scheck" != 33; then


echo Please unpack part "$Scheck" next!
exit 1
else
exit 0
fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.0.37'
else
echo 'x - continuing with patch-2.0.37'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.0.37' &&

+ */
+ startp = cpu_to_scr(NCB_SCRIPTH_PHYS (np, sdata_in));
X
- /*
- ** choose the correct patch area.
- ** if savep points to one, choose the other.
- */
+ cp->phys.header.savep = startp;
+ cp->phys.header.goalp = startp + 24;
+ cp->phys.header.lastp = startp;
+ cp->phys.header.wgoalp = startp + 24;
+ cp->phys.header.wlastp = startp;
X
- newcmd = cp->patch;
- if (cp->phys.header.savep == cpu_to_scr(vtophys (newcmd))) newcmd+=4;


+ cp->host_status = HS_BUSY;
+ cp->scsi_status = S_ILLEGAL;

+ cp->auto_sense = s_status;
X
- /*
- ** fillin the commands
- */


+ cp->start.schedule.l_paddr =
+ cpu_to_scr(NCB_SCRIPT_PHYS (np, select));

X
- newcmd[0] = cpu_to_scr(((cmd & 0x0f) << 24) | rest);
- newcmd[1] = cpu_to_scr(oadr + olen - rest);
- newcmd[2] = cpu_to_scr(SCR_JUMP);
- newcmd[3] = cpu_to_scr(nxtdsp);
+ /*
+ ** Select without ATN for quirky devices.
+ */
+ if (tp->quirks & QUIRK_NOMSG)
+ cp->start.schedule.l_paddr =
+ cpu_to_scr(NCB_SCRIPTH_PHYS (np, select_no_atn));
X
- if (DEBUG_FLAGS & DEBUG_PHASE) {
- PRINT_ADDR(cp->cmd);
- printf ("newcmd[%d] %x %x %x %x.\n",
- (int) (newcmd - cp->patch),
- (unsigned)scr_to_cpu(newcmd[0]),
- (unsigned)scr_to_cpu(newcmd[1]),
- (unsigned)scr_to_cpu(newcmd[2]),
- (unsigned)scr_to_cpu(newcmd[3]));
+ ncr_put_start_queue(np, cp);
+


+ OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, start));

+ return;
X }
- /*
- ** fake the return address (to the patch).
- ** and restart script processor at dispatcher.
- */
- np->profile.num_break++;
- OUTL (nc_temp, vtophys (newcmd));
- if ((cmd & 7) == 0)
- OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, dispatch));
- else
- OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, checkatn));
+
+out:
+ OUTONB (nc_dcntl, (STD|NOCOM));
+ return;
X }
X
+


X /*==========================================================
X **
X **

@@ -7463,159 +7704,79 @@
X static int ncr_show_msg (u_char * msg)
X {
X u_char i;
- printf ("%x",*msg);
+ printk ("%x",*msg);
X if (*msg==M_EXTENDED) {
X for (i=1;i<8;i++) {
X if (i-1>msg[1]) break;
- printf ("-%x",msg[i]);
+ printk ("-%x",msg[i]);
X };
X return (i+1);
X } else if ((*msg & 0xf0) == 0x20) {
- printf ("-%x",msg[1]);
+ printk ("-%x",msg[1]);
X return (2);
X };
X return (1);
X }
X
+
X void ncr_int_sir (ncb_p np)
X {
X u_char scntl3;
X u_char chg, ofs, per, fak, wide;
X u_char num = INB (nc_dsps);
X ccb_p cp=0;
- u_long dsa;


- u_char target = INB (nc_ctest0) & 0x0f;

+ u_long dsa = INL (nc_dsa);


+ u_char target = INB (nc_sdid) & 0x0f;

X tcb_p tp = &np->target[target];
- int i;
- if (DEBUG_FLAGS & DEBUG_TINY) printf ("I#%d", num);
+
+ if (DEBUG_FLAGS & DEBUG_TINY) printk ("I#%d", num);
X
X switch (num) {
- case SIR_SENSE_RESTART:
- case SIR_STALL_RESTART:
- break;
- case SIR_STALL_QUEUE: /* Ignore, just restart the script */
+ case SIR_RESEL_NO_MSG_IN:
+ case SIR_RESEL_NO_IDENTIFY:
+ /*
+ ** If devices reselecting without sending an IDENTIFY
+ ** message still exist, this should help.
+ ** We just assume lun=0, 1 CCB, no tag.
+ */
+ if (tp->lp[0]) {
+ OUTL (nc_dsp, scr_to_cpu(tp->lp[0]->jump_ccb[0]));
+ return;
+ }
+ case SIR_RESEL_BAD_TARGET: /* Will send a TARGET RESET message */
+ case SIR_RESEL_BAD_LUN: /* Will send a TARGET RESET message */
+ case SIR_RESEL_BAD_I_T_L_Q: /* Will send an ABORT TAG message */
+ case SIR_RESEL_BAD_I_T_L: /* Will send an ABORT message */
+ printk ("%s:%d: SIR %d, "
+ "incorrect nexus identification on reselection\n",
+ ncr_name (np), target, num);
X goto out;
-
+ case SIR_DONE_OVERFLOW:
+ printk ("%s:%d: SIR %d, "
+ "CCB done queue overflow\n",
+ ncr_name (np), target, num);
+ goto out;
+ case SIR_BAD_STATUS:


+ cp = np->header.cp;

+ if (!cp || CCB_PHYS (cp, phys) != dsa)
+ goto out;
+ ncr_sir_to_redo(np, num, cp);
+ return;
X default:
X /*
X ** lookup the ccb


X */
- dsa = INL (nc_dsa);

X cp = np->ccb;
X while (cp && (CCB_PHYS (cp, phys) != dsa))
X cp = cp->link_ccb;
X
- assert (cp);
- if (!cp)
- goto out;
- assert (cp == np->header.cp);


- if (cp != np->header.cp)

+ assert (cp && cp == np->header.cp);
+
+ if (!cp || cp != np->header.cp)
X goto out;
X }
X
X switch (num) {
- u_long endp;
- case SIR_DATA_IO_IS_OUT:
- case SIR_DATA_IO_IS_IN:
-/*
-** We did not guess the direction of transfer. We have to wait for
-** actual data direction driven by the target before setting
-** pointers. We must patch the global header too.
-*/
- if (num == SIR_DATA_IO_IS_OUT) {
- endp = NCB_SCRIPTH_PHYS (np, data_out) + MAX_SCATTER*16;
- cp->phys.header.goalp = cpu_to_scr(endp + 8);
- cp->phys.header.savep =
- cpu_to_scr(endp - cp->segments*16);
- } else {
- endp = NCB_SCRIPT_PHYS (np, data_in) + MAX_SCATTER*16;
- cp->phys.header.goalp = cpu_to_scr(endp + 8);
- cp->phys.header.savep =
- cpu_to_scr(endp - cp->segments*16);
- }
-
- cp->phys.header.lastp = cp->phys.header.savep;
- np->header.savep = cp->phys.header.savep;
- np->header.goalp = cp->phys.header.goalp;
- np->header.lastp = cp->phys.header.lastp;
-
- OUTL (nc_temp, scr_to_cpu(np->header.savep));
- OUTL (nc_dsp, scr_to_cpu(np->header.savep));
- return;
- /* break; */
-
-/*--------------------------------------------------------------------
-**
-** Processing of interrupted getcc selects
-**
-**--------------------------------------------------------------------
-*/
-
- case SIR_SENSE_RESTART:
- /*------------------------------------------
- ** Script processor is idle.
- ** Look for interrupted "check cond"
- **------------------------------------------
- */
-
- if (DEBUG_FLAGS & DEBUG_RESTART)
- printf ("%s: int#%d",ncr_name (np),num);
- cp = (ccb_p) 0;
- for (i=0; i<MAX_TARGET; i++) {
- if (DEBUG_FLAGS & DEBUG_RESTART) printf (" t%d", i);
- tp = &np->target[i];
- if (DEBUG_FLAGS & DEBUG_RESTART) printf ("+");
- cp = tp->hold_cp;
- if (!cp) continue;
- if (DEBUG_FLAGS & DEBUG_RESTART) printf ("+");
- if ((cp->host_status==HS_BUSY) &&
- (cp->scsi_status==S_CHECK_COND))
- break;
- if (DEBUG_FLAGS & DEBUG_RESTART) printf ("- (remove)");
- tp->hold_cp = cp = (ccb_p) 0;
- };
-
- if (cp) {
- if (DEBUG_FLAGS & DEBUG_RESTART)
- printf ("+ restart job ..\n");
- OUTL (nc_dsa, CCB_PHYS (cp, phys));
- OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, getcc));
- return;
- };
-
- /*
- ** no job, resume normal processing
- */
- if (DEBUG_FLAGS & DEBUG_RESTART) printf (" -- remove trap\n");
- np->script->start0[0] = cpu_to_scr(SCR_INT ^ IFFALSE (0));
- break;
-
- case SIR_SENSE_FAILED:
- /*-------------------------------------------
- ** While trying to select for
- ** getting the condition code,
- ** a target reselected us.
- **-------------------------------------------
- */
- if (DEBUG_FLAGS & DEBUG_RESTART) {
- PRINT_ADDR(cp->cmd);
- printf ("in getcc reselect by t%d.\n",
- (int)INB(nc_ssid) & 0x0f);
- }
-
- /*
- ** Mark this job
- */
- cp->host_status = HS_BUSY;
- cp->scsi_status = S_CHECK_COND;
- np->target[cp->cmd->target].hold_cp = cp;
-
- /*
- ** And patch code to restart it.
- */
- np->script->start0[0] = cpu_to_scr(SCR_INT);
- break;
-
X /*-----------------------------------------------------------------------------
X **
X ** Was Sie schon immer ueber transfermode negotiation wissen wollten ...
@@ -7699,7 +7860,7 @@
X
X if (DEBUG_FLAGS & DEBUG_NEGO) {
X PRINT_ADDR(cp->cmd);
- printf ("negotiation failed sir=%x status=%x.\n",
+ printk ("negotiation failed sir=%x status=%x.\n",
X num, cp->nego_status);
X };
X
@@ -7722,7 +7883,8 @@
X np->msgout[0] = M_NOOP;
X cp->nego_status = 0;
X OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, dispatch));
- break;
+ return;
+/* break; */
X
X case SIR_NEGO_SYNC:
X /*
@@ -7731,9 +7893,9 @@
X
X if (DEBUG_FLAGS & DEBUG_NEGO) {
X PRINT_ADDR(cp->cmd);
- printf ("sync msgin: ");
+ printk ("sync msgin: ");
X (void) ncr_show_msg (np->msgin);


- printf (".\n");

+ printk (".\n");
X };
X

X /*
@@ -7751,7 +7913,7 @@
X */
X
X if (ofs)
- tp->inqdata[7] |= INQ7_SYNC;
+ tp->inq_byte7 |= INQ7_SYNC;
X
X /*
X ** check values against driver limits.
@@ -7785,7 +7947,7 @@
X
X if (DEBUG_FLAGS & DEBUG_NEGO) {
X PRINT_ADDR(cp->cmd);
- printf ("sync: per=%d scntl3=0x%x ofs=%d fak=%d chg=%d.\n",
+ printk ("sync: per=%d scntl3=0x%x ofs=%d fak=%d chg=%d.\n",
X per, scntl3, ofs, fak, chg);
X }
X
@@ -7819,20 +7981,6 @@
X };
X
X /*
- ** It was a request.
- ** Check against the table of target capabilities.
- ** If target not capable force M_REJECT and asynchronous.
- */
- if (np->unit < SCSI_NCR_MAX_HOST) {
- tp->inqdata[7] &=
- (target_capabilities[np->unit].and_map[target]);
- if (!(tp->inqdata[7] & INQ7_SYNC)) {
- ofs = 0;
- fak = 7;


- }
- }
-
- /*

X ** It was a request. Set value and
X ** prepare an answer message
X */
@@ -7849,9 +7997,9 @@
X
X if (DEBUG_FLAGS & DEBUG_NEGO) {
X PRINT_ADDR(cp->cmd);
- printf ("sync msgout: ");
+ printk ("sync msgout: ");
X (void) ncr_show_msg (np->msgout);


- printf (".\n");

+ printk (".\n");
X }
X

X if (!ofs) {
@@ -7868,9 +8016,9 @@
X */
X if (DEBUG_FLAGS & DEBUG_NEGO) {
X PRINT_ADDR(cp->cmd);
- printf ("wide msgin: ");
+ printk ("wide msgin: ");
X (void) ncr_show_msg (np->msgin);


- printf (".\n");

+ printk (".\n");
X };
X

X /*
@@ -7886,7 +8034,7 @@
X */
X
X if (wide)
- tp->inqdata[7] |= INQ7_WIDE16;
+ tp->inq_byte7 |= INQ7_WIDE16;
X
X /*
X ** check values against driver limits.
@@ -7897,7 +8045,7 @@
X
X if (DEBUG_FLAGS & DEBUG_NEGO) {
X PRINT_ADDR(cp->cmd);
- printf ("wide: wide=%d chg=%d.\n", wide, chg);
+ printk ("wide: wide=%d chg=%d.\n", wide, chg);
X }
X
X if (INB (HS_PRT) == HS_NEGOTIATE) {
@@ -7947,9 +8095,9 @@
X
X if (DEBUG_FLAGS & DEBUG_NEGO) {
X PRINT_ADDR(cp->cmd);
- printf ("wide msgout: ");
+ printk ("wide msgout: ");
X (void) ncr_show_msg (np->msgin);


- printf (".\n");

+ printk (".\n");
X }

X break;
X
@@ -7969,7 +8117,7 @@
X */
X
X PRINT_ADDR(cp->cmd);
- printf ("M_REJECT received (%x:%x).\n",
+ printk ("M_REJECT received (%x:%x).\n",
X (unsigned)scr_to_cpu(np->lastmsg), np->msgout[0]);
X break;
X
@@ -7982,9 +8130,9 @@
X */
X
X PRINT_ADDR(cp->cmd);
- printf ("M_REJECT sent for ");
+ printk ("M_REJECT sent for ");
X (void) ncr_show_msg (np->msgin);


- printf (".\n");

+ printk (".\n");
X break;
X
X /*--------------------------------------------------------------------
@@ -8004,9 +8152,9 @@
X */
X
X PRINT_ADDR(cp->cmd);
- printf ("M_IGN_RESIDUE received, but not yet implemented.\n");
+ printk ("M_IGN_RESIDUE received, but not yet implemented.\n");
X break;
-
+#if 0
X case SIR_MISSING_SAVE:
X /*-----------------------------------------------
X **
@@ -8017,92 +8165,13 @@
X */
X
X PRINT_ADDR(cp->cmd);
- printf ("M_DISCONNECT received, but datapointer not saved: "
+ printk ("M_DISCONNECT received, but datapointer not saved: "
X "data=%x save=%x goal=%x.\n",
X (unsigned) INL (nc_temp),
X (unsigned) scr_to_cpu(np->header.savep),
X (unsigned) scr_to_cpu(np->header.goalp));
X break;
-
-#if 0 /* This stuff does not work */
-/*--------------------------------------------------------------------
-**
-** Processing of a "S_QUEUE_FULL" status.
-**
-** The current command has been rejected,
-** because there are too many in the command queue.
-** We have started too many commands for that target.
-**
-** If possible, reinsert at head of queue.
-** Stall queue until there are no disconnected jobs
-** (ncr is REALLY idle). Then restart processing.
-**
-** We should restart the current job after the controller
-** has become idle. But this is not yet implemented.
-**
-**--------------------------------------------------------------------
-*/
- case SIR_STALL_QUEUE:
- /*-----------------------------------------------
- **
- ** Stall the start queue.
- **
- **-----------------------------------------------
- */
- PRINT_ADDR(cp->cmd);
- printf ("queue full.\n");
-
- np->script->start1[0] = cpu_to_scr(SCR_INT);
-
- /*
- ** Try to disable tagged transfers.
- */
- ncr_setmaxtags (np, &np->target[target], 0);
-
- /*
- ** @QUEUE@
- **
- ** Should update the launch field of the
- ** current job to be able to restart it.
- ** Then prepend it to the start queue.
- */


-
- /* fall through */
-

- case SIR_STALL_RESTART:
- /*-----------------------------------------------
- **
- ** Enable selecting again,
- ** if NO disconnected jobs.
- **
- **-----------------------------------------------
- */
- /*
- ** Look for a disconnected job.
- */


- cp = np->ccb;

- while (cp && cp->host_status != HS_DISCONNECT)


- cp = cp->link_ccb;

-
- /*
- ** if there is one, ...
- */
- if (cp) {
- /*
- ** wait for reselection
- */
- OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, reselect));
- return;
- };
-
- /*
- ** else remove the interrupt.
- */
-
- printf ("%s: queue empty.\n", ncr_name (np));
- np->script->start1[0] = cpu_to_scr(SCR_INT ^ IFFALSE (0));
- break;
-#endif /* This stuff does not work */
+#endif
X };
X
X out:
@@ -8118,48 +8187,71 @@


X **==========================================================
X */
X

-static ccb_p ncr_get_ccb
- (ncb_p np, u_long target, u_long lun)
+static ccb_p ncr_get_ccb (ncb_p np, u_char tn, u_char ln)
X {
- lcb_p lp;


+ tcb_p tp = &np->target[tn];
+ lcb_p lp = tp->lp[ln];

+ u_char tag = NO_TAG;
X ccb_p cp = (ccb_p) 0;
X
X /*
X ** Lun structure available ?
X */
+ if (lp) {
+ XPT_QUEHEAD *qp;
+ /*
+ ** Keep from using more tags than we can handle.
+ */
+ if (lp->usetags && lp->busyccbs >= lp->maxnxs)
+ return (ccb_p) 0;
X
- lp = np->target[target].lp[lun];
-
- if (lp && lp->opennings && (!lp->active || lp->active < lp->reqlink)) {
-
- cp = lp->next_ccb;
+ /*
+ ** Allocate a new CCB if needed.
+ */
+ if (xpt_que_empty(&lp->free_ccbq))
+ ncr_alloc_ccb(np, tn, ln);
X
X /*
+ ** Tune tag mode if asked by user.
+ */
+ if (lp->queuedepth != lp->numtags) {
+ ncr_setup_tags(np, tn, ln);
+ }
+
+ /*
X ** Look for free CCB
X */
-
- while (cp && cp->magic) cp = cp->next_ccb;
+ qp = xpt_remque_head(&lp->free_ccbq);
+ if (qp) {
+ cp = xpt_que_entry(qp, struct ccb, link_ccbq);
+ if (cp->magic) {
+ PRINT_LUN(np, tn, ln);
+ printk ("ccb free list corrupted (@%p)\n", cp);


+ cp = 0;
+ }

+ else {
+ xpt_insque_tail(qp, &lp->wait_ccbq);
+ ++lp->busyccbs;


+ }
+ }
X
X /*

- ** Increment active commands and decrement credit.
+ ** If a CCB is available,
+ ** Get a tag for this nexus if required.
X */
-
X if (cp) {
- ++lp->active;
- --lp->opennings;
+ if (lp->usetags)
+ tag = lp->cb_tags[lp->ia_tag];
X }
+ else if (lp->actccbs > 0)
+ return (ccb_p) 0;
X }
X
X /*
X ** if nothing available, take the default.
- ** DANGEROUS, because this ccb is not suitable for
- ** reselection.
- ** If lp->actccbs > 0 wait for a suitable ccb to be free.
X */
- if ((!cp) && lp && lp->actccbs > 0)
- return ((ccb_p) 0);
-
- if (!cp) cp = np->ccb;
+ if (!cp)


+ cp = np->ccb;

X
X /*
X ** Wait until available.
@@ -8176,7 +8268,32 @@
X return ((ccb_p) 0);
X
X cp->magic = 1;
- return (cp);
+
+ /*
+ ** Move to next available tag if tag used.


+ */
+ if (lp) {

+ if (tag != NO_TAG) {
+ ++lp->ia_tag;
+ if (lp->ia_tag == SCSI_NCR_MAX_TAGS)
+ lp->ia_tag = 0;
+ lp->tags_umap |= (((tagmap_t) 1) << tag);


+ }
+ }
+
+ /*

+ ** Remember all informations needed to free this CCB.
+ */
+ cp->tag = tag;
+ cp->target = tn;
+ cp->lun = ln;
+
+ if (DEBUG_FLAGS & DEBUG_TAGS) {
+ PRINT_LUN(np, tn, ln);
+ printk ("ccb @%p using tag %d.\n", cp, tag);
+ }
+
+ return cp;
X }
X
X /*==========================================================
@@ -8188,252 +8305,417 @@


X **==========================================================
X */
X

-void ncr_free_ccb (ncb_p np, ccb_p cp, u_long target, u_long lun)
+static void ncr_free_ccb (ncb_p np, ccb_p cp)
X {
- lcb_p lp;


+ tcb_p tp = &np->target[cp->target];
+ lcb_p lp = tp->lp[cp->lun];

+
+ if (DEBUG_FLAGS & DEBUG_TAGS) {
+ PRINT_LUN(np, cp->target, cp->lun);
+ printk ("ccb @%p freeing tag %d.\n", cp, cp->tag);
+ }
X
X /*
- ** sanity
+ ** If lun control block available,
+ ** decrement active commands and increment credit,
+ ** free the tag if any and remove the JUMP for reselect.
X */
-
- assert (cp != NULL);
+ if (lp) {
+ if (cp->tag != NO_TAG) {
+ lp->cb_tags[lp->if_tag++] = cp->tag;
+ if (lp->if_tag == SCSI_NCR_MAX_TAGS)
+ lp->if_tag = 0;
+ lp->tags_umap &= ~(((tagmap_t) 1) << cp->tag);
+ lp->tags_smap &= lp->tags_umap;
+ lp->jump_ccb[cp->tag] =
+ cpu_to_scr(NCB_SCRIPTH_PHYS(np, bad_i_t_l_q));
+ } else {
+ lp->jump_ccb[0] =
+ cpu_to_scr(NCB_SCRIPTH_PHYS(np, bad_i_t_l));


+ }
+ }
X
X /*

- ** Decrement active commands and increment credit.
+ ** Make this CCB available.
X */
X
- lp = np->target[target].lp[lun];
X if (lp) {
- --lp->active;
- ++lp->opennings;
+ if (cp != np->ccb) {
+ xpt_remque(&cp->link_ccbq);
+ xpt_insque_head(&cp->link_ccbq, &lp->free_ccbq);
+ }
+ --lp->busyccbs;


+ if (cp->queued) {
+ --lp->queuedccbs;
+ }

X }
-
X cp -> host_status = HS_IDLE;
X cp -> magic = 0;


+ if (cp->queued) {
+ --np->queuedccbs;
+ cp->queued = 0;
+ }
+

X #if 0
X if (cp == np->ccb)
X wakeup ((caddr_t) cp);
X #endif
X }
X
-/*==========================================================
-**
-**
-** Allocation of resources for Targets/Luns/Tags.
-**
-**
-**==========================================================
-*/
X
-static void ncr_alloc_ccb (ncb_p np, u_long target, u_long lun)
+#define ncr_reg_bus_addr(r) \
+ (bus_dvma_to_mem(np->paddr) + offsetof (struct ncr_reg, r))
+
+/*------------------------------------------------------------------------
+** Initialize the fixed part of a CCB structure.
+**------------------------------------------------------------------------
+**------------------------------------------------------------------------
+*/
+static void ncr_init_ccb(ncb_p np, ccb_p cp)
X {
- tcb_p tp;
- lcb_p lp;
- ccb_p cp;
+ ncrcmd copy_4 = np->features & FE_PFEN ? SCR_COPY(4) : SCR_COPY_F(4);
X
- assert (np != NULL);
+ /*
+ ** Remember virtual and bus address of this ccb.
+ */
+ cp->p_ccb = vtophys(cp);
+ cp->phys.header.cp = cp;
X
- if (target>=MAX_TARGET) return;
- if (lun >=MAX_LUN ) return;
+ /*
+ ** This allows xpt_remque to work for the default ccb.
+ */
+ xpt_que_init(&cp->link_ccbq);
X
- tp=&np->target[target];
+ /*
+ ** Initialyze the start and restart launch script.
+ **
+ ** COPY(4) @(...p_phys), @(dsa)
+ ** JUMP @(sched_point)
+ */
+ cp->start.setup_dsa[0] = cpu_to_scr(copy_4);
+ cp->start.setup_dsa[1] = cpu_to_scr(vtophys(&cp->start.p_phys));
+ cp->start.setup_dsa[2] = cpu_to_scr(ncr_reg_bus_addr(nc_dsa));
+ cp->start.schedule.l_cmd = cpu_to_scr(SCR_JUMP);
+ cp->start.p_phys = cpu_to_scr(vtophys(&cp->phys));
X
- if (!tp->jump_tcb.l_cmd) {
- /*
- ** initialize it.
- */
- tp->jump_tcb.l_cmd =
- cpu_to_scr((SCR_JUMP^IFFALSE (DATA (0x80 + target))));
- tp->jump_tcb.l_paddr = np->jump_tcb.l_paddr;
+ bcopy(&cp->start, &cp->restart, sizeof(cp->restart));
X
- tp->getscr[0] = (np->features & FE_PFEN) ?
- cpu_to_scr(SCR_COPY(1)):cpu_to_scr(SCR_COPY_F(1));
- tp->getscr[1] = cpu_to_scr(vtophys (&tp->sval));
- tp->getscr[2] =
- cpu_to_scr(np->paddr + offsetof (struct ncr_reg, nc_sxfer));
+ cp->start.schedule.l_paddr = cpu_to_scr(NCB_SCRIPT_PHYS (np, idle));
+ cp->restart.schedule.l_paddr = cpu_to_scr(NCB_SCRIPTH_PHYS (np, abort));
+}
X
- tp->getscr[3] = (np->features & FE_PFEN) ?
- cpu_to_scr(SCR_COPY(1)):cpu_to_scr(SCR_COPY_F(1));
- tp->getscr[4] = cpu_to_scr(vtophys (&tp->wval));
- tp->getscr[5] =
- cpu_to_scr(np->paddr + offsetof (struct ncr_reg, nc_scntl3));
X
- assert (( (offsetof(struct ncr_reg, nc_sxfer) ^
- offsetof(struct tcb , sval )) &3) == 0);
- assert (( (offsetof(struct ncr_reg, nc_scntl3) ^
- offsetof(struct tcb , wval )) &3) == 0);
+/*------------------------------------------------------------------------
+** Allocate a CCB and initialize its fixed part.
+**------------------------------------------------------------------------
+**------------------------------------------------------------------------
+*/
+static void ncr_alloc_ccb(ncb_p np, u_char tn, u_char ln)
+{


+ tcb_p tp = &np->target[tn];
+ lcb_p lp = tp->lp[ln];

+ ccb_p cp = 0;
X
- tp->call_lun.l_cmd = cpu_to_scr(SCR_CALL);
- tp->call_lun.l_paddr =
- cpu_to_scr(NCB_SCRIPT_PHYS (np, resel_lun));
+ /*
+ ** Allocate memory for this CCB.
+ */
+ cp = m_alloc(sizeof(struct ccb), 5);
+ if (!cp)
+ return;
X
- tp->jump_lcb.l_cmd = cpu_to_scr(SCR_JUMP);
- tp->jump_lcb.l_paddr = cpu_to_scr(NCB_SCRIPTH_PHYS (np, abort));
- np->jump_tcb.l_paddr = cpu_to_scr(vtophys (&tp->jump_tcb));
+ if (DEBUG_FLAGS & DEBUG_ALLOC) {
+ PRINT_LUN(np, tn, ln);
+ printk ("new ccb @%p.\n", cp);
X }
X
X /*
- ** Logic unit control block
+ ** Count it and initialyze it.
X */
- lp = tp->lp[lun];
- if (!lp) {
- /*
- ** Allocate a lcb
- */
- lp = (lcb_p) m_alloc (sizeof (struct lcb), LCB_ALIGN_SHIFT);
- if (!lp) return;
+ lp->actccbs++;
+ np->actccbs++;
+ bzero (cp, sizeof (*cp));
+ ncr_init_ccb(np, cp);
X
- if (DEBUG_FLAGS & DEBUG_ALLOC) {
- PRINT_LUN(np, target, lun);
- printf ("new lcb @%p.\n", lp);
- }
+ /*
+ ** Chain into wakeup list and free ccb queue and take it
+ ** into account for tagged commands.
+ */
+ cp->link_ccb = np->ccb->link_ccb;
+ np->ccb->link_ccb = cp;
X
- /*
- ** Initialize it
- */
- bzero (lp, sizeof (*lp));
- lp->jump_lcb.l_cmd =
- cpu_to_scr(SCR_JUMP ^ IFFALSE (DATA (lun)));
- lp->jump_lcb.l_paddr = tp->jump_lcb.l_paddr;
+ xpt_insque_head(&cp->link_ccbq, &lp->free_ccbq);
+ ncr_setup_tags (np, tn, ln);


+}
+
+/*==========================================================
+**
+**

+** Allocation of resources for Targets/Luns/Tags.
+**
+**
+**==========================================================
+*/
X
- lp->call_tag.l_cmd = cpu_to_scr(SCR_CALL);
- lp->call_tag.l_paddr =
- cpu_to_scr(NCB_SCRIPT_PHYS (np, resel_tag));
X
- lp->jump_ccb.l_cmd = cpu_to_scr(SCR_JUMP);
- lp->jump_ccb.l_paddr =
- cpu_to_scr(NCB_SCRIPTH_PHYS (np, aborttag));
+/*------------------------------------------------------------------------
+** Target control block initialisation.
+**------------------------------------------------------------------------
+** This data structure is fully initialized after a SCSI command
+** has been successfully completed for this target.
+** It contains a SCRIPT that is called on target reselection.
+**------------------------------------------------------------------------
+*/
+static void ncr_init_tcb (ncb_p np, u_char tn)
+{


+ tcb_p tp = &np->target[tn];

+ ncrcmd copy_1 = np->features & FE_PFEN ? SCR_COPY(1) : SCR_COPY_F(1);
+ int th = tn & 3;
+ int i;
X
- lp->actlink = 1;
+ /*
+ ** Jump to next tcb if SFBR does not match this target.


+ ** JUMP IF (SFBR != #target#), @(next tcb)

+ */
+ tp->jump_tcb.l_cmd =
+ cpu_to_scr((SCR_JUMP ^ IFFALSE (DATA (0x80 + tn))));
+ tp->jump_tcb.l_paddr = np->jump_tcb[th].l_paddr;
X
- lp->active = 1;
+ /*
+ ** Load the synchronous transfer register.
+ ** COPY @(tp->sval), @(sxfer)
+ */
+ tp->getscr[0] = cpu_to_scr(copy_1);
+ tp->getscr[1] = cpu_to_scr(vtophys (&tp->sval));
+ tp->getscr[2] = cpu_to_scr(ncr_reg_bus_addr(nc_sxfer));
+
+ /*
+ ** Load the timing register.
+ ** COPY @(tp->wval), @(scntl3)
+ */
+ tp->getscr[3] = cpu_to_scr(copy_1);
+ tp->getscr[4] = cpu_to_scr(vtophys (&tp->wval));
+ tp->getscr[5] = cpu_to_scr(ncr_reg_bus_addr(nc_scntl3));
X
- /*
- ** Chain into LUN list
- */
- tp->jump_lcb.l_paddr = cpu_to_scr(vtophys (&lp->jump_lcb));
- tp->lp[lun] = lp;
+ /*
+ ** Get the IDENTIFY message and the lun.
+ ** CALL @script(resel_lun)
+ */
+ tp->call_lun.l_cmd = cpu_to_scr(SCR_CALL);
+ tp->call_lun.l_paddr = cpu_to_scr(NCB_SCRIPT_PHYS (np, resel_lun));
X

- ncr_setmaxtags (np, tp, driver_setup.default_tags);

+ /*
+ ** Look for the lun control block of this nexus.


+ ** For i = 0 to 3

+ ** JUMP ^ IFTRUE (MASK (i, 3)), @(next_lcb)
+ */
+ for (i = 0 ; i < 4 ; i++) {
+ tp->jump_lcb[i].l_cmd =
+ cpu_to_scr((SCR_JUMP ^ IFTRUE (MASK (i, 3))));
+ tp->jump_lcb[i].l_paddr =
+ cpu_to_scr(NCB_SCRIPTH_PHYS (np, bad_identify));
X }
X
X /*
- ** Allocate ccbs up to lp->reqccbs.
+ ** Link this target control block to the JUMP chain.
X */
+ np->jump_tcb[th].l_paddr = cpu_to_scr(vtophys (&tp->jump_tcb));
X
X /*
- ** Limit possible number of ccbs.
- **
- ** If tagged command queueing is enabled,
- ** can use more than one ccb.
+ ** These assert's should be moved at driver initialisations.
X */
- if (np->actccbs >= MAX_START-2) return;
- if (lp->actccbs && (lp->actccbs >= lp->reqccbs))
- return;
+ assert (( (offsetof(struct ncr_reg, nc_sxfer) ^
+ offsetof(struct tcb , sval )) &3) == 0);
+ assert (( (offsetof(struct ncr_reg, nc_scntl3) ^
+ offsetof(struct tcb , wval )) &3) == 0);
+}
+
+
+/*------------------------------------------------------------------------
+** Lun control block allocation and initialization.
+**------------------------------------------------------------------------
+** This data structure is allocated and initialized after a SCSI
+** command has been successfully completed for this target/lun.
+**------------------------------------------------------------------------
+*/
+static lcb_p ncr_alloc_lcb (ncb_p np, u_char tn, u_char ln)
+{


+ tcb_p tp = &np->target[tn];
+ lcb_p lp = tp->lp[ln];

+ ncrcmd copy_4 = np->features & FE_PFEN ? SCR_COPY(4) : SCR_COPY_F(4);
+ int lh = ln & 3;
X
X /*
- ** Allocate a ccb
+ ** Already done, return.
X */
- cp = (ccb_p) m_alloc (sizeof (struct ccb), CCB_ALIGN_SHIFT);
- if (!cp)
- return;
+ if (lp)
+ return lp;
+
+ /*
+ ** Allocate the lcb.
+ */
+ lp = m_alloc(sizeof(struct lcb), 3);
+ if (!lp)
+ goto fail;
+ bzero(lp, sizeof(*lp));
+ tp->lp[ln] = lp;
X
X if (DEBUG_FLAGS & DEBUG_ALLOC) {
- PRINT_LUN(np, target, lun);
- printf ("new ccb @%p.\n", cp);
+ PRINT_LUN(np, tn, ln);
+ printk ("new lcb @%p.\n", lp);
X }
X
X /*
- ** Count it
+ ** Initialize the target control block if not yet.
X */
- lp->actccbs++;
- np->actccbs++;
+ if (!tp->jump_tcb.l_cmd)
+ ncr_init_tcb(np, tn);
X
X /*
- ** Initialize it
+ ** Initialize the CCB queue headers.
X */
- bzero (cp, sizeof (*cp));
+ xpt_que_init(&lp->free_ccbq);
+ xpt_que_init(&lp->busy_ccbq);
+ xpt_que_init(&lp->wait_ccbq);
+ xpt_que_init(&lp->skip_ccbq);
X
X /*
- ** Fill in physical addresses
+ ** Set max CCBs to 1 and use the default 1 entry
+ ** jump table by default.
X */
-
- cp->p_ccb = vtophys (cp);
+ lp->maxnxs = 1;
+ lp->jump_ccb = &lp->jump_ccb_0;
+ lp->p_jump_ccb = cpu_to_scr(vtophys(lp->jump_ccb));
X
X /*
- ** Chain into reselect list
+ ** Initilialyze the reselect script:
+ **
+ ** Jump to next lcb if SFBR does not match this lun.
+ ** Load TEMP with the CCB direct jump table bus address.
+ ** Get the SIMPLE TAG message and the tag.
+ **
+ ** JUMP IF (SFBR != #lun#), @(next lcb)
+ ** COPY @(lp->p_jump_ccb), @(temp)
+ ** JUMP @script(resel_notag)
X */


- cp->jump_ccb.l_cmd = cpu_to_scr(SCR_JUMP);

- cp->jump_ccb.l_paddr = lp->jump_ccb.l_paddr;
- lp->jump_ccb.l_paddr = cpu_to_scr(CCB_PHYS (cp, jump_ccb));
- cp->call_tmp.l_cmd = cpu_to_scr(SCR_CALL);
- cp->call_tmp.l_paddr = cpu_to_scr(NCB_SCRIPT_PHYS (np, resel_tmp));
+ lp->jump_lcb.l_cmd =
+ cpu_to_scr((SCR_JUMP ^ IFFALSE (MASK (0x80+ln, 0xff))));
+ lp->jump_lcb.l_paddr = tp->jump_lcb[lh].l_paddr;
+
+ lp->load_jump_ccb[0] = cpu_to_scr(copy_4);
+ lp->load_jump_ccb[1] = cpu_to_scr(vtophys (&lp->p_jump_ccb));
+ lp->load_jump_ccb[2] = cpu_to_scr(ncr_reg_bus_addr(nc_temp));
+
+ lp->jump_tag.l_cmd = cpu_to_scr(SCR_JUMP);
+ lp->jump_tag.l_paddr = cpu_to_scr(NCB_SCRIPT_PHYS (np, resel_notag));
X
X /*
- ** Chain into wakeup list
+ ** Link this lun control block to the JUMP chain.
X */
- cp->link_ccb = np->ccb->link_ccb;
- np->ccb->link_ccb = cp;
+ tp->jump_lcb[lh].l_paddr = cpu_to_scr(vtophys (&lp->jump_lcb));
X
X /*
- ** Chain into CCB list
+ ** Initialize command queuing control.
X */
- cp->next_ccb = lp->next_ccb;
- lp->next_ccb = cp;
+ lp->busyccbs = 1;
+ lp->queuedccbs = 1;
+ lp->queuedepth = 1;
+fail:
+ return lp;
X }
X
-/*==========================================================
-**
-**
-** Announce the number of ccbs/tags to the scsi driver.
-**
-**
-**==========================================================
-*/
X
-static void ncr_opennings (ncb_p np, lcb_p lp, Scsi_Cmnd * cmd)
+/*------------------------------------------------------------------------
+** Lun control block setup on INQUIRY data received.
+**------------------------------------------------------------------------
+** We only support WIDE, SYNC for targets and CMDQ for logical units.
+** This setup is done on each INQUIRY since we are expecting user
+** will play with CHANGE DEFINITION commands. :-)
+**------------------------------------------------------------------------
+*/
+static lcb_p ncr_setup_lcb (ncb_p np, u_char tn, u_char ln, u_char *inq_data)
X {


+ tcb_p tp = &np->target[tn];
+ lcb_p lp = tp->lp[ln];

+ u_char inq_byte7;
+
X /*
- ** want to reduce the number ...
+ ** If no lcb, try to allocate it.
X */
- if (lp->actlink > lp->reqlink) {
+ if (!lp && !(lp = ncr_alloc_lcb(np, tn, ln)))
+ goto fail;
X
- /*
- ** Try to reduce the count.
- ** We assume to run at splbio ..
- */
- u_char diff = lp->actlink - lp->reqlink;
+ /*
+ ** Get device quirks from a speciality table.
+ */
+ tp->quirks = ncr_lookup (inq_data);
+ if (tp->quirks && bootverbose) {
+ PRINT_LUN(np, tn, ln);
+ printk ("quirks=%x.\n", tp->quirks);
+ }
X
- if (!diff) return;
+ /*
+ ** Evaluate trustable target/unit capabilities.
+ ** We only believe device version >= SCSI-2 that
+ ** use appropriate response data format (2).
+ */
+ inq_byte7 = 0;
+ if ((inq_data[2] & 0x7) >= 2 && (inq_data[3] & 0xf) == 2)
+ inq_byte7 = inq_data[7];
X
- if (diff > lp->opennings)
- diff = lp->opennings;
+ /*
+ ** Throw away announced LUN capabilities if we are told
+ ** that there is no real device supported by the logical unit.
+ */
+ if ((inq_data[0] & 0xe0) > 0x20 || (inq_data[0] & 0x1f) == 0x1f)
+ inq_byte7 &= (INQ7_SYNC | INQ7_WIDE16);
X
- lp->opennings -= diff;
+ /*
+ ** If user is wanting SYNC, force this feature.
+ */
+ if (driver_setup.force_sync_nego)
+ inq_byte7 |= INQ7_SYNC;
X
- lp->actlink -= diff;
- if (DEBUG_FLAGS & DEBUG_TAGS)
- printf ("%s: actlink: diff=%d, new=%d, req=%d\n",
- ncr_name(np), diff, lp->actlink, lp->reqlink);


- return;
- };
+ /*

+ ** Prepare negotiation if SIP capabilities have changed.
+ */
+ tp->inq_done = 1;
+ if ((inq_byte7 ^ tp->inq_byte7) & (INQ7_SYNC | INQ7_WIDE16)) {
+ tp->inq_byte7 = inq_byte7;
+ ncr_negotiate(np, tp);
+ }
X
X /*
- ** want to increase the number ?
+ ** If unit supports tagged commands, allocate the
+ ** CCB JUMP table if not yet.
X */
- if (lp->reqlink > lp->actlink) {
- u_char diff = lp->reqlink - lp->actlink;
+ if ((inq_byte7 & INQ7_QUEUE) && lp->jump_ccb == &lp->jump_ccb_0) {
+ int i;
+ lp->jump_ccb = m_alloc(256, 8);
+ if (!lp->jump_ccb) {
+ lp->jump_ccb = &lp->jump_ccb_0;
+ goto fail;
+ }
+ lp->p_jump_ccb = cpu_to_scr(vtophys(lp->jump_ccb));
+ for (i = 0 ; i < 64 ; i++)
+ lp->jump_ccb[i] =
+ cpu_to_scr(NCB_SCRIPTH_PHYS (np, bad_i_t_l_q));
+ for (i = 0 ; i < SCSI_NCR_MAX_TAGS ; i++)
+ lp->cb_tags[i] = i;
+ lp->maxnxs = SCSI_NCR_MAX_TAGS;
+ lp->tags_stime = jiffies;
+ }
X
- lp->opennings += diff;
+ /*
+ ** Adjust tagged queueing status if needed.
+ */
+ if ((inq_byte7 ^ lp->inq_byte7) & INQ7_QUEUE) {
+ lp->inq_byte7 = inq_byte7;
+ lp->numtags = lp->maxtags;
+ ncr_setup_tags (np, tn, ln);
+ }
X
- lp->actlink += diff;
-#if 0
- wakeup ((caddr_t) xp->sc_link);
-#endif
- if (DEBUG_FLAGS & DEBUG_TAGS)
- printf ("%s: actlink: diff=%d, new=%d, req=%d\n",
- ncr_name(np), diff, lp->actlink, lp->reqlink);
- };
+fail:
+ return lp;
X }
X
X /*==========================================================
@@ -8471,9 +8753,6 @@
X int segment = 0;
X int use_sg = (int) cmd->use_sg;
X
-#if 0
- bzero (cp->phys.data, sizeof (cp->phys.data));
-#endif
X data = cp->phys.data;
X cp->data_len = 0;
X
@@ -8522,7 +8801,7 @@
X static int ncr_regtest (struct ncb* np)
X )
X {
- register volatile u_long data;
+ register volatile u_int32 data;
X /*
X ** ncr registers may NOT be cached.
X ** write 0xffffffff to a read only register area,
@@ -8536,7 +8815,7 @@
X #else
X if ((data & 0xe2f0fffd) != 0x02000080) {
X #endif
- printf ("CACHE TEST FAILED: reg dstat-sstat2 readback %x.\n",
+ printk ("CACHE TEST FAILED: reg dstat-sstat2 readback %x.\n",
X (unsigned) data);
X return (0x10);
X };
@@ -8548,8 +8827,8 @@
X static int ncr_snooptest (struct ncb* np)
X )
X {
- u_long ncr_rd, ncr_wr, ncr_bk, host_rd, host_wr, pc, err=0;
- int i;
+ u_int32 ncr_rd, ncr_wr, ncr_bk, host_rd, host_wr, pc;
+ int i, err=0;
X #ifndef NCR_IOMAPPED
X if (np->reg) {
X err |= ncr_regtest (np);
@@ -8591,22 +8870,22 @@
X ** Reset ncr chip
X */


X OUTB (nc_istat, SRST);
- DELAY (1000);
+ UDELAY (100);
X OUTB (nc_istat, 0 );

X /*
X ** check for timeout
X */
X if (i>=NCR_SNOOP_TIMEOUT) {
- printf ("CACHE TEST FAILED: timeout.\n");
+ printk ("CACHE TEST FAILED: timeout.\n");
X return (0x20);
X };
X /*
X ** Check termination position.
X */
X if (pc != NCB_SCRIPTH_PHYS (np, snoopend)+8) {
- printf ("CACHE TEST FAILED: script execution failed.\n");
- printf ("start=%08lx, pc=%08lx, end=%08lx\n",
- (u_long) NCB_SCRIPTH_PHYS (np, snooptest), pc,
+ printk ("CACHE TEST FAILED: script execution failed.\n");
+ printk ("start=%08lx, pc=%08lx, end=%08lx\n",
+ (u_long) NCB_SCRIPTH_PHYS (np, snooptest), (u_long) pc,
X (u_long) NCB_SCRIPTH_PHYS (np, snoopend) +8);
X return (0x40);
X };
@@ -8614,17 +8893,17 @@
X ** Show results.
X */
X if (host_wr != ncr_rd) {
- printf ("CACHE TEST FAILED: host wrote %d, ncr read %d.\n",
+ printk ("CACHE TEST FAILED: host wrote %d, ncr read %d.\n",
X (int) host_wr, (int) ncr_rd);
X err |= 1;
X };
X if (host_rd != ncr_wr) {
- printf ("CACHE TEST FAILED: ncr wrote %d, host read %d.\n",
+ printk ("CACHE TEST FAILED: ncr wrote %d, host read %d.\n",
X (int) ncr_wr, (int) host_rd);
X err |= 2;
X };
X if (ncr_bk != ncr_wr) {
- printf ("CACHE TEST FAILED: ncr wrote %d, read back %d.\n",
+ printk ("CACHE TEST FAILED: ncr wrote %d, read back %d.\n",
X (int) ncr_wr, (int) ncr_bk);
X err |= 4;
X };
@@ -8652,8 +8931,8 @@
X #define PROFILE cp->phys.header.stamp
X static void ncb_profile (ncb_p np, ccb_p cp)
X {
- int co, st, en, di, se, post,work,disc;
- u_long diff;
+ long co, st, en, di, re, post, work, disc;
+ u_int diff;
X
X PROFILE.end = jiffies;
X
@@ -8665,18 +8944,18 @@
X
X en = ncr_delta (PROFILE.start,PROFILE.end),
X di = ncr_delta (PROFILE.start,PROFILE.disconnect),
- se = ncr_delta (PROFILE.start,PROFILE.select);
+ re = ncr_delta (PROFILE.start,PROFILE.reselect);
X post = en - st;
X
X /*
X ** @PROFILE@ Disconnect time invalid if multiple disconnects
X */
X
- if (di>=0) disc = se-di; else disc = 0;
+ if (di>=0) disc = re - di; else disc = 0;
X
X work = (st - co) - disc;
X
- diff = (np->disc_phys - np->disc_ref) & 0xff;
+ diff = (scr_to_cpu(np->disc_phys) - np->disc_ref) & 0xff;
X np->disc_ref += diff;
X
X np->profile.num_trans += 1;
@@ -8718,13 +8997,13 @@
X
X static struct table_entry device_tab[] =
X {
-#ifdef NCR_GETCC_WITHMSG
+#if 0
X {"", "", "", QUIRK_NOMSG},
+#endif
X {"SONY", "SDT-5000", "3.17", QUIRK_NOMSG},
X {"WangDAT", "Model 2600", "01.7", QUIRK_NOMSG},
X {"WangDAT", "Model 3200", "02.2", QUIRK_NOMSG},
X {"WangDAT", "Model 1300", "02.4", QUIRK_NOMSG},
-#endif
X {"", "", "", 0} /* catch all: must be last entry. */
X };
X
@@ -8788,21 +9067,21 @@
X }
X
X if (bootverbose >= 2)
- printf ("%s: enabling clock multiplier\n", ncr_name(np));
+ printk ("%s: enabling clock multiplier\n", ncr_name(np));
X
X OUTB(nc_stest1, DBLEN); /* Enable clock multiplier */
X if (np->multiplier > 2) { /* Poll bit 5 of stest4 for quadrupler */
X int i = 20;
X while (!(INB(nc_stest4) & LCKFRQ) && --i > 0)
- DELAY(20);
+ UDELAY (20);
X if (!i)
- printf("%s: the chip cannot lock the frequency\n", ncr_name(np));
+ printk("%s: the chip cannot lock the frequency\n", ncr_name(np));
X } else /* Wait 20 micro-seconds for doubler */
- DELAY(20);
+ UDELAY (20);
X OUTB(nc_stest3, HSC); /* Halt the scsi clock */
X OUTB(nc_scntl3, scntl3);
X OUTB(nc_stest1, (DBLEN|DBLSEL));/* Select clock multiplier */
- OUTB(nc_stest3, 0x00|TE); /* Restart scsi clock */
+ OUTB(nc_stest3, 0x00); /* Restart scsi clock */
X }
X
X
@@ -8839,7 +9118,7 @@
X OUTB (nc_stime1, 0); /* disable general purpose timer */
X OUTB (nc_stime1, gen); /* set to nominal delay of 1<<gen * 125us */
X while (!(INW(nc_sist) & GEN) && ms++ < 100000)
- DELAY(1000); /* count ms */
+ UDELAY (1000); /* count ms */
X OUTB (nc_stime1, 0); /* disable general purpose timer */
X /*
X * set prescaler to divide by whatever 0 means
@@ -8849,7 +9128,7 @@
X OUTB (nc_scntl3, 0);
X

X if (bootverbose >= 2)

- printf ("%s: Delay (GEN=%d): %u msec\n", ncr_name(np), gen, ms);
+ printk ("%s: Delay (GEN=%d): %u msec\n", ncr_name(np), gen, ms);
X /*
X * adjust for prescaler, and convert into KHz
X */
@@ -8875,7 +9154,7 @@
X */
X if (mult > 1 && (stest1 & (DBLEN+DBLSEL)) == DBLEN+DBLSEL) {


X if (bootverbose >= 2)

- printf ("%s: clock multiplier found\n", ncr_name(np));
+ printk ("%s: clock multiplier found\n", ncr_name(np));
X np->multiplier = mult;
X }
X
@@ -8887,14 +9166,14 @@
X if (np->multiplier != mult || (scntl3 & 7) < 3 || !(scntl3 & 1)) {
X unsigned f2;
X
- OUTB(nc_istat, SRST); DELAY(5); OUTB(nc_istat, 0);
+ OUTB(nc_istat, SRST); UDELAY (5); OUTB(nc_istat, 0);
X
X (void) ncrgetfreq (np, 11); /* throw away first result */
X f1 = ncrgetfreq (np, 11);
X f2 = ncrgetfreq (np, 11);
X
X if (bootverbose)
- printf ("%s: NCR clock is %uKHz, %uKHz\n", ncr_name(np), f1, f2);
+ printk ("%s: NCR clock is %uKHz, %uKHz\n", ncr_name(np), f1, f2);
X
X if (f1 > f2) f1 = f2; /* trust lower result */
X
@@ -8904,7 +9183,7 @@
X
X if (f1 < 80000 && mult > 1) {


X if (bootverbose >= 2)

- printf ("%s: clock multiplier assumed\n", ncr_name(np));
+ printk ("%s: clock multiplier assumed\n", ncr_name(np));
X np->multiplier = mult;
X }
X } else {
@@ -8943,6 +9222,12 @@
X ** ---------------------------------------------------------------------
X */
X
+#ifdef MODULE
+#define ARG_SEP ' '
+#else
+#define ARG_SEP ','
+#endif
+
X __initfunc(
X void ncr53c8xx_setup(char *str, int *ints)
X )
@@ -8955,33 +9240,33 @@
X int c;
X
X while (cur != NULL && (pc = strchr(cur, ':')) != NULL) {
+ char *pe;
+
X val = 0;
X pv = pc;
X c = *++pv;
+
X if (c == 'n')
X val = 0;
X else if (c == 'y')
X val = 1;
X else {
X base = 0;
-#if 0
- if (c == '0') {
- c = *pv++;
- base = 8;
- }
- if (c == 'x') {
- ++pv;
- base = 16;
+ val = (int) simple_strtoul(pv, &pe, base);
+ }
+ if (!strncmp(cur, "tags:", 5)) {
+ int i;
+ driver_setup.default_tags = val;
+ if (pe && *pe == '/') {
+ i = 0;
+ while (*pe && *pe != ARG_SEP &&
+ i < sizeof(driver_setup.tag_ctrl)-1) {
+ driver_setup.tag_ctrl[i++] = *pe++;
+ }
+ driver_setup.tag_ctrl[i] = '\0';
X }
- else if (c >= '0' && c <= '9')
- base = 10;
- else
- break;
-#endif
- val = (int) simple_strtoul(pv, NULL, base);
X }
-
- if (!strncmp(cur, "mpar:", 5))
+ else if (!strncmp(cur, "mpar:", 5))
X driver_setup.master_parity = val;
X else if (!strncmp(cur, "spar:", 5))
X driver_setup.scsi_parity = val;
@@ -8995,11 +9280,6 @@
X driver_setup.force_sync_nego = val;
X else if (!strncmp(cur, "revprob:", 8))
X driver_setup.reverse_probe = val;
- else if (!strncmp(cur, "tags:", 5)) {
- if (val > SCSI_NCR_MAX_TAGS)
- val = SCSI_NCR_MAX_TAGS;
- driver_setup.default_tags = val;
- }
X else if (!strncmp(cur, "sync:", 5))
X driver_setup.default_sync = val;
X else if (!strncmp(cur, "verb:", 5))
@@ -9030,13 +9310,9 @@
X else if (!strncmp(cur, "safe:", 5) && val)
X memcpy(&driver_setup, &driver_safe_setup, sizeof(driver_setup));
X else
- printf("ncr53c8xx_setup: unexpected boot option '%.*s' ignored\n", (int)(pc-cur+1), cur);
+ printk("ncr53c8xx_setup: unexpected boot option '%.*s' ignored\n", (int)(pc-cur+1), cur);
X
-#ifdef MODULE
- if ((cur = strchr(cur, ' ')) != NULL)
-#else
- if ((cur = strchr(cur, ',')) != NULL)
-#endif
+ if ((cur = strchr(cur, ARG_SEP)) != NULL)
X ++cur;
X }
X #endif /* SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT */
@@ -9065,24 +9341,31 @@
X )
X {
X #define YesNo(y) y ? 'y' : 'n'
- printk("ncr53c8xx: setup=disc:%c,specf:%d,ultra:%c,tags:%d,sync:%d,burst:%d,wide:%c,diff:%d\n",
- YesNo(driver_setup.disconnection),
- driver_setup.special_features,
- YesNo(driver_setup.ultra_scsi),
- driver_setup.default_tags,
- driver_setup.default_sync,
- driver_setup.burst_max,
- YesNo(driver_setup.max_wide),
- driver_setup.diff_support);
- printk("ncr53c8xx: setup=mpar:%c,spar:%c,fsn=%c,verb:%d,debug:0x%x,led:%c,settle:%d,irqm:%d\n",
- YesNo(driver_setup.master_parity),
- YesNo(driver_setup.scsi_parity),
- YesNo(driver_setup.force_sync_nego),
- driver_setup.verbose,
- driver_setup.debug,
- YesNo(driver_setup.led_pin),
- driver_setup.settle_delay,
- driver_setup.irqm);
+ printk ("ncr53c8xx: setup=disc:%c,specf:%d,ultra:%d,tags:%d,sync:%d,"
+ "burst:%d,wide:%c,diff:%d,revprob:%c,buschk:0x%x\n",
+ YesNo(driver_setup.disconnection),
+ driver_setup.special_features,
+ driver_setup.ultra_scsi,
+ driver_setup.default_tags,
+ driver_setup.default_sync,
+ driver_setup.burst_max,
+ YesNo(driver_setup.max_wide),
+ driver_setup.diff_support,
+ YesNo(driver_setup.reverse_probe),
+ driver_setup.bus_check);
+
+ printk ("ncr53c8xx: setup=mpar:%c,spar:%c,fsn=%c,verb:%d,debug:0x%x,"
+ "led:%c,settle:%d,irqm:%d,nvram:0x%x,pcifix:0x%x\n",
+ YesNo(driver_setup.master_parity),
+ YesNo(driver_setup.scsi_parity),
+ YesNo(driver_setup.force_sync_nego),
+ driver_setup.verbose,
+ driver_setup.debug,
+ YesNo(driver_setup.led_pin),
+ driver_setup.settle_delay,
+ driver_setup.irqm,
+ driver_setup.use_nvram,
+ driver_setup.pci_fix_up);
X #undef YesNo
X }
X
@@ -9102,7 +9385,7 @@
X int i, j;
X int attach_count = 0;
X ncr_nvram *nvram;
- ncr_device *devp;
+ ncr_device *devp = 0; /* to shut up gcc */
X
X if (!nvram_index)
X return 0;
@@ -9117,13 +9400,13 @@
X if (nvram_index == -1)
X nvram_index = i;
X #ifdef SCSI_NCR_DEBUG_NVRAM
- printf("ncr53c8xx: NVRAM: Symbios format Boot Block, 53c%s, PCI bus %d, device %d, function %d\n",
+ printk("ncr53c8xx: NVRAM: Symbios format Boot Block, 53c%s, PCI bus %d, device %d, function %d\n",
X devp->chip.name, devp->slot.bus,
X (int) (devp->slot.device_fn & 0xf8) >> 3,
X (int) devp->slot.device_fn & 7);
X for (j = 0 ; j < 4 ; j++) {
X Symbios_host *h = &nvram->data.Symbios.host[j];
- printf("ncr53c8xx: BOOT[%d] device_id=%04x vendor_id=%04x device_fn=%02x io_port=%04x %s\n",
+ printk("ncr53c8xx: BOOT[%d] device_id=%04x vendor_id=%04x device_fn=%02x io_port=%04x %s\n",
X j, h->device_id, h->vendor_id,
X h->device_fn, h->io_port,
X (h->flags & SYMBIOS_INIT_SCAN_AT_BOOT) ? "SCAN AT BOOT" : "");
@@ -9131,7 +9414,7 @@
X }
X else if (nvram->type == SCSI_NCR_TEKRAM_NVRAM) {
X /* display Tekram nvram data */
- printf("ncr53c8xx: NVRAM: Tekram format data, 53c%s, PCI bus %d, device %d, function %d\n",
+ printk("ncr53c8xx: NVRAM: Tekram format data, 53c%s, PCI bus %d, device %d, function %d\n",
X devp->chip.name, devp->slot.bus,
X (int) (devp->slot.device_fn & 0xf8) >> 3,
X (int) devp->slot.device_fn & 7);
@@ -9198,18 +9481,14 @@
X #ifdef SCSI_NCR_NVRAM_SUPPORT
X int nvram_index = 0;
X #endif
- if (initverbose >= 2)
- ncr_print_driver_setup();
X
X #ifdef SCSI_NCR_DEBUG_INFO_SUPPORT
X ncr_debug = driver_setup.debug;
X #endif


X
-#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0)

X tpnt->proc_dir = &proc_scsi_ncr53c8xx;


-# ifdef SCSI_NCR_PROC_INFO_SUPPORT
+#ifdef SCSI_NCR_PROC_INFO_SUPPORT

X tpnt->proc_info = ncr53c8xx_proc_info;


-# endif
X #endif
X

X #if defined(SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT) && defined(MODULE)
@@ -9217,6 +9496,9 @@
X ncr53c8xx_setup(ncr53c8xx, (int *) 0);
X #endif
X
+ if (initverbose >= 2)
+ ncr_print_driver_setup();
+
X /*
X ** Detect all 53c8xx hosts and then attach them.
X **
@@ -9228,7 +9510,11 @@
X ** the order they are detected.
X */


X
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,92)

+ if (!pci_present())
+#else
X if (!pcibios_present())
+#endif
X return 0;
X
X chips = sizeof(ncr_chip_ids) / sizeof(ncr_chip_ids[0]);
@@ -9276,7 +9562,7 @@
X }
X }
X #endif
- printf(KERN_INFO "ncr53c8xx: 53c%s detected %s\n",
+ printk(KERN_INFO "ncr53c8xx: 53c%s detected %s\n",
X device[count].chip.name, msg);
X ++count;
X }
@@ -9292,7 +9578,7 @@
X for (i= 0; i < count; i++) {
X if (!device[i].attach_done &&
X !ncr_attach (tpnt, attach_count, &device[i])) {
- attach_count++;
+ attach_count++;
X }
X }
X
@@ -9312,11 +9598,14 @@
X {
X ushort vendor_id, device_id, command;
X uchar cache_line_size, latency_timer;
- uchar irq, revision;
-#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0)
- uint base, base_2, io_port;
+ uchar revision;
+#if LINUX_VERSION_CODE > LinuxVersionCode(2,1,92)
+ struct pci_dev *pdev;
+ ulong base, base_2, io_port;
+ uint irq;
X #else
- ulong base, base_2;
+ uchar irq;
+ uint base, base_2, io_port;
X #endif
X int i;
X
@@ -9325,8 +9614,6 @@
X #endif
X ncr_chip *chip;
X
- printk(KERN_INFO "ncr53c8xx: at PCI bus %d, device %d, function %d\n",
- bus, (int) (device_fn & 0xf8) >> 3, (int) device_fn & 7);
X /*
X * Read info from the PCI config space.
X * pcibios_read_config_xxx() functions are assumed to be used for
@@ -9340,16 +9627,29 @@
X PCI_DEVICE_ID, &device_id);
X (void) pcibios_read_config_word(bus, device_fn,
X PCI_COMMAND, &command);
+#if LINUX_VERSION_CODE > LinuxVersionCode(2,1,92)
+ pdev = pci_find_slot(bus, device_fn);
+ io_port = pdev->base_address[0];
+ base = pdev->base_address[1];
+ base_2 = pdev->base_address[2];


+ irq = pdev->irq;
+#else

X (void) pcibios_read_config_dword(bus, device_fn,
X PCI_BASE_ADDRESS_0, &io_port);
X (void) pcibios_read_config_dword(bus, device_fn,
X PCI_BASE_ADDRESS_1, &base);
X (void) pcibios_read_config_dword(bus, device_fn,
X PCI_BASE_ADDRESS_2, &base_2);
- (void) pcibios_read_config_byte(bus, device_fn,
- PCI_CLASS_REVISION,&revision);
+
+ /* Handle 64bit base adresses for 53C896. */
+ if ((base & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == PCI_BASE_ADDRESS_MEM_TYPE_64)
+ (void) pcibios_read_config_dword(bus, device_fn,
+ PCI_BASE_ADDRESS_3, &base_2);
X (void) pcibios_read_config_byte(bus, device_fn,
X PCI_INTERRUPT_LINE, &irq);
+#endif
+ (void) pcibios_read_config_byte(bus, device_fn,
+ PCI_CLASS_REVISION,&revision);
X (void) pcibios_read_config_byte(bus, device_fn,
X PCI_CACHE_LINE_SIZE, &cache_line_size);
X (void) pcibios_read_config_byte(bus, device_fn,
@@ -9369,6 +9669,34 @@
X chip->revision_id = revision;
X break;
X }
+
+#if defined(__i386__)
+ /*
+ * Ignore Symbios chips controlled by SISL RAID controller.
+ */
+ if (chip && (base_2 & PCI_BASE_ADDRESS_MEM_MASK)) {
+ unsigned int ScriptsSize, MagicValue;
+ vm_offset_t ScriptsRAM;
+
+ if (chip->features & FE_RAM8K)
+ ScriptsSize = 8192;
+ else
+ ScriptsSize = 4096;
+
+ ScriptsRAM = remap_pci_mem(base_2 & PCI_BASE_ADDRESS_MEM_MASK,
+ ScriptsSize);
+ if (ScriptsRAM) {
+ MagicValue = readl(ScriptsRAM + ScriptsSize - 16);
+ unmap_pci_mem(ScriptsRAM, ScriptsSize);
+ if (MagicValue == 0x52414944)


+ return -1;
+ }
+ }

+#endif
+
+ printk(KERN_INFO "ncr53c8xx: at PCI bus %d, device %d, function %d\n",
+ bus, (int) (device_fn & 0xf8) >> 3, (int) device_fn & 7);
+
X if (!chip) {
X printk("ncr53c8xx: not initializing, device not supported\n");
X return -1;
@@ -9376,25 +9704,111 @@
X
X #ifdef __powerpc__
X /*
- * Severall fix-up for power/pc.
+ * Several fix-up for power/pc.
X * Should not be performed by the driver.
X */
- if ((command &
- (PCI_COMMAND_MASTER|PCI_COMMAND_IO|PCI_COMMAND_MEMORY)) !=
- (PCI_COMMAND_MASTER|PCI_COMMAND_IO|PCI_COMMAND_MEMORY)) {
- printk("ncr53c8xx : setting PCI master/io/command bit\n");
- command |= PCI_COMMAND_MASTER|PCI_COMMAND_IO|PCI_COMMAND_MEMORY;
+ if (!(command & PCI_COMMAND_MASTER)) {
+ printk("ncr53c8xx: attempting to force PCI_COMMAND_MASTER...");
+ command |= PCI_COMMAND_MASTER;
X pcibios_write_config_word(bus, device_fn, PCI_COMMAND, command);
+ pcibios_read_config_word(bus, device_fn, PCI_COMMAND, &command);
+ if (!(command & PCI_COMMAND_MASTER)) {
+ printk("failed!\n");
+ } else {
+ printk("succeeded.\n");
+ }
X }
- if (io_port >= 0x10000000) {
- io_port = (io_port & 0x00FFFFFF) | 0x01000000;
- pcibios_write_config_dword(bus, device_fn, PCI_BASE_ADDRESS_0, io_port);
- }
- if (base >= 0x10000000) {
- base = (base & 0x00FFFFFF) | 0x01000000;
- pcibios_write_config_dword(bus, device_fn, PCI_BASE_ADDRESS_1, base);
+
+ if (!(command & PCI_COMMAND_IO)) {
+ printk("ncr53c8xx: attempting to force PCI_COMMAND_IO...");
+ command |= PCI_COMMAND_IO;
+ pcibios_write_config_word(bus, device_fn, PCI_COMMAND, command);
+ pcibios_read_config_word(bus, device_fn, PCI_COMMAND, &command);
+ if (!(command & PCI_COMMAND_IO)) {
+ printk("failed!\n");
+ } else {
+ printk("succeeded.\n");
+ }
X }
-#endif
+
+ if (!(command & PCI_COMMAND_MEMORY)) {
+ printk("ncr53c8xx: attempting to force PCI_COMMAND_MEMORY...");
+ command |= PCI_COMMAND_MEMORY;
+ pcibios_write_config_word(bus, device_fn, PCI_COMMAND, command);
+ pcibios_read_config_word(bus, device_fn, PCI_COMMAND, &command);
+ if (!(command & PCI_COMMAND_MEMORY)) {
+ printk("failed!\n");
+ } else {
+ printk("succeeded.\n");
+ }
+ }
+
+ if ( is_prep ) {
+ if (io_port >= 0x10000000) {
+ printk("ncr53c8xx: reallocating io_port (Wacky IBM)");
+ io_port = (io_port & 0x00FFFFFF) | 0x01000000;
+ pcibios_write_config_dword(bus, device_fn, PCI_BASE_ADDRESS_0, io_port);
+ }
+ if (base >= 0x10000000) {
+ printk("ncr53c8xx: reallocating base (Wacky IBM)");
+ base = (base & 0x00FFFFFF) | 0x01000000;
+ pcibios_write_config_dword(bus, device_fn, PCI_BASE_ADDRESS_1, base);
+ }
+ if (base_2 >= 0x10000000) {
+ printk("ncr53c8xx: reallocating base2 (Wacky IBM)");
+ base_2 = (base_2 & 0x00FFFFFF) | 0x01000000;
+ pcibios_write_config_dword(bus, device_fn, PCI_BASE_ADDRESS_2, base_2);
+ }
+ }
+#endif /* __powerpc__ */
+
+#ifdef __sparc__
+ /*
+ * Severall fix-ups for sparc.
+ *
+ * Should not be performed by the driver, but how can OBP know
+ * each and every PCI card, if they don't use Fcode?
+ */
+
+ base = __pa(base);
+ base_2 = __pa(base_2);
+
+ if (!(command & PCI_COMMAND_MASTER)) {
+ if (initverbose >= 2)
+ printk("ncr53c8xx: setting PCI_COMMAND_MASTER bit (fixup)\n");
+ command |= PCI_COMMAND_MASTER;
+ pcibios_write_config_word(bus, device_fn, PCI_COMMAND, command);
+ pcibios_read_config_word(bus, device_fn, PCI_COMMAND, &command);
+ }
+
+ if ((chip->features & FE_WRIE) && !(command & PCI_COMMAND_INVALIDATE)) {
+ if (initverbose >= 2)
+ printk("ncr53c8xx: setting PCI_COMMAND_INVALIDATE bit (fixup)\n");
+ command |= PCI_COMMAND_INVALIDATE;
+ pcibios_write_config_word(bus, device_fn, PCI_COMMAND, command);
+ pcibios_read_config_word(bus, device_fn, PCI_COMMAND, &command);
+ }
+
+ if ((chip->features & FE_CLSE) && !cache_line_size) {
+ cache_line_size = CACHE_LINE_SIZE;
+ if (initverbose >= 2)
+ printk("ncr53c8xx: setting PCI_CACHE_LINE_SIZE to %d (fixup)\n", cache_line_size);
+ pcibios_write_config_byte(bus, device_fn,
+ PCI_CACHE_LINE_SIZE, cache_line_size);
+ pcibios_read_config_byte(bus, device_fn,
+ PCI_CACHE_LINE_SIZE, &cache_line_size);
+ }
+
+ if (!latency_timer) {
+ latency_timer = 248;
+ if (initverbose >= 2)
+ printk("ncr53c8xx: setting PCI_LATENCY_TIMER to %d bus clocks (fixup)\n", latency_timer);
+ pcibios_write_config_byte(bus, device_fn,
+ PCI_LATENCY_TIMER, latency_timer);
+ pcibios_read_config_byte(bus, device_fn,
+ PCI_LATENCY_TIMER, &latency_timer);
+ }
+#endif /* __sparc__ */
X
X /*
X * Check availability of IO space, memory space and master capability.
@@ -9431,8 +9845,13 @@
X base_2 &= PCI_BASE_ADDRESS_MEM_MASK;
X
X if (io_port && check_region (io_port, 128)) {
+#ifdef __sparc__
+ printk("ncr53c8xx: IO region 0x%lx to 0x%lx is in use\n",
+ io_port, (io_port + 127));
+#else
X printk("ncr53c8xx: IO region 0x%x to 0x%x is in use\n",
X (int) io_port, (int) (io_port + 127));
+#endif
X return -1;
X }
X
@@ -9465,7 +9884,7 @@
X /*
X * Try to fix up PCI config according to wished features.
X */
-#if defined(__i386) && !defined(MODULE)
+#if defined(__i386__) && !defined(MODULE)
X if ((driver_setup.pci_fix_up & 1) &&
X (chip->features & FE_CLSE) && cache_line_size == 0) {
X #if LINUX_VERSION_CODE < LinuxVersionCode(2,1,75)
@@ -9475,6 +9894,7 @@
X switch(boot_cpu_data.x86) {
X #endif
X case 4: cache_line_size = 4; break;
+ case 6:
X case 5: cache_line_size = 8; break;
X }
X if (cache_line_size)
@@ -9610,35 +10030,111 @@
X return 0;
X }


X
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,0,0)

X /*
X ** Linux select queue depths function
X */
+
+#define DEF_DEPTH (driver_setup.default_tags)
+#define ALL_TARGETS -2
+#define NO_TARGET -1
+#define ALL_LUNS -2
+#define NO_LUN -1
+
+static int device_queue_depth(ncb_p np, int target, int lun)
+{
+ int c, h, t, u, v;
+ char *p = driver_setup.tag_ctrl;
+ char *ep;
+
+ h = -1;
+ t = NO_TARGET;
+ u = NO_LUN;
+ while ((c = *p++) != 0) {
+ v = simple_strtoul(p, &ep, 0);
+ switch(c) {
+ case '/':
+ ++h;
+ t = ALL_TARGETS;
+ u = ALL_LUNS;
+ break;
+ case 't':
+ if (t != target)
+ t = (target == v) ? v : NO_TARGET;
+ u = ALL_LUNS;
+ break;
+ case 'u':
+ if (u != lun)
+ u = (lun == v) ? v : NO_LUN;
+ break;
+ case 'q':
+ if (h == np->unit &&
+ (t == ALL_TARGETS || t == target) &&
+ (u == ALL_LUNS || u == lun))
+ return v;
+ break;
+ case '-':
+ t = ALL_TARGETS;
+ u = ALL_LUNS;
+ break;
+ default:
+ break;
+ }
+ p = ep;
+ }
+ return DEF_DEPTH;
+}
+
X static void ncr53c8xx_select_queue_depths(struct Scsi_Host *host, struct scsi_device *devlist)
X {
X struct scsi_device *device;
X
X for (device = devlist; device; device = device->next) {
- if (device->host == host) {
-#if SCSI_NCR_MAX_TAGS > 1
- if (device->tagged_supported) {
- device->queue_depth = SCSI_NCR_MAX_TAGS;
- }
- else {
- device->queue_depth = 2;
- }
-#else
- device->queue_depth = 1;
-#endif
+ ncb_p np;
+ tcb_p tp;
+ lcb_p lp;
+ int numtags;
+
+ if (device->host != host)
+ continue;
+
+ np = ((struct host_data *) host->hostdata)->ncb;
+ tp = &np->target[device->id];
+ lp = tp->lp[device->lun];
+
+ /*
+ ** Select queue depth from driver setup.
+ ** Donnot use more than configured by user.
+ ** Use at least 2.
+ ** Donnot use more than our maximum.
+ */
+ numtags = device_queue_depth(np, device->id, device->lun);
+ if (numtags > tp->usrtags)
+ numtags = tp->usrtags;
+ if (!device->tagged_supported)
+ numtags = 1;
+ device->queue_depth = numtags;
+ if (device->queue_depth < 2)
+ device->queue_depth = 2;
+ if (device->queue_depth > SCSI_NCR_MAX_TAGS)
+ device->queue_depth = SCSI_NCR_MAX_TAGS;
+
+ /*
+ ** Since the queue depth is not tunable under Linux,
+ ** we need to know this value in order not to
+ ** announce stupid things to user.


+ */
+ if (lp) {

+ lp->numtags = lp->maxtags = numtags;
+ lp->scdev_depth = device->queue_depth;
+ }
+ ncr_setup_tags (np, device->id, device->lun);
X
X #ifdef DEBUG_NCR53C8XX
-printk("ncr53c8xx_select_queue_depth: id=%d, lun=%d, queue_depth=%d\n",
- device->id, device->lun, device->queue_depth);
+printk("ncr53c8xx_select_queue_depth: host=%d, id=%d, lun=%d, depth=%d\n",
+ np->unit, device->id, device->lun, device->queue_depth);
X #endif
- }
X }


X }
-#endif
X
X /*

X ** Linux entry point of queuecommand() function
@@ -9646,69 +10142,96 @@
X
X int ncr53c8xx_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *))
X {
+ ncb_p np = ((struct host_data *) cmd->host->hostdata)->ncb;
+ unsigned long flags;
X int sts;
+
X #ifdef DEBUG_NCR53C8XX
X printk("ncr53c8xx_queue_command\n");
X #endif
X
- if ((sts = ncr_queue_command(cmd, done)) != DID_OK) {
+ cmd->scsi_done = done;
+ cmd->host_scribble = NULL;
+ cmd->SCp.ptr = NULL;
+ cmd->SCp.buffer = NULL;
+
+ NCR_LOCK_NCB(np, flags);
+
+ if ((sts = ncr_queue_command(np, cmd)) != DID_OK) {
X cmd->result = ScsiResult(sts, 0);
- done(cmd);
X #ifdef DEBUG_NCR53C8XX
X printk("ncr53c8xx : command not queued - result=%d\n", sts);
X #endif
- return sts;
X }
X #ifdef DEBUG_NCR53C8XX
+ else
X printk("ncr53c8xx : command successfully queued\n");
X #endif
+
+ NCR_UNLOCK_NCB(np, flags);
+
+ if (sts != DID_OK)
+ done(cmd);
+
X return sts;
X }
X
X /*
X ** Linux entry point of the interrupt handler.
-** Fort linux versions > 1.3.70, we trust the kernel for
+** Since linux versions > 1.3.70, we trust the kernel for
X ** passing the internal host descriptor as 'dev_id'.
X ** Otherwise, we scan the host list and call the interrupt
X ** routine for each host that uses this IRQ.
X */
X
-#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,70)
X static void ncr53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs)


SHAR_EOF
true || echo 'restore of patch-2.0.37 failed'
fi

echo 'End of part 33'
echo 'File patch-2.0.37 is continued in part 34'
echo 34 > _shar_seq_.tmp

Thomas...@ciw.uni-karlsruhe.de

unread,
Jun 16, 1999, 3:00:00 AM6/16/99
to
Archive-name: v2.0/patch-2.0.37/part34

#!/bin/sh
# this is part 34 of a 45 - part archive


# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.0.37 continued
if test ! -r _shar_seq_.tmp; then
echo 'Please unpack part 1 first!'
exit 1
fi
(read Scheck

if test "$Scheck" != 34; then


echo Please unpack part "$Scheck" next!
exit 1
else
exit 0
fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.0.37'
else
echo 'x - continuing with patch-2.0.37'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.0.37' &&

X {
+ unsigned long flags;
+ ncb_p np = (ncb_p) dev_id;
+ Scsi_Cmnd *done_list;
+
X #ifdef DEBUG_NCR53C8XX
X printk("ncr53c8xx : interrupt received\n");
X #endif
X
- if (DEBUG_FLAGS & DEBUG_TINY) printf ("[");
- ncr_exception((ncb_p) dev_id);
- if (DEBUG_FLAGS & DEBUG_TINY) printf ("]\n");
-}
-


-#else
-static void ncr53c8xx_intr(int irq, struct pt_regs * regs)

-{
- struct Scsi_Host *host;

- struct host_data *host_data;
+ if (DEBUG_FLAGS & DEBUG_TINY) printk ("[");
X
- for (host = first_host; host; host = host->next) {
- if (host->hostt == the_template && host->irq == irq) {
- host_data = (struct host_data *) host->hostdata;
- if (DEBUG_FLAGS & DEBUG_TINY) printf ("[");
- ncr_exception(host_data->ncb);
- if (DEBUG_FLAGS & DEBUG_TINY) printf ("]\n");
- }
+ NCR_LOCK_NCB(np, flags);
+ ncr_exception(np);
+ done_list = np->done_list;
+ np->done_list = 0;
+ NCR_UNLOCK_NCB(np, flags);
+
+ if (DEBUG_FLAGS & DEBUG_TINY) printk ("]\n");
+
+ if (done_list) {
+ NCR_LOCK_SCSI_DONE(np, flags);
+ ncr_flush_done_cmds(done_list);
+ NCR_UNLOCK_SCSI_DONE(np, flags);


X }
X }
-#endif
X
X /*

X ** Linux entry point of the timer handler
X */
X
-static void ncr53c8xx_timeout(unsigned long np)
+static void ncr53c8xx_timeout(unsigned long npref)
X {
+ ncb_p np = (ncb_p) npref;
+ unsigned long flags;
+ Scsi_Cmnd *done_list;
+
+ NCR_LOCK_NCB(np, flags);
X ncr_timeout((ncb_p) np);
+ done_list = np->done_list;
+ np->done_list = 0;
+ NCR_UNLOCK_NCB(np, flags);
+
+ if (done_list) {
+ NCR_LOCK_SCSI_DONE(np, flags);
+ ncr_flush_done_cmds(done_list);
+ NCR_UNLOCK_SCSI_DONE(np, flags);
+ }
X }
X
X /*
@@ -9716,16 +10239,24 @@
X */
X
X #if defined SCSI_RESET_SYNCHRONOUS && defined SCSI_RESET_ASYNCHRONOUS
-
X int ncr53c8xx_reset(Scsi_Cmnd *cmd, unsigned int reset_flags)
+#else
+int ncr53c8xx_reset(Scsi_Cmnd *cmd)
+#endif


X {
+ ncb_p np = ((struct host_data *) cmd->host->hostdata)->ncb;

X int sts;
X unsigned long flags;
+ Scsi_Cmnd *done_list;
X
+#if defined SCSI_RESET_SYNCHRONOUS && defined SCSI_RESET_ASYNCHRONOUS
X printk("ncr53c8xx_reset: pid=%lu reset_flags=%x serial_number=%ld serial_number_at_timeout=%ld\n",
X cmd->pid, reset_flags, cmd->serial_number, cmd->serial_number_at_timeout);
+#else
+ printk("ncr53c8xx_reset: command pid %lu\n", cmd->pid);
+#endif
X
- save_flags(flags); cli();
+ NCR_LOCK_NCB(np, flags);
X
X /*
X * We have to just ignore reset requests in some situations.
@@ -9743,8 +10274,13 @@
X * before returning SCSI_RESET_SUCCESS.
X */
X
- sts = ncr_reset_bus(cmd,
+#if defined SCSI_RESET_SYNCHRONOUS && defined SCSI_RESET_ASYNCHRONOUS
+ sts = ncr_reset_bus(np, cmd,
X (reset_flags & (SCSI_RESET_SYNCHRONOUS | SCSI_RESET_ASYNCHRONOUS)) == SCSI_RESET_SYNCHRONOUS);
+#else
+ sts = ncr_reset_bus(np, cmd, 0);
+#endif
+
X /*
X * Since we always reset the controller, when we return success,
X * we add this information to the return code.
@@ -9755,33 +10291,36 @@
X #endif
X
X out:
- restore_flags(flags);
+ done_list = np->done_list;
+ np->done_list = 0;
+ NCR_UNLOCK_NCB(np, flags);
+
+ ncr_flush_done_cmds(done_list);


+
X return sts;
X }

-#else
-int ncr53c8xx_reset(Scsi_Cmnd *cmd)
-{
- printk("ncr53c8xx_reset: command pid %lu\n", cmd->pid);
- return ncr_reset_bus(cmd, 1);
-}
-#endif
X
X /*
X ** Linux entry point of abort() function
X */
X
-#if defined SCSI_RESET_SYNCHRONOUS && defined SCSI_RESET_ASYNCHRONOUS
-
X int ncr53c8xx_abort(Scsi_Cmnd *cmd)


X {
+ ncb_p np = ((struct host_data *) cmd->host->hostdata)->ncb;

X int sts;
X unsigned long flags;
+ Scsi_Cmnd *done_list;
X
+#if defined SCSI_RESET_SYNCHRONOUS && defined SCSI_RESET_ASYNCHRONOUS
X printk("ncr53c8xx_abort: pid=%lu serial_number=%ld serial_number_at_timeout=%ld\n",
X cmd->pid, cmd->serial_number, cmd->serial_number_at_timeout);
+#else
+ printk("ncr53c8xx_abort: command pid %lu\n", cmd->pid);
+#endif
X
- save_flags(flags); cli();
+ NCR_LOCK_NCB(np, flags);
X
+#if defined SCSI_RESET_SYNCHRONOUS && defined SCSI_RESET_ASYNCHRONOUS
X /*
X * We have to just ignore abort requests in some situations.
X */
@@ -9789,19 +10328,19 @@
X sts = SCSI_ABORT_NOT_RUNNING;
X goto out;
X }
+#endif
X
- sts = ncr_abort_command(cmd);
+ sts = ncr_abort_command(np, cmd);
X out:
- restore_flags(flags);
+ done_list = np->done_list;
+ np->done_list = 0;
+ NCR_UNLOCK_NCB(np, flags);
+
+ ncr_flush_done_cmds(done_list);


+
X return sts;
X }

-#else
-int ncr53c8xx_abort(Scsi_Cmnd *cmd)
-{
- printk("ncr53c8xx_abort: command pid %lu\n", cmd->pid);
- return ncr_abort_command(cmd);
-}
-#endif
+
X
X #ifdef MODULE
X int ncr53c8xx_release(struct Scsi_Host *host)
@@ -9836,7 +10375,7 @@
X Scsi_Cmnd *wcmd;
X
X #ifdef DEBUG_WAITING_LIST
- printf("%s: cmd %lx inserted into waiting list\n", ncr_name(np), (u_long) cmd);
+ printk("%s: cmd %lx inserted into waiting list\n", ncr_name(np), (u_long) cmd);
X #endif
X cmd->next_wcmd = 0;
X if (!(wcmd = np->waiting_list)) np->waiting_list = cmd;
@@ -9859,7 +10398,7 @@
X cmd->next_wcmd = 0;
X }
X #ifdef DEBUG_WAITING_LIST
- printf("%s: cmd %lx retrieved from waiting list\n", ncr_name(np), (u_long) cmd);
+ printk("%s: cmd %lx retrieved from waiting list\n", ncr_name(np), (u_long) cmd);
X #endif
X return cmd;
X }
@@ -9875,70 +10414,29 @@
X np->waiting_list = 0;
X
X #ifdef DEBUG_WAITING_LIST
- if (waiting_list) printf("%s: waiting_list=%lx processing sts=%d\n", ncr_name(np), (u_long) waiting_list, sts);
+ if (waiting_list) printk("%s: waiting_list=%lx processing sts=%d\n", ncr_name(np), (u_long) waiting_list, sts);
X #endif
X while ((wcmd = waiting_list) != 0) {
X waiting_list = (Scsi_Cmnd *) wcmd->next_wcmd;
X wcmd->next_wcmd = 0;
X if (sts == DID_OK) {
X #ifdef DEBUG_WAITING_LIST
- printf("%s: cmd %lx trying to requeue\n", ncr_name(np), (u_long) wcmd);
+ printk("%s: cmd %lx trying to requeue\n", ncr_name(np), (u_long) wcmd);
X #endif
- sts = ncr_queue_command(wcmd, wcmd->scsi_done);
+ sts = ncr_queue_command(np, wcmd);
X }
X if (sts != DID_OK) {
X #ifdef DEBUG_WAITING_LIST
- printf("%s: cmd %lx done forced sts=%d\n", ncr_name(np), (u_long) wcmd, sts);
+ printk("%s: cmd %lx done forced sts=%d\n", ncr_name(np), (u_long) wcmd, sts);
X #endif
X wcmd->result = ScsiResult(sts, 0);
- wcmd->scsi_done(wcmd);
+ ncr_queue_done_cmd(np, wcmd);
X }
X }
X }
X
X #undef next_wcmd
X
-/*
-** Returns data transfer direction for common op-codes.
-*/
-
-static int guess_xfer_direction(int opcode)
-{
- int d;
-
- switch(opcode) {
- case 0x12: /* INQUIRY 12 */
- case 0x4D: /* LOG SENSE 4D */
- case 0x5A: /* MODE SENSE(10) 5A */
- case 0x1A: /* MODE SENSE(6) 1A */
- case 0x3C: /* READ BUFFER 3C */
- case 0x1C: /* RECEIVE DIAGNOSTIC RESULTS 1C */
- case 0x03: /* REQUEST SENSE 03 */
- d = XferIn;
- break;
- case 0x39: /* COMPARE 39 */
- case 0x3A: /* COPY AND VERIFY 3A */
- case 0x18: /* COPY 18 */
- case 0x4C: /* LOG SELECT 4C */
- case 0x55: /* MODE SELECT(10) 55 */
- case 0x3B: /* WRITE BUFFER 3B */
- case 0x1D: /* SEND DIAGNOSTIC 1D */
- case 0x40: /* CHANGE DEFINITION 40 */
- case 0x15: /* MODE SELECT(6) 15 */
- d = XferOut;
- break;
- case 0x00: /* TEST UNIT READY 00 */
- d = XferNone;
- break;
- default:
- d = XferBoth;
- break;
- }
-
- return d;
-}
-
-
X #ifdef SCSI_NCR_PROC_INFO_SUPPORT
X
X /*=========================================================================
@@ -10026,6 +10524,8 @@
X uc->cmd = UC_SETTAGS;
X else if ((arg_len = is_keyword(ptr, len, "setorder")) != 0)
X uc->cmd = UC_SETORDER;
+ else if ((arg_len = is_keyword(ptr, len, "setverbose")) != 0)
+ uc->cmd = UC_SETVERBOSE;
X else if ((arg_len = is_keyword(ptr, len, "setwide")) != 0)
X uc->cmd = UC_SETWIDE;
X else if ((arg_len = is_keyword(ptr, len, "setdebug")) != 0)
@@ -10034,15 +10534,11 @@
X uc->cmd = UC_SETFLAG;
X else if ((arg_len = is_keyword(ptr, len, "clearprof")) != 0)
X uc->cmd = UC_CLEARPROF;
-#ifdef UC_DEBUG_ERROR_RECOVERY
- else if ((arg_len = is_keyword(ptr, len, "debug_error_recovery")) != 0)
- uc->cmd = UC_DEBUG_ERROR_RECOVERY;
-#endif
X else
X arg_len = 0;
X
X #ifdef DEBUG_PROC_INFO
-printf("ncr_user_command: arg_len=%d, cmd=%ld\n", arg_len, uc->cmd);
+printk("ncr_user_command: arg_len=%d, cmd=%ld\n", arg_len, uc->cmd);
X #endif
X
X if (!arg_len)
@@ -10062,20 +10558,21 @@
X GET_INT_ARG(target);
X uc->target = (1<<target);
X #ifdef DEBUG_PROC_INFO
-printf("ncr_user_command: target=%ld\n", target);
+printk("ncr_user_command: target=%ld\n", target);
X #endif
X }
X break;
X }
X
X switch(uc->cmd) {
+ case UC_SETVERBOSE:
X case UC_SETSYNC:
X case UC_SETTAGS:
X case UC_SETWIDE:
X SKIP_SPACES(1);
X GET_INT_ARG(uc->data);
X #ifdef DEBUG_PROC_INFO
-printf("ncr_user_command: data=%ld\n", uc->data);
+printk("ncr_user_command: data=%ld\n", uc->data);
X #endif
X break;
X case UC_SETORDER:
@@ -10123,7 +10620,7 @@
X ptr += arg_len; len -= arg_len;
X }
X #ifdef DEBUG_PROC_INFO
-printf("ncr_user_command: data=%ld\n", uc->data);
+printk("ncr_user_command: data=%ld\n", uc->data);
X #endif
X break;
X case UC_SETFLAG:
@@ -10138,24 +10635,6 @@
X ptr += arg_len; len -= arg_len;
X }


X break;
-#ifdef UC_DEBUG_ERROR_RECOVERY
- case UC_DEBUG_ERROR_RECOVERY:

- SKIP_SPACES(1);
- if ((arg_len = is_keyword(ptr, len, "sge")))
- uc->data = 1;
- else if ((arg_len = is_keyword(ptr, len, "abort")))
- uc->data = 2;
- else if ((arg_len = is_keyword(ptr, len, "reset")))
- uc->data = 3;
- else if ((arg_len = is_keyword(ptr, len, "parity")))
- uc->data = 4;
- else if ((arg_len = is_keyword(ptr, len, "none")))
- uc->data = 0;
- else
- return -EINVAL;
- ptr += arg_len; len -= arg_len;
- break;
-#endif
X default:
X break;
X }
@@ -10165,9 +10644,9 @@
X else {
X long flags;
X
- save_flags(flags); cli();
+ NCR_LOCK_NCB(np, flags);
X ncr_usercmd (np);
- restore_flags(flags);
+ NCR_UNLOCK_NCB(np, flags);
X }
X return length;
X }
@@ -10239,7 +10718,11 @@
X copy_info(&info, "revision id 0x%x\n", np->revision_id);
X
X copy_info(&info, " IO port address 0x%lx, ", (u_long) np->port);
+#ifdef __sparc__
+ copy_info(&info, "IRQ number %s\n", __irq_itoa(np->irq));
+#else
X copy_info(&info, "IRQ number %d\n", (int) np->irq);
+#endif
X

X #ifndef NCR_IOMAPPED
X if (np->reg)

@@ -10288,7 +10771,7 @@
X int retv;
X
X #ifdef DEBUG_PROC_INFO
-printf("ncr53c8xx_proc_info: hostno=%d, func=%d\n", hostno, func);
+printk("ncr53c8xx_proc_info: hostno=%d, func=%d\n", hostno, func);
X #endif
X
X for (host = first_host; host; host = host->next) {
@@ -10426,7 +10909,7 @@
X nvram_stop(np, &gpreg);
X
X #ifdef SCSI_NCR_DEBUG_NVRAM
-printf("ncr53c8xx: NvRAM marker=%x trailer=%x %x %x %x %x %x byte_count=%d/%d checksum=%x/%x\n",
+printk("ncr53c8xx: NvRAM marker=%x trailer=%x %x %x %x %x %x byte_count=%d/%d checksum=%x/%x\n",
X nvram->start_marker,
X nvram->trailer[0], nvram->trailer[1], nvram->trailer[2],
X nvram->trailer[3], nvram->trailer[4], nvram->trailer[5],
@@ -10576,7 +11059,7 @@
X static void nvram_setBit(ncr_slot *np, u_char write_bit, u_char *gpreg, int bit_mode)
X )
X {
- DELAY(5);
+ UDELAY (5);
X switch (bit_mode){
X case SET_BIT:
X *gpreg |= write_bit;
@@ -10593,7 +11076,7 @@
X
X }
X OUTB (nc_gpreg, *gpreg);
- DELAY(5);
+ UDELAY (5);
X }
X
X #undef SET_BIT 0
@@ -10730,7 +11213,7 @@
X static void Tnvram_Read_Bit(ncr_slot *np, u_char *read_bit, u_char *gpreg)
X )
X {
- DELAY(2);
+ UDELAY (2);
X Tnvram_Clk(np, gpreg);
X *read_bit = INB (nc_gpreg);
X }
@@ -10750,7 +11233,7 @@
X *gpreg |= 0x10;
X
X OUTB (nc_gpreg, *gpreg);
- DELAY(2);
+ UDELAY (2);
X
X Tnvram_Clk(np, gpreg);
X }
@@ -10764,7 +11247,7 @@
X {
X *gpreg &= 0xef;
X OUTB (nc_gpreg, *gpreg);
- DELAY(2);
+ UDELAY (2);
X
X Tnvram_Clk(np, gpreg);
X }
@@ -10777,7 +11260,7 @@
X )
X {
X OUTB (nc_gpreg, *gpreg | 0x04);
- DELAY(2);
+ UDELAY (2);
X OUTB (nc_gpreg, *gpreg);
X }
X
diff -u --recursive --new-file v2.0.36/linux/drivers/scsi/ncr53c8xx.h linux/drivers/scsi/ncr53c8xx.h
--- v2.0.36/linux/drivers/scsi/ncr53c8xx.h Mon Jul 13 13:46:35 1998
+++ linux/drivers/scsi/ncr53c8xx.h Sun Jun 13 10:21:02 1999
@@ -45,7 +45,7 @@
X /*
X ** Name and revision of the driver
X */
-#define SCSI_NCR_DRIVER_NAME "ncr53c8xx - revision 2.5f.1"
+#define SCSI_NCR_DRIVER_NAME "ncr53c8xx - revision 3.1e"
X
X /*
X ** Check supported Linux versions
@@ -56,51 +56,34 @@
X #endif
X #include <linux/config.h>
X
-/*
-** During make dep of linux-1.2.13, LINUX_VERSION_CODE is undefined
-** Under linux-1.3.X, all seems to be OK.
-** So, we have only to define it under 1.2.13
-*/
-
X #define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
X
-#if !defined(LINUX_VERSION_CODE)
-#define LINUX_VERSION_CODE LinuxVersionCode(1,2,13)
+/*
+ * No more an option, enabled by default.
+ */
+#ifndef CONFIG_SCSI_NCR53C8XX_NVRAM_DETECT
+#define CONFIG_SCSI_NCR53C8XX_NVRAM_DETECT


X #endif
X
X /*

-** Normal IO or memory mapped IO.
-**
-** Memory mapped IO only works with linux-1.3.X
-** If your motherboard does not work with memory mapped IO,
-** define SCSI_NCR_IOMAPPED for PATCHLEVEL 3 too.
+** These options are not tunable from 'make config'
X */
-
-#if LINUX_VERSION_CODE < LinuxVersionCode(1,3,0)
-# define SCSI_NCR_IOMAPPED
-#endif
-
-#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0)
-# define SCSI_NCR_PROC_INFO_SUPPORT
-#endif
-
-#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,72)
-# define SCSI_NCR_SHARE_IRQ
-#endif
+#define SCSI_NCR_PROC_INFO_SUPPORT
+#define SCSI_NCR_SHARE_IRQ
X
X /*
X ** If you want a driver as small as possible, donnot define the
X ** following options.
X */
-
X #define SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT
X #define SCSI_NCR_DEBUG_INFO_SUPPORT
X #define SCSI_NCR_PCI_FIX_UP_SUPPORT
X #ifdef SCSI_NCR_PROC_INFO_SUPPORT
-# define SCSI_NCR_PROFILE_SUPPORT
+# ifdef CONFIG_SCSI_NCR53C8XX_PROFILE
+# define SCSI_NCR_PROFILE_SUPPORT
+# endif
X # define SCSI_NCR_USER_COMMAND_SUPPORT
X # define SCSI_NCR_USER_INFO_SUPPORT
-/* # define SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT */
X #endif
X
X /*==========================================================
@@ -130,25 +113,27 @@
X #define SCSI_NCR_MAX_SYNC (40)
X
X /*
- * Allow tags from 2 to 12, default 4
+ * Allow tags from 2 to 64, default 8
X */
X #ifdef CONFIG_SCSI_NCR53C8XX_MAX_TAGS
X #if CONFIG_SCSI_NCR53C8XX_MAX_TAGS < 2
X #define SCSI_NCR_MAX_TAGS (2)
-#elif CONFIG_SCSI_NCR53C8XX_MAX_TAGS > 12
-#define SCSI_NCR_MAX_TAGS (12)
+#elif CONFIG_SCSI_NCR53C8XX_MAX_TAGS > 64
+#define SCSI_NCR_MAX_TAGS (64)
X #else
X #define SCSI_NCR_MAX_TAGS CONFIG_SCSI_NCR53C8XX_MAX_TAGS
X #endif
X #else


-#define SCSI_NCR_MAX_TAGS (4)
+#define SCSI_NCR_MAX_TAGS (8)

X #endif
X
X /*
X * Allow tagged command queuing support if configured with default number
X * of tags set to max (see above).
X */
-#ifdef CONFIG_SCSI_NCR53C8XX_TAGGED_QUEUE
+#ifdef CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS
+#define SCSI_NCR_SETUP_DEFAULT_TAGS CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS
+#elif defined CONFIG_SCSI_NCR53C8XX_TAGGED_QUEUE
X #define SCSI_NCR_SETUP_DEFAULT_TAGS SCSI_NCR_MAX_TAGS
X #else
X #define SCSI_NCR_SETUP_DEFAULT_TAGS (0)
@@ -161,16 +146,19 @@
X #define SCSI_NCR_IOMAPPED
X #elif defined(__alpha__) || defined(__powerpc__)
X #define SCSI_NCR_IOMAPPED
+#elif defined(__sparc__)
+#undef SCSI_NCR_IOMAPPED
X #endif
X
X /*
X * Sync transfer frequency at startup.
- * Allow from 5Mhz to 40Mhz default 10 Mhz.
+ * Allow from 5Mhz to 40Mhz default 20 Mhz.
X */
X #ifndef CONFIG_SCSI_NCR53C8XX_SYNC
-#define CONFIG_SCSI_NCR53C8XX_SYNC (5)
+#define CONFIG_SCSI_NCR53C8XX_SYNC (20)
X #elif CONFIG_SCSI_NCR53C8XX_SYNC > SCSI_NCR_MAX_SYNC
-#define SCSI_NCR_SETUP_DEFAULT_SYNC SCSI_NCR_MAX_SYNC
+#undef CONFIG_SCSI_NCR53C8XX_SYNC
+#define CONFIG_SCSI_NCR53C8XX_SYNC SCSI_NCR_MAX_SYNC
X #endif
X
X #if CONFIG_SCSI_NCR53C8XX_SYNC == 0
@@ -245,14 +233,18 @@
X #define SCSI_NCR_ALWAYS_SIMPLE_TAG
X #define SCSI_NCR_MAX_SCATTER (127)
X #define SCSI_NCR_MAX_TARGET (16)
-#define SCSI_NCR_MAX_HOST (2)
-#define SCSI_NCR_TIMEOUT_ALERT (3*HZ)
X
+/* No need to use a too large adapter queue */
+#if SCSI_NCR_MAX_TAGS <= 32
X #define SCSI_NCR_CAN_QUEUE (7*SCSI_NCR_MAX_TAGS)
+#else
+#define SCSI_NCR_CAN_QUEUE (250)
+#endif
+
X #define SCSI_NCR_CMD_PER_LUN (SCSI_NCR_MAX_TAGS)
X #define SCSI_NCR_SG_TABLESIZE (SCSI_NCR_MAX_SCATTER)
X
-#define SCSI_NCR_TIMER_INTERVAL ((HZ+5-1)/5)
+#define SCSI_NCR_TIMER_INTERVAL (HZ)
X
X #if 1 /* defined CONFIG_SCSI_MULTI_LUN */
X #define SCSI_NCR_MAX_LUN (8)
@@ -268,21 +260,12 @@
X
X #if defined(HOSTS_C) || defined(MODULE)
X
-#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,98)
X #include <scsi/scsicam.h>
-#else
-#include <linux/scsicam.h>
-#endif
X
X int ncr53c8xx_abort(Scsi_Cmnd *);
X int ncr53c8xx_detect(Scsi_Host_Template *tpnt);
X int ncr53c8xx_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-
-#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,98)
X int ncr53c8xx_reset(Scsi_Cmnd *, unsigned int);
-#else
-int ncr53c8xx_reset(Scsi_Cmnd *);
-#endif
X
X #ifdef MODULE
X int ncr53c8xx_release(struct Scsi_Host *);
@@ -304,34 +287,22 @@
X sg_tablesize: SCSI_NCR_SG_TABLESIZE, \
X cmd_per_lun: SCSI_NCR_CMD_PER_LUN, \
X use_clustering: DISABLE_CLUSTERING}
-
-#elif LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0)
-
-#define NCR53C8XX { NULL, NULL, NULL, NULL, \
- SCSI_NCR_DRIVER_NAME, ncr53c8xx_detect, \
- ncr53c8xx_release, NULL, NULL, \
- ncr53c8xx_queue_command,ncr53c8xx_abort, \
- ncr53c8xx_reset, NULL, scsicam_bios_param, \
- SCSI_NCR_CAN_QUEUE, 7, \
- SCSI_NCR_SG_TABLESIZE, SCSI_NCR_CMD_PER_LUN, \
- 0, 0, DISABLE_CLUSTERING}
X
X #else
X
-#define NCR53C8XX { NULL, NULL, \
+#define NCR53C8XX { NULL, NULL, NULL, NULL, \
X SCSI_NCR_DRIVER_NAME, ncr53c8xx_detect, \
- ncr53c8xx_release, NULL, NULL, \
+ ncr53c8xx_release, NULL, NULL, \
X ncr53c8xx_queue_command,ncr53c8xx_abort, \
X ncr53c8xx_reset, NULL, scsicam_bios_param, \
X SCSI_NCR_CAN_QUEUE, 7, \
X SCSI_NCR_SG_TABLESIZE, SCSI_NCR_CMD_PER_LUN, \
X 0, 0, DISABLE_CLUSTERING}
-
+
X #endif /* LINUX_VERSION_CODE */
X
X #endif /* defined(HOSTS_C) || defined(MODULE) */
X
-
X #ifndef HOSTS_C
X
X /*
@@ -347,13 +318,18 @@
X #error "BIG ENDIAN byte ordering needs kernel version >= 2.1.0"
X #endif
X
-#ifdef __powerpc__
+#if defined(__powerpc__)
X #define inw_l2b inw
X #define inl_l2b inl
X #define outw_b2l outw
X #define outl_b2l outl
+#elif defined(__sparc__)
+#define readw_l2b readw
+#define readl_l2b readl
+#define writew_b2l writew
+#define writel_b2l writel
X #else
-#error "Support for BIG ENDIAN is only available for the PowerPC"
+#error "Support for BIG ENDIAN is only available for PowerPC and SPARC"
X #endif
X
X #else /* Assumed x86 or alpha */
@@ -448,6 +424,10 @@
X #define FE_LDSTR (1<<13)
X #define FE_RAM (1<<14)
X #define FE_CLK80 (1<<15)
+#define FE_RAM8K (1<<16)
+#define FE_64BIT (1<<17)
+#define FE_IO256 (1<<18)
+#define FE_NOPM (1<<19)
X #define FE_CACHE_SET (FE_ERL|FE_CLSE|FE_WRIE|FE_ERMP)
X #define FE_SCSI_SET (FE_WIDE|FE_ULTRA|FE_ULTRA2|FE_DBLR|FE_QUAD|F_CLK80)
X #define FE_SPECIAL_SET (FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM)
@@ -492,7 +472,10 @@
X {PCI_DEVICE_ID_NCR_53C875, 0x01, "875", 6, 16, 5, \
X FE_WIDE|FE_ULTRA|FE_CLK80|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\
X , \
- {PCI_DEVICE_ID_NCR_53C875, 0xff, "875", 6, 16, 5, \
+ {PCI_DEVICE_ID_NCR_53C875, 0x0f, "875", 6, 16, 5, \
+ FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\
+ , \
+ {PCI_DEVICE_ID_NCR_53C875, 0xff, "876", 6, 16, 5, \
X FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\
X , \
X {PCI_DEVICE_ID_NCR_53C875J,0xff, "875J", 6, 16, 5, \
@@ -505,7 +488,8 @@
X FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\
X , \
X {PCI_DEVICE_ID_NCR_53C896, 0xff, "896", 7, 31, 7, \
- FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\
+ FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM|\
+ FE_RAM8K|FE_64BIT|FE_IO256|FE_NOPM}\
X }
X
X /*
@@ -582,94 +566,6 @@
X 1 \
X }
X
-/*
-** Define the table of target capabilities by host and target
-**
-** If you have problems with a scsi device, note the host unit and the
-** corresponding target number.
-**
-** Edit the corresponding entry of the table below and try successively:
-** NQ7_Questionnable
-** NQ7_IdeLike


-**
-** This bitmap is anded with the byte 7 of inquiry data on completion of
-** INQUIRY command.

-** The driver never see the zeroed bits and will ignore the corresponding


-** capabilities of the target.
-*/
-

-#define INQ7_SftRe 1
-#define INQ7_CmdQueue (1<<1) /* Tagged Command */
-#define INQ7_Reserved (1<<2)
-#define INQ7_Linked (1<<3)
-#define INQ7_Sync (1<<4) /* Synchronous Negotiation */
-#define INQ7_WBus16 (1<<5)
-#define INQ7_WBus32 (1<<6)
-#define INQ7_RelAdr (1<<7)
-
-#define INQ7_IdeLike 0
-#define INQ7_Scsi1Like INQ7_IdeLike
-#define INQ7_Perfect 0xff
-#define INQ7_Questionnable ~(INQ7_CmdQueue|INQ7_Sync)
-#define INQ7_VeryQuestionnable \
- ~(INQ7_CmdQueue|INQ7_Sync|INQ7_WBus16|INQ7_WBus32)
-
-#define INQ7_Default INQ7_Perfect
-
-#define NCR53C8XX_TARGET_CAPABILITIES \
-/* Host 0 */ \
-{ \
- { \
- /* Target 0 */ INQ7_Default, \
- /* Target 1 */ INQ7_Default, \
- /* Target 2 */ INQ7_Default, \
- /* Target 3 */ INQ7_Default, \
- /* Target 4 */ INQ7_Default, \
- /* Target 5 */ INQ7_Default, \
- /* Target 6 */ INQ7_Default, \
- /* Target 7 */ INQ7_Default, \
- /* Target 8 */ INQ7_Default, \
- /* Target 9 */ INQ7_Default, \
- /* Target 10 */ INQ7_Default, \
- /* Target 11 */ INQ7_Default, \
- /* Target 12 */ INQ7_Default, \
- /* Target 13 */ INQ7_Default, \
- /* Target 14 */ INQ7_Default, \
- /* Target 15 */ INQ7_Default, \
- } \
-}, \
-/* Host 1 */ \
-{ \
- { \
- /* Target 0 */ INQ7_Default, \
- /* Target 1 */ INQ7_Default, \
- /* Target 2 */ INQ7_Default, \
- /* Target 3 */ INQ7_Default, \
- /* Target 4 */ INQ7_Default, \
- /* Target 5 */ INQ7_Default, \
- /* Target 6 */ INQ7_Default, \
- /* Target 7 */ INQ7_Default, \
- /* Target 8 */ INQ7_Default, \
- /* Target 9 */ INQ7_Default, \
- /* Target 10 */ INQ7_Default, \
- /* Target 11 */ INQ7_Default, \
- /* Target 12 */ INQ7_Default, \
- /* Target 13 */ INQ7_Default, \
- /* Target 14 */ INQ7_Default, \
- /* Target 15 */ INQ7_Default, \
- } \
-}
-
-/*
-** Replace the proc_dir_entry of the standard ncr driver.
-*/
-
-#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0)
-#if defined(CONFIG_SCSI_NCR53C7xx) || !defined(CONFIG_SCSI_NCR53C8XX)
-#define PROC_SCSI_NCR53C8XX PROC_SCSI_NCR53C7xx
-#endif
-#endif
-
X /**************** ORIGINAL CONTENT of ncrreg.h from FreeBSD ******************/
X
X /*-----------------------------------------------------------------
@@ -794,7 +690,11 @@
X /*28*/ u_int32 nc_dnad; /* ### Next command register */
X /*2c*/ u_int32 nc_dsp; /* --> Script Pointer */
X /*30*/ u_int32 nc_dsps; /* --> Script pointer save/opcode#2 */
-/*34*/ u_int32 nc_scratcha; /* ??? Temporary register a */
+
+/*34*/ u_char nc_scratcha; /* Temporary register a */
+/*35*/ u_char nc_scratcha1;
+/*36*/ u_char nc_scratcha2;
+/*37*/ u_char nc_scratcha3;
X
X /*38*/ u_char nc_dmode;
X #define BL_2 0x80 /* mod: burst length shift value +2 */
@@ -868,7 +768,20 @@
X
X /*53*/ u_char nc_53_;
X /*54*/ u_short nc_sodl; /* Lowlevel: data out to scsi data */
-/*56*/ u_short nc_56_;
+/*56*/ u_char nc_ccntl0; /* Chip Control 0 (896) */
+ #define ENPMJ 0x80 /* Enable Phase Mismatch Jump */
+ #define PMJCTL 0x40 /* Phase Mismatch Jump Control */
+ #define ENNDJ 0x20 /* Enable Non Data PM Jump */
+ #define DISFC 0x10 /* Disable Auto FIFO Clear */
+ #define DILS 0x02 /* Disable Internal Load/Store */
+ #define DPR 0x01 /* Disable Pipe Req */
+
+/*57*/ u_char nc_ccntl1; /* Chip Control 1 (896) */
+ #define ZMOD 0x80 /* High Impedance Mode */
+ #define DDAC 0x08 /* Disable Dual Address Cycle */
+ #define XTIMOD 0x04 /* 64-bit Table Ind. Indexing Mode */
+ #define EXTIBMV 0x02 /* Enable 64-bit Table Ind. BMOV */
+ #define EXDBMV 0x01 /* Enable 64-bit Direct BMOV */
X /*58*/ u_short nc_sbdl; /* Lowlevel: data from scsi data */
X /*5a*/ u_short nc_5a_;
X /*5c*/ u_char nc_scr0; /* Working register B */
@@ -1073,10 +986,10 @@
X
X /*-----------------------------------------------------------
X **
-** FROM_REG (reg) reg = SFBR
+** FROM_REG (reg) SFBR = reg
X ** << 0 >>
X **
-** TO_REG (reg) SFBR = reg
+** TO_REG (reg) reg = SFBR
X ** << 0 >>
X **
X ** LOAD_REG (reg, data) reg = <data>
@@ -1102,6 +1015,42 @@
X
X /*-----------------------------------------------------------
X **
+** LOAD from memory to register.
+** STORE from register to memory.
+**
+**-----------------------------------------------------------
+**
+** LOAD_ABS (LEN)
+** <<start address>>
+**
+** LOAD_REL (LEN) (DSA relative)
+** <<dsa_offset>>
+**
+**-----------------------------------------------------------
+*/
+
+#define SCR_NO_FLUSH2 0x02000000
+#define SCR_DSA_REL2 0x10000000
+
+#define SCR_LOAD_R(reg, how, n) \
+ (0xe1000000 | how | (SCR_REG_OFS(REG(reg))) | (n))
+
+#define SCR_STORE_R(reg, how, n) \
+ (0xe0000000 | how | (SCR_REG_OFS(REG(reg))) | (n))
+
+#define SCR_LOAD_ABS(reg, n) SCR_LOAD_R(reg, SCR_NO_FLUSH2, n)
+#define SCR_LOAD_REL(reg, n) SCR_LOAD_R(reg, SCR_NO_FLUSH2|SCR_DSA_REL2, n)
+#define SCR_LOAD_ABS_F(reg, n) SCR_LOAD_R(reg, 0, n)
+#define SCR_LOAD_REL_F(reg, n) SCR_LOAD_R(reg, SCR_DSA_REL2, n)
+
+#define SCR_STORE_ABS(reg, n) SCR_STORE_R(reg, SCR_NO_FLUSH2, n)
+#define SCR_STORE_REL(reg, n) SCR_STORE_R(reg, SCR_NO_FLUSH2|SCR_DSA_REL2,n)
+#define SCR_STORE_ABS_F(reg, n) SCR_STORE_R(reg, 0, n)
+#define SCR_STORE_REL_F(reg, n) SCR_STORE_R(reg, SCR_DSA_REL2, n)
+
+
+/*-----------------------------------------------------------
+**
X ** Waiting for Disconnect or Reselect
X **
X **-----------------------------------------------------------
@@ -1136,7 +1085,7 @@
X **-----------------------------------------------------------
X */
X
-#define SCR_NO_OP 0x80000000
+#define SCR_NO_OP 0x80000000
X #define SCR_JUMP 0x80080000
X #define SCR_JUMPR 0x80880000
X #define SCR_CALL 0x88080000
diff -u --recursive --new-file v2.0.36/linux/drivers/scsi/pci2000.c linux/drivers/scsi/pci2000.c
--- v2.0.36/linux/drivers/scsi/pci2000.c Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/pci2000.c Sun Jun 13 10:21:02 1999
@@ -0,0 +1,716 @@
+/*+M*************************************************************************
+ * Perceptive Solutions, Inc. PCI-2000 device driver proc support for Linux.
+ *
+ * Copyright (c) 1997 Perceptive Solutions, Inc.


+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *

+ * File Name: pci2000i.c
+ *
+ * Revisions 1.10 Jan-21-1999
+ *
+ * - Fixed sign on message to reflect proper controller name.
+ * - Added support for RAID status monitoring and control.
+ *
+ *-M*************************************************************************/
+#define PCI2000_VERSION "1.10"
+
+#include <linux/module.h>


+
+#include <linux/kernel.h>
+#include <linux/head.h>
+#include <linux/types.h>
+#include <linux/string.h>

+#include <linux/bios32.h>
+#include <linux/pci.h>


+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/sched.h>

+#include <linux/proc_fs.h>
+#include <asm/dma.h>
+#include <asm/system.h>
+#include <asm/io.h>


+#include <linux/blk.h>
+#include "scsi.h"
+#include "hosts.h"
+

+#include "pci2000.h"
+#include "psi_roy.h"
+
+#include<linux/stat.h>
+
+struct proc_dir_entry Proc_Scsi_Pci2000 =
+ { PROC_SCSI_PCI2000, 7, "pci2000", S_IFDIR | S_IRUGO | S_IXUGO, 2 };
+
+//#define DEBUG 1
+
+#ifdef DEBUG
+#define DEB(x) x
+#define STOP_HERE {int st;for(st=0;st<100;st++){st=1;}}
+#else
+#define DEB(x)
+#define STOP_HERE
+#endif
+
+typedef struct
+ {
+ ULONG address;
+ ULONG length;
+ } SCATGATH, *PSCATGATH;
+
+typedef struct
+ {
+ Scsi_Cmnd *SCpnt;
+ SCATGATH scatGath[16];
+ UCHAR tag;
+ } DEV2000, *PDEV2000;
+
+typedef struct
+ {
+ USHORT basePort;
+ USHORT mb0;
+ USHORT mb1;
+ USHORT mb2;
+ USHORT mb3;
+ USHORT mb4;
+ USHORT cmd;
+ USHORT tag;
+ DEV2000 dev[MAX_BUS][MAX_UNITS];
+ } ADAPTER2000, *PADAPTER2000;
+
+#define HOSTDATA(host) ((PADAPTER2000)&host->hostdata)
+
+
+static struct Scsi_Host *PsiHost[MAXADAPTER] = {NULL,}; // One for each adapter
+static int NumAdapters = 0;
+/****************************************************************
+ * Name: WaitReady :LOCAL
+ *
+ * Description: Wait for controller ready.
+ *
+ * Parameters: padapter - Pointer adapter data structure.
+ *
+ * Returns: TRUE on not ready.
+ *
+ ****************************************************************/
+static int WaitReady (PADAPTER2000 padapter)
+ {
+ ULONG timer;
+
+ timer = jiffies + TIMEOUT_COMMAND; // calculate the timeout value
+ do {
+ if ( !inb_p (padapter->cmd) )
+ return FALSE;
+ } while ( timer > jiffies ); // test for timeout
+ return TRUE;
+ }
+/****************************************************************
+ * Name: OpDone :LOCAL
+ *
+ * Description: Clean up operation and issue done to caller.
+ *
+ * Parameters: SCpnt - Pointer to SCSI command structure.
+ * status - Caller status.
+ *
+ * Returns: Nothing.
+ *
+ ****************************************************************/
+static void OpDone (Scsi_Cmnd *SCpnt, ULONG status)
+ {
+ SCpnt->result = status;
+ SCpnt->scsi_done (SCpnt);
+ }
+/****************************************************************
+ * Name: Command :LOCAL
+ *
+ * Description: Issue queued command to the PCI-2000.
+ *
+ * Parameters: padapter - Pointer to adapter information structure.
+ * cmd - PCI-2000 command byte.
+ *
+ * Returns: Non-zero command tag if operation is accepted.
+ *
+ ****************************************************************/
+static UCHAR Command (PADAPTER2000 padapter, UCHAR cmd)
+ {
+ outb_p (cmd, padapter->cmd);
+ if ( WaitReady (padapter) )
+ return 0;
+
+ if ( inw_p (padapter->mb0) )
+ return 0;
+
+ return inb_p (padapter->mb1);
+ }
+/****************************************************************
+ * Name: BuildSgList :LOCAL
+ *
+ * Description: Build the scatter gather list for controller.
+ *
+ * Parameters: SCpnt - Pointer to SCSI command structure.
+ * padapter - Pointer to adapter information structure.
+ * pdev - Pointer to adapter device structure.
+ *
+ * Returns: Non-zero in not scatter gather.
+ *
+ ****************************************************************/
+static int BuildSgList (Scsi_Cmnd *SCpnt, PADAPTER2000 padapter, PDEV2000 pdev)
+ {
+ int z;
+
+ if ( SCpnt->use_sg )
+ {
+ for ( z = 0; z < SCpnt->use_sg; z++ )
+ {
+ pdev->scatGath[z].address = virt_to_bus (((struct scatterlist *)SCpnt->request_buffer)[z].address);
+ pdev->scatGath[z].length = ((struct scatterlist *)SCpnt->request_buffer)[z].length;
+ }
+ outl (virt_to_bus (pdev->scatGath), padapter->mb2);
+ outl ((SCpnt->use_sg << 24) | SCpnt->request_bufflen, padapter->mb3);
+ return FALSE;
+ }
+ outl (virt_to_bus (SCpnt->request_buffer), padapter->mb2);
+ outl (SCpnt->request_bufflen, padapter->mb3);
+ return TRUE;
+ }
+/*********************************************************************
+ * Name: PsiRaidCmd
+ *
+ * Description: Execute a simple command.
+ *
+ * Parameters: padapter - Pointer to adapter control structure.
+ * cmd - Roy command byte.
+ *
+ * Returns: Return error status.
+ *
+ ********************************************************************/
+static int PsiRaidCmd (PADAPTER2000 padapter, char cmd)
+ {
+ if ( WaitReady (padapter) ) // test for command register ready
+ return DID_TIME_OUT;
+ outb_p (cmd, padapter->cmd); // issue command
+ if ( WaitReady (padapter) ) // wait for adapter ready
+ return DID_TIME_OUT;
+ return DID_OK;
+ }
+/****************************************************************
+ * Name: Irq_Handler :LOCAL
+ *
+ * Description: Interrupt handler.
+ *
+ * Parameters: irq - Hardware IRQ number.
+ * dev_id -
+ * regs -
+ *
+ * Returns: TRUE if drive is not ready in time.
+ *
+ ****************************************************************/
+static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
+ {
+ struct Scsi_Host *shost = NULL; // Pointer to host data block
+ PADAPTER2000 padapter; // Pointer to adapter control structure
+ PDEV2000 pdev;
+ Scsi_Cmnd *SCpnt;
+ UCHAR tag = 0;
+ UCHAR tag0;
+ ULONG error;
+ int pun;
+ int bus;
+ int z;
+
+ DEB(printk ("\npci2000 recieved interrupt "));
+ for ( z = 0; z < NumAdapters; z++ ) // scan for interrupt to process
+ {
+ if ( PsiHost[z]->irq == (UCHAR)(irq & 0xFF) )
+ {
+ tag = inb_p (HOSTDATA(PsiHost[z])->tag);
+ if ( tag )
+ {
+ shost = PsiHost[z];
+ break;
+ }
+ }
+ }
+
+ if ( !shost )
+ {
+ DEB (printk ("\npci2000: not my interrupt"));
+ return;
+ }
+
+ padapter = HOSTDATA(shost);
+
+ tag0 = tag & 0x7F; // mask off the error bit
+ for ( bus = 0; bus < MAX_BUS; bus++ ) // scan the busses
+ {
+ for ( pun = 0; pun < MAX_UNITS; pun++ ) // scan the targets
+ {
+ pdev = &padapter->dev[bus][pun];
+ if ( !pdev->tag )
+ continue;
+ if ( pdev->tag == tag0 ) // is this it?
+ {
+ pdev->tag = 0;
+ SCpnt = pdev->SCpnt;
+ goto irqProceed;
+ }
+ }
+ }
+
+ outb_p (0xFF, padapter->tag); // clear the op interrupt
+ outb_p (CMD_DONE, padapter->cmd); // complete the op
+ return; // done, but, with what?
+
+irqProceed:;
+ if ( tag & ERR08_TAGGED ) // is there an error here?
+ {
+ if ( WaitReady (padapter) )
+ {
+ OpDone (SCpnt, DID_TIME_OUT << 16);
+ return;
+ }
+
+ outb_p (tag0, padapter->mb0); // get real error code
+ outb_p (CMD_ERROR, padapter->cmd);
+ if ( WaitReady (padapter) ) // wait for controller to suck up the op
+ {
+ OpDone (SCpnt, DID_TIME_OUT << 16);
+ return;
+ }
+
+ error = inl (padapter->mb0); // get error data
+ outb_p (0xFF, padapter->tag); // clear the op interrupt
+ outb_p (CMD_DONE, padapter->cmd); // complete the op
+
+ DEB (printk ("status: %lX ", error));
+ if ( error == 0x00020002 ) // is this error a check condition?
+ {
+ if ( bus ) // are we doint SCSI commands?
+ {
+ OpDone (SCpnt, (DID_OK << 16) | 2);
+ return;
+ }
+ if ( *SCpnt->cmnd == SCSIOP_TEST_UNIT_READY )
+ OpDone (SCpnt, (DRIVER_SENSE << 24) | (DID_OK << 16) | 2); // test caller we have sense data too
+ else
+ OpDone (SCpnt, DID_ERROR << 16);
+ return;
+ }
+ OpDone (SCpnt, DID_ERROR << 16);
+ return;
+ }
+
+ outb_p (0xFF, padapter->tag); // clear the op interrupt
+ outb_p (CMD_DONE, padapter->cmd); // complete the op
+ OpDone (SCpnt, DID_OK << 16);
+ }
+/****************************************************************
+ * Name: Pci2220i_QueueCommand
+ *
+ * Description: Process a queued command from the SCSI manager.
+ *
+ * Parameters: SCpnt - Pointer to SCSI command structure.
+ * done - Pointer to done function to call.
+ *
+ * Returns: Status code.
+ *
+ ****************************************************************/
+int Pci2000_QueueCommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
+ {
+ UCHAR *cdb = (UCHAR *)SCpnt->cmnd; // Pointer to SCSI CDB
+ PADAPTER2000 padapter = HOSTDATA(SCpnt->host); // Pointer to adapter control structure
+ int rc = -1; // command return code
+ UCHAR bus = SCpnt->channel;
+ UCHAR pun = SCpnt->target;
+ UCHAR lun = SCpnt->lun;
+ UCHAR cmd;
+ PDEV2000 pdev = &padapter->dev[bus][pun];
+
+ if ( !done )
+ {
+ printk("pci2000_queuecommand: %02X: done can't be NULL\n", *cdb);


+ return 0;
+ }
+

+ SCpnt->scsi_done = done;

+ pdev->SCpnt = SCpnt; // Save this command data
+
+ if ( WaitReady (padapter) )
+ {
+ rc = DID_ERROR;
+ goto finished;
+ }
+
+ outw_p (pun | (lun << 8), padapter->mb0);
+
+ if ( bus )
+ {
+ DEB (if(*cdb) printk ("\nCDB: %X- %X %X %X %X %X %X %X %X %X %X ", SCpnt->cmd_len, cdb[0], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5], cdb[6], cdb[7], cdb[8], cdb[9]));
+ DEB (if(*cdb) printk ("\ntimeout_per_command: %d, timeout_total: %d, timeout: %d, internal_timout: %d", SCpnt->timeout_per_command,
+ SCpnt->timeout_total, SCpnt->timeout, SCpnt->internal_timeout));
+ outl (SCpnt->timeout_per_command, padapter->mb1);
+ outb_p (CMD_SCSI_TIMEOUT, padapter->cmd);
+ if ( WaitReady (padapter) )
+ {
+ rc = DID_ERROR;
+ goto finished;
+ }
+
+ outw_p (pun | (lun << 8), padapter->mb0);
+ outw_p (SCpnt->cmd_len << 8, padapter->mb0 + 2);
+ outl (virt_to_bus (cdb), padapter->mb1);
+ if ( BuildSgList (SCpnt, padapter, pdev) )
+ cmd = CMD_SCSI_THRU;
+ else
+ cmd = CMD_SCSI_THRU_SG;
+ if ( (pdev->tag = Command (padapter, cmd)) == 0 )
+ rc = DID_TIME_OUT;
+ goto finished;
+ }
+ else
+ {
+ if ( lun )
+ {
+ rc = DID_BAD_TARGET;
+ goto finished;
+ }
+ }
+
+ switch ( *cdb )
+ {
+ case SCSIOP_INQUIRY: // inquiry CDB
+ if ( cdb[2] == SC_MY_RAID )
+ {
+ switch ( cdb[3] )
+ {
+ case MY_SCSI_REBUILD:
+ OpDone (SCpnt, PsiRaidCmd (padapter, CMD_RAID_REBUILD) << 16);
+ return 0;
+ case MY_SCSI_ALARMMUTE:
+ OpDone (SCpnt, PsiRaidCmd (padapter, CMD_RAID_MUTE) << 16);
+ return 0;
+ case MY_SCSI_DEMOFAIL:
+ OpDone (SCpnt, PsiRaidCmd (padapter, CMD_RAID_FAIL) << 16);


+ return 0;
+ default:

+ if ( SCpnt->use_sg )
+ {
+ rc = DID_ERROR;
+ goto finished;
+ }
+ else
+ outl (virt_to_bus (SCpnt->request_buffer), padapter->mb2);
+ outl (cdb[5], padapter->mb0);
+ outl (cdb[3], padapter->mb3);
+ cmd = CMD_DASD_RAID_RQ;
+ break;
+ }
+ break;
+ }
+
+ if ( SCpnt->use_sg )
+ {
+ outl (virt_to_bus (((struct scatterlist *)(SCpnt->request_buffer))->address), padapter->mb2);
+ }
+ else
+ {
+ outl (virt_to_bus (SCpnt->request_buffer), padapter->mb2);
+ }
+ outl (SCpnt->request_bufflen, padapter->mb3);
+ cmd = CMD_DASD_SCSI_INQ;
+ break;
+
+ case SCSIOP_TEST_UNIT_READY: // test unit ready CDB
+ outl (virt_to_bus (SCpnt->sense_buffer), padapter->mb2);
+ outl (sizeof (SCpnt->sense_buffer), padapter->mb3);
+ cmd = CMD_TEST_READY;
+ break;
+
+ case SCSIOP_READ_CAPACITY: // read capctiy CDB
+ if ( SCpnt->use_sg )
+ {
+ outl (virt_to_bus (((struct scatterlist *)(SCpnt->request_buffer))->address), padapter->mb2);
+ }
+ else
+ {
+ outl (virt_to_bus (SCpnt->request_buffer), padapter->mb2);
+ }
+ outl (8, padapter->mb3);
+ cmd = CMD_DASD_CAP;
+ break;
+ case SCSIOP_VERIFY: // verify CDB
+ outw_p ((USHORT)cdb[8] | ((USHORT)cdb[7] << 8), padapter->mb0 + 2);
+ outl (XSCSI2LONG (&cdb[2]), padapter->mb1);
+ cmd = CMD_READ_SG;
+ break;
+ case SCSIOP_READ: // read10 CDB
+ outw_p ((USHORT)cdb[8] | ((USHORT)cdb[7] << 8), padapter->mb0 + 2);
+ outl (XSCSI2LONG (&cdb[2]), padapter->mb1);
+ if ( BuildSgList (SCpnt, padapter, pdev) )
+ cmd = CMD_READ;
+ else
+ cmd = CMD_READ_SG;
+ break;
+ case SCSIOP_READ6: // read6 CDB
+ outw_p (cdb[4], padapter->mb0 + 2);
+ outl ((SCSI2LONG (&cdb[1])) & 0x001FFFFF, padapter->mb1);
+ if ( BuildSgList (SCpnt, padapter, pdev) )
+ cmd = CMD_READ;
+ else
+ cmd = CMD_READ_SG;
+ break;
+ case SCSIOP_WRITE: // write10 CDB
+ outw_p ((USHORT)cdb[8] | ((USHORT)cdb[7] << 8), padapter->mb0 + 2);
+ outl (XSCSI2LONG (&cdb[2]), padapter->mb1);
+ if ( BuildSgList (SCpnt, padapter, pdev) )
+ cmd = CMD_WRITE;
+ else
+ cmd = CMD_WRITE_SG;
+ break;
+ case SCSIOP_WRITE6: // write6 CDB
+ outw_p (cdb[4], padapter->mb0 + 2);
+ outl ((SCSI2LONG (&cdb[1])) & 0x001FFFFF, padapter->mb1);
+ if ( BuildSgList (SCpnt, padapter, pdev) )
+ cmd = CMD_WRITE;
+ else
+ cmd = CMD_WRITE_SG;
+ break;
+ case SCSIOP_START_STOP_UNIT:
+ cmd = CMD_EJECT_MEDIA;
+ break;
+ case SCSIOP_MEDIUM_REMOVAL:
+ switch ( cdb[4] )
+ {
+ case 0:
+ cmd = CMD_UNLOCK_DOOR;


+ break;
+ case 1:

+ cmd = CMD_LOCK_DOOR;
+ break;
+ default:
+ cmd = 0;
+ break;
+ }
+ if ( cmd )
+ break;
+ default:
+ DEB (printk ("pci2220i_queuecommand: Unsupported command %02X\n", *cdb));
+ OpDone (SCpnt, DID_ERROR << 16);
+ return 0;
+ }
+
+ if ( (pdev->tag = Command (padapter, cmd)) == 0 )
+ rc = DID_TIME_OUT;
+finished:;
+ if ( rc != -1 )
+ OpDone (SCpnt, rc << 16);
+ return 0;
+ }
+/****************************************************************
+ * Name: internal_done :LOCAL
+ *
+ * Description: Done handler for non-queued commands
+ *
+ * Parameters: SCpnt - Pointer to SCSI command structure.
+ *
+ * Returns: Nothing.
+ *
+ ****************************************************************/


+static void internal_done (Scsi_Cmnd * SCpnt)

+ {
+ SCpnt->SCp.Status++;
+ }

+/****************************************************************
+ * Name: Pci2220i_Command
+ *
+ * Description: Process a command from the SCSI manager.
+ *
+ * Parameters: SCpnt - Pointer to SCSI command structure.
+ *
+ * Returns: Status code.
+ *
+ ****************************************************************/
+int Pci2000_Command (Scsi_Cmnd *SCpnt)
+ {
+ DEB(printk("pci2000_command: ..calling pci2000_queuecommand\n"));
+
+ Pci2000_QueueCommand (SCpnt, internal_done);


+
+ SCpnt->SCp.Status = 0;
+ while (!SCpnt->SCp.Status)
+ barrier ();
+ return SCpnt->result;
+ }

+/****************************************************************
+ * Name: Pci2220i_Detect
+ *
+ * Description: Detect and initialize our boards.
+ *
+ * Parameters: tpnt - Pointer to SCSI host template structure.
+ *
+ * Returns: Number of adapters found.
+ *
+ ****************************************************************/
+int Pci2000_Detect (Scsi_Host_Template *tpnt)
+ {


+ int pci_index = 0;

+ struct Scsi_Host *pshost;
+ PADAPTER2000 padapter;
+ int z, zz;
+ int setirq;
+
+ if ( pcibios_present () )
+ {
+ for ( pci_index = 0; pci_index <= MAXADAPTER; ++pci_index )
+ {
+ UCHAR pci_bus, pci_device_fn;
+
+ if ( pcibios_find_device (VENDOR_PSI, DEVICE_ROY_1, pci_index, &pci_bus, &pci_device_fn) != 0 )
+ break;
+
+ pshost = scsi_register (tpnt, sizeof(ADAPTER2000));
+ padapter = HOSTDATA(pshost);
+
+ pcibios_read_config_word (pci_bus, pci_device_fn, PCI_BASE_ADDRESS_1, &padapter->basePort);
+ padapter->basePort &= 0xFFFE;
+ DEB (printk ("\nBase Regs = %#04X", padapter->basePort)); // get the base I/O port address
+ padapter->mb0 = padapter->basePort + RTR_MAILBOX; // get the 32 bit mail boxes
+ padapter->mb1 = padapter->basePort + RTR_MAILBOX + 4;
+ padapter->mb2 = padapter->basePort + RTR_MAILBOX + 8;
+ padapter->mb3 = padapter->basePort + RTR_MAILBOX + 12;
+ padapter->mb4 = padapter->basePort + RTR_MAILBOX + 16;
+ padapter->cmd = padapter->basePort + RTR_LOCAL_DOORBELL; // command register
+ padapter->tag = padapter->basePort + RTR_PCI_DOORBELL; // tag/response register
+
+ if ( WaitReady (padapter) )
+ goto unregister;
+ outb_p (0x84, padapter->mb0);
+ outb_p (CMD_SPECIFY, padapter->cmd);
+ if ( WaitReady (padapter) )
+ goto unregister;
+
+ pcibios_read_config_byte (pci_bus, pci_device_fn, PCI_INTERRUPT_LINE, &pshost->irq);
+ setirq = 1;
+ for ( z = 0; z < pci_index; z++ ) // scan for shared interrupts
+ {
+ if ( PsiHost[z]->irq == pshost->irq ) // if shared then, don't posses
+ setirq = 0;
+ }
+ if ( setirq ) // if not shared, posses
+ {
+ if ( request_irq (pshost->irq, Irq_Handler, 0, "pci2000", NULL) )
+ {
+ printk ("Unable to allocate IRQ for PSI-2000 controller.\n");
+ goto unregister;
+ }
+ }
+ PsiHost[pci_index] = pshost; // save SCSI_HOST pointer
+
+ pshost->unique_id = padapter->basePort;
+ pshost->max_id = 16;
+ pshost->max_channel = 1;
+
+ for ( zz = 0; zz < MAX_BUS; zz++ )
+ for ( z = 0; z < MAX_UNITS; z++ )
+ padapter->dev[zz][z].tag = 0;
+
+ printk("\nPSI-2000 Intelligent Storage SCSI CONTROLLER: at I/O = %X IRQ = %d\n", padapter->basePort, pshost->irq);
+ printk("Version %s, Compiled %s %s\n\n", PCI2000_VERSION, __DATE__, __TIME__);
+ continue;
+unregister:;
+ scsi_unregister (pshost);
+ }
+ }
+ NumAdapters = pci_index;
+ return pci_index;
+ }
+/****************************************************************
+ * Name: Pci2220i_Abort
+ *
+ * Description: Process the Abort command from the SCSI manager.
+ *
+ * Parameters: SCpnt - Pointer to SCSI command structure.
+ *
+ * Returns: Allways snooze.
+ *
+ ****************************************************************/
+int Pci2000_Abort (Scsi_Cmnd *SCpnt)
+ {
+ DEB (printk ("pci2000_abort\n"));
+ return SCSI_ABORT_SNOOZE;
+ }
+/****************************************************************
+ * Name: Pci2220i_Reset
+ *
+ * Description: Process the Reset command from the SCSI manager.
+ *
+ * Parameters: SCpnt - Pointer to SCSI command structure.
+ * flags - Flags about the reset command
+ *
+ * Returns: No active command at this time, so this means
+ * that each time we got some kind of response the
+ * last time through. Tell the mid-level code to
+ * request sense information in order to decide what
+ * to do next.
+ *
+ ****************************************************************/
+int Pci2000_Reset (Scsi_Cmnd *SCpnt, unsigned int reset_flags)
+ {
+ return SCSI_RESET_PUNT;
+ }
+
+#include "sd.h"
+
+/****************************************************************
+ * Name: Pci2220i_BiosParam
+ *
+ * Description: Process the biosparam request from the SCSI manager to
+ * return C/H/S data.
+ *
+ * Parameters: disk - Pointer to SCSI disk structure.
+ * dev - Major/minor number from kernel.
+ * geom - Pointer to integer array to place geometry data.
+ *
+ * Returns: zero.
+ *
+ ****************************************************************/
+int Pci2000_BiosParam (Scsi_Disk *disk, kdev_t dev, int geom[])
+ {
+ PADAPTER2000 padapter;
+
+ padapter = HOSTDATA(disk->device->host);
+
+ if ( WaitReady (padapter) )
+ return 0;
+ outb_p (disk->device->id, padapter->mb0);
+ outb_p (CMD_GET_PARMS, padapter->cmd);
+ if ( WaitReady (padapter) )
+ return 0;
+
+ geom[0] = inb_p (padapter->mb2 + 3);
+ geom[1] = inb_p (padapter->mb2 + 2);
+ geom[2] = inw_p (padapter->mb2);


+ return 0;
+ }
+
+

+#ifdef MODULE
+/* Eventually this will go into an include file, but this will be later */
+Scsi_Host_Template driver_template = PCI2000;
+
+#include "scsi_module.c"
+#endif
+
diff -u --recursive --new-file v2.0.36/linux/drivers/scsi/pci2000.h linux/drivers/scsi/pci2000.h
--- v2.0.36/linux/drivers/scsi/pci2000.h Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/pci2000.h Sun Jun 13 10:21:02 1999
@@ -0,0 +1,226 @@
+/*+M*************************************************************************
+ * Perceptive Solutions, Inc. PCI-2000 device driver proc support for Linux.
+ *
+ * Copyright (c) 1997 Perceptive Solutions, Inc.


+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *

+ * File Name: pci2000.h
+ *
+ * Description: Header file for the SCSI driver for the PCI-2000
+ * interface card.
+ *
+ *-M*************************************************************************/
+#ifndef _PCI2000_H
+#define _PCI2000_H
+
+#include <linux/types.h>
+#include <linux/kdev_t.h>
+
+#ifndef PSI_EIDE_SCSIOP
+#define PSI_EIDE_SCSIOP 1
+
+/************************************************/
+/* definition of standard data types */
+/************************************************/
+#define CHAR char
+#define UCHAR unsigned char
+#define SHORT short
+#define USHORT unsigned short
+#define BOOL long
+#define LONG long
+#define ULONG unsigned long
+#define VOID void
+
+typedef CHAR *PCHAR;
+typedef UCHAR *PUCHAR;
+typedef SHORT *PSHORT;
+typedef USHORT *PUSHORT;
+typedef BOOL *PBOOL;
+typedef LONG *PLONG;
+typedef ULONG *PULONG;
+typedef VOID *PVOID;
+
+
+/************************************************/
+/* Misc. macros */
+/************************************************/
+#define ANY2SCSI(up, p) \
+((UCHAR *)up)[0] = (((ULONG)(p)) >> 8); \
+((UCHAR *)up)[1] = ((ULONG)(p));
+
+#define SCSI2LONG(up) \
+( (((long)*(((UCHAR *)up))) << 16) \
++ (((long)(((UCHAR *)up)[1])) << 8) \
++ ((long)(((UCHAR *)up)[2])) )
+
+#define XANY2SCSI(up, p) \
+((UCHAR *)up)[0] = ((long)(p)) >> 24; \
+((UCHAR *)up)[1] = ((long)(p)) >> 16; \
+((UCHAR *)up)[2] = ((long)(p)) >> 8; \
+((UCHAR *)up)[3] = ((long)(p));
+
+#define XSCSI2LONG(up) \
+( (((long)(((UCHAR *)up)[0])) << 24) \
++ (((long)(((UCHAR *)up)[1])) << 16) \
++ (((long)(((UCHAR *)up)[2])) << 8) \
++ ((long)(((UCHAR *)up)[3])) )
+
+/************************************************/
+/* SCSI CDB operation codes */
+/************************************************/
+#define SCSIOP_TEST_UNIT_READY 0x00
+#define SCSIOP_REZERO_UNIT 0x01
+#define SCSIOP_REWIND 0x01
+#define SCSIOP_REQUEST_BLOCK_ADDR 0x02
+#define SCSIOP_REQUEST_SENSE 0x03
+#define SCSIOP_FORMAT_UNIT 0x04
+#define SCSIOP_READ_BLOCK_LIMITS 0x05
+#define SCSIOP_REASSIGN_BLOCKS 0x07
+#define SCSIOP_READ6 0x08
+#define SCSIOP_RECEIVE 0x08
+#define SCSIOP_WRITE6 0x0A
+#define SCSIOP_PRINT 0x0A
+#define SCSIOP_SEND 0x0A
+#define SCSIOP_SEEK6 0x0B
+#define SCSIOP_TRACK_SELECT 0x0B
+#define SCSIOP_SLEW_PRINT 0x0B
+#define SCSIOP_SEEK_BLOCK 0x0C
+#define SCSIOP_PARTITION 0x0D
+#define SCSIOP_READ_REVERSE 0x0F
+#define SCSIOP_WRITE_FILEMARKS 0x10
+#define SCSIOP_FLUSH_BUFFER 0x10
+#define SCSIOP_SPACE 0x11
+#define SCSIOP_INQUIRY 0x12
+#define SCSIOP_VERIFY6 0x13
+#define SCSIOP_RECOVER_BUF_DATA 0x14
+#define SCSIOP_MODE_SELECT 0x15
+#define SCSIOP_RESERVE_UNIT 0x16
+#define SCSIOP_RELEASE_UNIT 0x17
+#define SCSIOP_COPY 0x18
+#define SCSIOP_ERASE 0x19
+#define SCSIOP_MODE_SENSE 0x1A
+#define SCSIOP_START_STOP_UNIT 0x1B
+#define SCSIOP_STOP_PRINT 0x1B
+#define SCSIOP_LOAD_UNLOAD 0x1B
+#define SCSIOP_RECEIVE_DIAGNOSTIC 0x1C
+#define SCSIOP_SEND_DIAGNOSTIC 0x1D
+#define SCSIOP_MEDIUM_REMOVAL 0x1E
+#define SCSIOP_READ_CAPACITY 0x25
+#define SCSIOP_READ 0x28
+#define SCSIOP_WRITE 0x2A
+#define SCSIOP_SEEK 0x2B
+#define SCSIOP_LOCATE 0x2B
+#define SCSIOP_WRITE_VERIFY 0x2E
+#define SCSIOP_VERIFY 0x2F
+#define SCSIOP_SEARCH_DATA_HIGH 0x30
+#define SCSIOP_SEARCH_DATA_EQUAL 0x31
+#define SCSIOP_SEARCH_DATA_LOW 0x32
+#define SCSIOP_SET_LIMITS 0x33
+#define SCSIOP_READ_POSITION 0x34
+#define SCSIOP_SYNCHRONIZE_CACHE 0x35
+#define SCSIOP_COMPARE 0x39
+#define SCSIOP_COPY_COMPARE 0x3A
+#define SCSIOP_WRITE_DATA_BUFF 0x3B
+#define SCSIOP_READ_DATA_BUFF 0x3C
+#define SCSIOP_CHANGE_DEFINITION 0x40
+#define SCSIOP_READ_SUB_CHANNEL 0x42
+#define SCSIOP_READ_TOC 0x43
+#define SCSIOP_READ_HEADER 0x44
+#define SCSIOP_PLAY_AUDIO 0x45
+#define SCSIOP_PLAY_AUDIO_MSF 0x47
+#define SCSIOP_PLAY_TRACK_INDEX 0x48
+#define SCSIOP_PLAY_TRACK_RELATIVE 0x49
+#define SCSIOP_PAUSE_RESUME 0x4B
+#define SCSIOP_LOG_SELECT 0x4C
+#define SCSIOP_LOG_SENSE 0x4D
+#define SCSIOP_MODE_SELECT10 0x55
+#define SCSIOP_MODE_SENSE10 0x5A
+#define SCSIOP_LOAD_UNLOAD_SLOT 0xA6
+#define SCSIOP_MECHANISM_STATUS 0xBD
+#define SCSIOP_READ_CD 0xBE
+
+// SCSI read capacity structure
+typedef struct _READ_CAPACITY_DATA
+ {
+ ULONG blks; /* total blocks (converted to little endian) */
+ ULONG blksiz; /* size of each (converted to little endian) */
+ } READ_CAPACITY_DATA, *PREAD_CAPACITY_DATA;
+
+// SCSI inquiry data
+typedef struct _INQUIRYDATA
+ {
+ UCHAR DeviceType :5;
+ UCHAR DeviceTypeQualifier :3;
+ UCHAR DeviceTypeModifier :7;
+ UCHAR RemovableMedia :1;
+ UCHAR Versions;
+ UCHAR ResponseDataFormat;
+ UCHAR AdditionalLength;
+ UCHAR Reserved[2];
+ UCHAR SoftReset :1;
+ UCHAR CommandQueue :1;
+ UCHAR Reserved2 :1;
+ UCHAR LinkedCommands :1;
+ UCHAR Synchronous :1;
+ UCHAR Wide16Bit :1;
+ UCHAR Wide32Bit :1;
+ UCHAR RelativeAddressing :1;
+ UCHAR VendorId[8];
+ UCHAR ProductId[16];
+ UCHAR ProductRevisionLevel[4];
+ UCHAR VendorSpecific[20];
+ UCHAR Reserved3[40];
+ } INQUIRYDATA, *PINQUIRYDATA;
+
+#endif
+
+// function prototypes
+int Pci2000_Detect (Scsi_Host_Template *tpnt);
+int Pci2000_Command (Scsi_Cmnd *SCpnt);
+int Pci2000_QueueCommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *));
+int Pci2000_Abort (Scsi_Cmnd *SCpnt);
+int Pci2000_Reset (Scsi_Cmnd *SCpnt, unsigned int flags);
+int Pci2000_BiosParam (Disk *disk, kdev_t dev, int geom[]);
+
+#ifndef NULL
+ #define NULL 0
+#endif
+
+extern struct proc_dir_entry Proc_Scsi_Pci2000;
+
+#define PCI2000 { NULL, NULL, \
+ &Proc_Scsi_Pci2000,/* proc_dir_entry */ \
+ NULL, \
+ "PCI-2000 SCSI Intelligent Disk Controller",\
+ Pci2000_Detect, \
+ NULL, \
+ NULL, \
+ Pci2000_Command, \
+ Pci2000_QueueCommand, \
+ Pci2000_Abort, \
+ Pci2000_Reset, \
+ NULL, \
+ Pci2000_BiosParam, \
+ 16, \
+ -1, \
+ 16, \


+ 1, \
+ 0, \
+ 0, \

+ DISABLE_CLUSTERING }
+
+#endif
diff -u --recursive --new-file v2.0.36/linux/drivers/scsi/pci2220i.c linux/drivers/scsi/pci2220i.c
--- v2.0.36/linux/drivers/scsi/pci2220i.c Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/pci2220i.c Sun Jun 13 10:21:02 1999
@@ -0,0 +1,819 @@
+/*+M*************************************************************************
+ * Perceptive Solutions, Inc. PCI-2000 device driver proc support for Linux.
+ *
+ * Copyright (c) 1997 Perceptive Solutions, Inc.


+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *

+ * File Name: pci2220i.c
+ *
+ * Description: SCSI driver for the PCI2220I EIDE interface card.
+ *
+ *-M*************************************************************************/
+
+#include <linux/module.h>


+
+#include <linux/kernel.h>
+#include <linux/head.h>
+#include <linux/types.h>
+#include <linux/string.h>

+#include <linux/bios32.h>
+#include <linux/pci.h>


+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/sched.h>

+#include <linux/proc_fs.h>
+#include <asm/dma.h>
+#include <asm/system.h>
+#include <asm/io.h>


+#include <linux/blk.h>
+#include "scsi.h"
+#include "hosts.h"
+

+#include "pci2220i.h"
+#include "psi_dale.h"
+
+#include<linux/stat.h>
+
+struct proc_dir_entry Proc_Scsi_Pci2220i =
+ { PROC_SCSI_PCI2220I, 7, "pci2220i", S_IFDIR | S_IRUGO | S_IXUGO, 2 };
+
+//#define DEBUG 1
+
+#ifdef DEBUG
+#define DEB(x) x
+#define STOP_HERE {int st;for(st=0;st<100;st++){st=1;}}
+#else
+#define DEB(x)
+#define STOP_HERE
+#endif
+
+#define MAXADAPTER 4 /* Increase this and the sizes of the arrays below, if you need more. */
+
+#define MAX_BUS_MASTER_BLOCKS 1 // This is the maximum we can bus master for (1024 bytes)
+
+#define PORT_DATA 0
+#define PORT_ERROR 1
+#define PORT_SECTOR_COUNT 2
+#define PORT_LBA_0 3


SHAR_EOF
true || echo 'restore of patch-2.0.37 failed'
fi

echo 'End of part 34'
echo 'File patch-2.0.37 is continued in part 35'
echo 35 > _shar_seq_.tmp

Thomas...@ciw.uni-karlsruhe.de

unread,
Jun 16, 1999, 3:00:00 AM6/16/99
to
Archive-name: v2.0/patch-2.0.37/part28

#!/bin/sh
# this is part 28 of a 45 - part archive


# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.0.37 continued
if test ! -r _shar_seq_.tmp; then
echo 'Please unpack part 1 first!'
exit 1
fi
(read Scheck

if test "$Scheck" != 28; then


echo Please unpack part "$Scheck" next!
exit 1
else
exit 0
fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.0.37'
else
echo 'x - continuing with patch-2.0.37'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.0.37' &&

+#define ORC_COMMAND 0x04 /* Command */


+#define BUSMS 0x04 /* BUS MASTER Enable */
+#define IOSPA 0x01 /* IO Space Enable */

+#define ORC_STATUS 0x06 /* Status register */
+#define ORC_REVISION 0x08 /* Revision number */
+#define ORC_BASE 0x10 /* Base address */
+#define ORC_BIOS 0x50 /* Expansion ROM base address */
+#define ORC_INT_NUM 0x3C /* Interrupt line */
+#define ORC_INT_PIN 0x3D /* Interrupt pin */
+
+/********************************************************/
+/* Orchid Host Command Set */
+/********************************************************/
+#define ORC_CMD_NOP 0x00 /* Host command - NOP */
+#define ORC_CMD_VERSION 0x01 /* Host command - Get F/W version */
+#define ORC_CMD_ECHO 0x02 /* Host command - ECHO */
+#define ORC_CMD_SET_NVM 0x03 /* Host command - Set NVRAM */
+#define ORC_CMD_GET_NVM 0x04 /* Host command - Get NVRAM */
+#define ORC_CMD_GET_BUS_STATUS 0x05 /* Host command - Get SCSI bus status */
+#define ORC_CMD_ABORT_SCB 0x06 /* Host command - Abort SCB */
+#define ORC_CMD_ISSUE_SCB 0x07 /* Host command - Issue SCB */
+
+/********************************************************/
+/* Orchid Register Set */
+/********************************************************/
+#define ORC_GINTS 0xA0 /* Global Interrupt Status */
+#define QINT 0x04 /* Reply Queue Interrupt */
+#define ORC_GIMSK 0xA1 /* Global Interrupt MASK */
+#define MQINT 0x04 /* Mask Reply Queue Interrupt */
+#define ORC_GCFG 0xA2 /* Global Configure */
+#define EEPRG 0x01 /* Enable EEPROM programming */
+#define ORC_GSTAT 0xA3 /* Global status */
+#define WIDEBUS 0x10 /* Wide SCSI Devices connected */
+#define ORC_HDATA 0xA4 /* Host Data */
+#define ORC_HCTRL 0xA5 /* Host Control */
+#define SCSIRST 0x80 /* SCSI bus reset */
+#define HDO 0x40 /* Host data out */
+#define HOSTSTOP 0x02 /* Host stop RISC engine */
+#define DEVRST 0x01 /* Device reset */
+#define ORC_HSTUS 0xA6 /* Host Status */
+#define HDI 0x02 /* Host data in */
+#define RREADY 0x01 /* RISC engine is ready to receive */
+#define ORC_NVRAM 0xA7 /* Nvram port address */
+#define SE2CS 0x008
+#define SE2CLK 0x004
+#define SE2DO 0x002
+#define SE2DI 0x001
+#define ORC_PQUEUE 0xA8 /* Posting queue FIFO */
+#define ORC_PQCNT 0xA9 /* Posting queue FIFO Cnt */
+#define ORC_RQUEUE 0xAA /* Reply queue FIFO */
+#define ORC_RQUEUECNT 0xAB /* Reply queue FIFO Cnt */
+#define ORC_FWBASEADR 0xAC /* Firmware base address */
+
+#define ORC_EBIOSADR0 0xB0 /* External Bios address */
+#define ORC_EBIOSADR1 0xB1 /* External Bios address */
+#define ORC_EBIOSADR2 0xB2 /* External Bios address */
+#define ORC_EBIOSDATA 0xB3 /* External Bios address */
+
+#define ORC_SCBSIZE 0xB7 /* SCB size register */
+#define ORC_SCBBASE0 0xB8 /* SCB base address 0 */
+#define ORC_SCBBASE1 0xBC /* SCB base address 1 */
+
+#define ORC_RISCCTL 0xE0 /* RISC Control */
+#define PRGMRST 0x002
+#define DOWNLOAD 0x001
+#define ORC_PRGMCTR0 0xE2 /* RISC program counter */
+#define ORC_PRGMCTR1 0xE3 /* RISC program counter */
+#define ORC_RISCRAM 0xEC /* RISC RAM data port 4 bytes */
+
+typedef struct orc_extended_scb { /* Extended SCB */
+ ORC_SG ESCB_SGList[TOTAL_SG_ENTRY]; /*0 Start of SG list */


+ Scsi_Cmnd *SCB_Srb; /*50 SRB Pointer */

+} ESCB;


+
+/***********************************************************************
+ SCSI Control Block
+************************************************************************/

+typedef struct orc_scb { /* Scsi_Ctrl_Blk */
+ UBYTE SCB_Opcode; /*00 SCB command code&residual */
+ UBYTE SCB_Flags; /*01 SCB Flags */
+ UBYTE SCB_Target; /*02 Target Id */
+ UBYTE SCB_Lun; /*03 Lun */
+ U32 SCB_Reserved0; /*04 Reserved for ORCHID must 0 */
+ U32 SCB_XferLen; /*08 Data Transfer Length */
+ U32 SCB_Reserved1; /*0C Reserved for ORCHID must 0 */
+ U32 SCB_SGLen; /*10 SG list # * 8 */
+ U32 SCB_SGPAddr; /*14 SG List Buf physical Addr */
+ U32 SCB_SGPAddrHigh; /*18 SG Buffer high physical Addr */
+ UBYTE SCB_HaStat; /*1C Host Status */
+ UBYTE SCB_TaStat; /*1D Target Status */
+ UBYTE SCB_Status; /*1E SCB status */
+ UBYTE SCB_Link; /*1F Link pointer, default 0xFF */
+ UBYTE SCB_SenseLen; /*20 Sense Allocation Length */
+ UBYTE SCB_CDBLen; /*21 CDB Length */
+ UBYTE SCB_Ident; /*22 Identify */
+ UBYTE SCB_TagMsg; /*23 Tag Message */
+ UBYTE SCB_CDB[IMAX_CDB]; /*24 SCSI CDBs */
+ UBYTE SCB_ScbIdx; /*3C Index for this ORCSCB */
+ U32 SCB_SensePAddr; /*34 Sense Buffer physical Addr */
+
+ ESCB *SCB_EScb; /*38 Extended SCB Pointer */
+#ifndef ALPHA
+ UBYTE SCB_Reserved2[4]; /*3E Reserved for Driver use */
+#endif
+} ORC_SCB;
+
+/* Opcodes of ORCSCB_Opcode */
+#define ORC_EXECSCSI 0x00 /* SCSI initiator command with residual */
+#define ORC_BUSDEVRST 0x01 /* SCSI Bus Device Reset */
+
+/* Status of ORCSCB_Status */
+#define SCB_COMPLETE 0x00 /* SCB request completed */
+#define SCB_POST 0x01 /* SCB is posted by the HOST */
+
+/* Bit Definition for ORCSCB_Flags */
+#define SCF_DISINT 0x01 /* Disable HOST interrupt */
+#define SCF_DIR 0x18 /* Direction bits */
+#define SCF_NO_DCHK 0x00 /* Direction determined by SCSI */
+#define SCF_DIN 0x08 /* From Target to Initiator */
+#define SCF_DOUT 0x10 /* From Initiator to Target */
+#define SCF_NO_XF 0x18 /* No data transfer */
+#define SCF_POLL 0x40
+
+/* Error Codes for ORCSCB_HaStat */


+#define HOST_SEL_TOUT 0x11
+#define HOST_DO_DU 0x12
+#define HOST_BUS_FREE 0x13
+#define HOST_BAD_PHAS 0x14
+#define HOST_INV_CMD 0x16
+#define HOST_SCSI_RST 0x1B
+#define HOST_DEV_RST 0x1C
+
+

+/* Error Codes for ORCSCB_TaStat */
+#define TARGET_CHK_COND 0x02
+#define TARGET_BUSY 0x08
+#define TARGET_TAG_FULL 0x28
+


+
+/* Queue tag msg: Simple_quque_tag, Head_of_queue_tag, Ordered_queue_tag */
+#define MSG_STAG 0x20
+#define MSG_HTAG 0x21
+#define MSG_OTAG 0x22
+

+#define MSG_IGNOREWIDE 0x23
+
+#define MSG_IDENT 0x80

+#define MSG_DISC 0x40 /* Disconnect allowed */
+


+
+/* SCSI MESSAGE */

+#define MSG_EXTEND 0x01
+#define MSG_SDP 0x02

+#define MSG_ABORT 0x06
+#define MSG_REJ 0x07
+#define MSG_NOP 0x08
+#define MSG_PARITY 0x09

+#define MSG_DEVRST 0x0C
+#define MSG_STAG 0x20


+
+/***********************************************************************
+ Target Device Control Structure
+**********************************************************************/
+

+typedef struct ORC_Tar_Ctrl_Struc {
+ UBYTE TCS_DrvDASD; /* 6 */
+ UBYTE TCS_DrvSCSI; /* 7 */
+ UBYTE TCS_DrvHead; /* 8 */


+ UWORD TCS_DrvFlags; /* 4 */

+ UBYTE TCS_DrvSector; /* 7 */

+} ORC_TCS, *PORC_TCS;
+
+/* Bit Definition for TCF_DrvFlags */
+#define TCS_DF_NODASD_SUPT 0x20 /* Suppress OS/2 DASD Mgr support */
+#define TCS_DF_NOSCSI_SUPT 0x40 /* Suppress OS/2 SCSI Mgr support */
+


+
+/***********************************************************************
+ Host Adapter Control Structure
+************************************************************************/

+typedef struct ORC_Ha_Ctrl_Struc {
+ USHORT HCS_Base; /* 00 */
+ UBYTE HCS_Index; /* 02 */


+ UBYTE HCS_Intr; /* 04 */

+ UBYTE HCS_SCSI_ID; /* 06 H/A SCSI ID */
+ UBYTE HCS_BIOS; /* 07 BIOS configuration */
+
+ UBYTE HCS_Flags; /* 0B */
+ UBYTE HCS_HAConfig1; /* 1B SCSI0MAXTags */
+ UBYTE HCS_MaxTar; /* 1B SCSI0MAXTags */
+
+ USHORT HCS_Units; /* Number of units this adapter */
+ USHORT HCS_AFlags; /* Adapter info. defined flags */
+ ULONG HCS_Timeout; /* Adapter timeout value */
+ PVOID HCS_virScbArray; /* 28 Virtual Pointer to SCB array */
+ U32 HCS_physScbArray; /* Scb Physical address */
+ PVOID HCS_virEscbArray; /* Virtual pointer to ESCB Scatter list */
+ U32 HCS_physEscbArray; /* scatter list Physical address */
+ UBYTE TargetFlag[16]; /* 30 target configuration, TCF_EN_TAG */
+ UBYTE MaximumTags[16]; /* 40 ORC_MAX_SCBS */
+ UBYTE ActiveTags[16][16]; /* 50 */
+ ORC_TCS HCS_Tcs[16]; /* 28 */
+ U32 BitAllocFlag[MAX_CHANNELS][8]; /* Max STB is 256, So 256/32 */
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+ spinlock_t BitAllocFlagLock;
+#endif
+ Scsi_Cmnd *pSRB_head;
+ Scsi_Cmnd *pSRB_tail;
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+ spinlock_t pSRB_lock;
+#endif
+} ORC_HCS;
+
+/* Bit Definition for HCS_Flags */
+
+#define HCF_SCSI_RESET 0x01 /* SCSI BUS RESET */
+#define HCF_PARITY 0x02 /* parity card */
+#define HCF_LVDS 0x10 /* parity card */
+
+/* Bit Definition for TargetFlag */
+
+#define TCF_EN_255 0x08
+#define TCF_EN_TAG 0x10
+#define TCF_BUSY 0x20
+#define TCF_DISCONNECT 0x40
+#define TCF_SPIN_UP 0x80
+
+/* Bit Definition for HCS_AFlags */
+#define HCS_AF_IGNORE 0x01 /* Adapter ignore */
+#define HCS_AF_DISABLE_RESET 0x10 /* Adapter disable reset */
+#define HCS_AF_DISABLE_ADPT 0x80 /* Adapter disable */
+
+
+/*---------------------------------------*/
+/* TimeOut for RESET to complete (30s) */
+/* */
+/* After a RESET the drive is checked */
+/* every 200ms. */
+/*---------------------------------------*/
+#define DELAYED_RESET_MAX (30*1000L)
+#define DELAYED_RESET_INTERVAL 200L
+
+/*----------------------------------------------*/
+/* TimeOut for IRQ from last interrupt (5s) */
+/*----------------------------------------------*/
+#define IRQ_TIMEOUT_INTERVAL (5*1000L)
+
+/*----------------------------------------------*/
+/* Retry Delay interval (200ms) */
+/*----------------------------------------------*/
+#define DELAYED_RETRY_INTERVAL 200L
+
+#define INQUIRY_SIZE 36
+#define CAPACITY_SIZE 8
+#define DEFAULT_SENSE_LEN 14
+
+#define DEVICE_NOT_FOUND 0x86
+
+/*----------------------------------------------*/
+/* Definition for PCI device */
+/*----------------------------------------------*/
+#define MAX_PCI_DEVICES 21
+#define MAX_PCI_BUSES 8
diff -u --recursive --new-file v2.0.36/linux/drivers/scsi/megaraid.c linux/drivers/scsi/megaraid.c
--- v2.0.36/linux/drivers/scsi/megaraid.c Sun Nov 15 21:51:47 1998
+++ linux/drivers/scsi/megaraid.c Sun Jun 13 10:21:02 1999
@@ -1,24 +1,27 @@
X /*===================================================================
X *
X * Linux MegaRAID device driver
- *
+ *
X * Copyright 1998 American Megatrends Inc.
X *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.


+ * This program is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
X *
- * Version : 0.92
+ * Version : 0.93
X *
X * Description: Linux device driver for AMI MegaRAID controller
X *
+ * Supported controllers: MegaRAID 418, 428, 438, 466
+ *
+ * Maintainer: Jeff L Jones <jeff...@ami.com>
+ *
X * History:
X *
X * Version 0.90:
- * Works and has been tested with the MegaRAID 428 controller, and
- * the MegaRAID 438 controller. Probably works with the 466 also,
- * but not tested.
+ * Original source contributed by Dell; integrated it into the kernel and
+ * cleaned up some things. Added support for 438/466 controllers.
X *
X * Version 0.91:
X * Aligned mailbox area on 16-byte boundry.
@@ -35,28 +38,33 @@
X * Removed setting of SA_INTERRUPT flag when requesting Irq.
X *
X * Version 0.92ac:
- * Small changes to the comments/formatting. Plus a couple of
- * added notes. Returned to the authors. No actual code changes
- * save printk levels.
- * 8 Oct 98 Alan Cox <alan...@linux.org>
+ * Small changes to the comments/formatting. Plus a couple of
+ * added notes. Returned to the authors. No actual code changes
+ * save printk levels.
+ * 8 Oct 98 Alan Cox <alan...@linux.org>
+ *
+ * Merged with 2.1.131 source tree.
+ * 12 Dec 98 K. Baranowski <k...@knm.org.pl>
+ *
+ * Version 0.93:
+ * Added support for vendor specific ioctl commands (0x80+xxh)
+ * Changed some fields in MEGARAID struct to better values.
+ * Added signature check for Rp controllers under 2.0 kernels
+ * Changed busy-wait loop to be time-based
+ * Fixed SMP race condition in isr
+ * Added kfree (sgList) on release
+ * Added #include linux/version.h to megaraid.h for hosts.h
+ * Changed max_id to represent max logical drives instead of targets.
+ *
X *
X * BUGS:
- * Tested with 2.1.90, but unfortunately there is a bug in pci.c which
- * fails to detect our controller. Does work with 2.1.118--don't know
- * which kernel in between it was fixed in.
- * With SMP enabled under 2.1.118 with more than one processor, gets an
- * error message "scsi_end_request: buffer-list destroyed" under heavy
- * IO, but doesn't seem to affect operation, or data integrity. The
- * message doesn't occur without SMP enabled, or with one proccessor with
- * SMP enabled, or under any combination under 2.0 kernels.
+ * Some older 2.1 kernels (eg. 2.1.90) have a bug in pci.c that
+ * fails to detect the controller as a pci device on the system.
X *
X *===================================================================*/
-#define QISR 1
X
X #define CRLFSTR "\n"
X
-#define MULTIQ 1
-
X #include <linux/config.h>
X #include <linux/version.h>
X
@@ -66,10 +74,8 @@
X #if LINUX_VERSION_CODE >= 0x20100


X char kernel_version[] = UTS_RELEASE;
X

-/* originally ported by Dell Corporation; updated, released, and maintained by
- American Megatrends */
-MODULE_AUTHOR("American Megatrends Inc.");
-MODULE_DESCRIPTION("AMI MegaRAID driver");
+MODULE_AUTHOR ("American Megatrends Inc.");
+MODULE_DESCRIPTION ("AMI MegaRAID driver");


X #endif
X #endif
X

@@ -107,18 +113,21 @@
X
X #include "megaraid.h"
X
-/*================================================================
- *
- * #Defines
- *
- *================================================================*/
+//================================================================
+//
+// #Defines
+//
+//================================================================
X
X #if LINUX_VERSION_CODE < 0x020100
X #define ioremap vremap
X #define iounmap vfree
X
X /* simulate spin locks */
-typedef struct {volatile char lock;} spinlock_t;
+typedef struct {
+ volatile char lock;
+} spinlock_t;
+
X #define spin_lock_init(x) { (x)->lock = 0;}
X #define spin_lock_irqsave(x,flags) { while ((x)->lock) barrier();\
X (x)->lock=1; save_flags(flags);\
@@ -153,125 +162,124 @@
X spin_unlock_irqrestore(&mega_lock,cpuflag);\
X };
X
-u_long RDINDOOR(mega_host_config *megaCfg)
+u_long RDINDOOR (mega_host_config * megaCfg)
X {
- return readl(megaCfg->base + 0x20);
+ return readl (megaCfg->base + 0x20);
X }
X
-void WRINDOOR(mega_host_config *megaCfg, u_long value)
+void WRINDOOR (mega_host_config * megaCfg, u_long value)
X {
- writel(value,megaCfg->base+0x20);
+ writel (value, megaCfg->base + 0x20);
X }
X
-u_long RDOUTDOOR(mega_host_config *megaCfg)
+u_long RDOUTDOOR (mega_host_config * megaCfg)
X {
- return readl(megaCfg->base+0x2C);
+ return readl (megaCfg->base + 0x2C);
X }
X
-void WROUTDOOR(mega_host_config *megaCfg, u_long value)
+void WROUTDOOR (mega_host_config * megaCfg, u_long value)
X {
- writel(value,megaCfg->base+0x2C);
+ writel (value, megaCfg->base + 0x2C);
X }
X
-/*================================================================
- *
- * Function prototypes
- *
- *================================================================*/
-static int MegaIssueCmd(mega_host_config *megaCfg,
- u_char *mboxData,
- mega_scb *scb,
+//================================================================
+//
+// Function prototypes
+//
+//================================================================
+static int MegaIssueCmd (mega_host_config * megaCfg,
+ u_char * mboxData,
+ mega_scb * scb,
X int intr);
-static int build_sglist(mega_host_config *megaCfg, mega_scb *scb,
- u_long *buffer, u_long *length);
+static int build_sglist (mega_host_config * megaCfg, mega_scb * scb,
+ u_long * buffer, u_long * length);
X
-static void mega_runque(void *);
-static void mega_rundoneq(void);
-static void mega_cmd_done(mega_host_config *,mega_scb *, int);
+static void mega_runque (void *);
+static void mega_rundoneq (void);
+static void mega_cmd_done (mega_host_config *, mega_scb *, int);
+static mega_scb *mega_ioctl (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt);
X
X /* set SERDEBUG to 1 to enable serial debugging */
X #define SERDEBUG 0
X #if SERDEBUG
-static void ser_init(void);
-static void ser_puts(char *str);
-static void ser_putc(char c);
-static int ser_printk(const char *fmt, ...);
+static void ser_init (void);
+static void ser_puts (char *str);
+static void ser_putc (char c);
+static int ser_printk (const char *fmt,...);
X #endif
X
-/*================================================================
- *
- * Global variables
- *
- *================================================================*/
-static int numCtlrs = 0;
-static mega_host_config *megaCtlrs[4] = { 0 };
+//================================================================
+//
+// Global variables
+//
+//================================================================
+static int numCtlrs = 0;
+static mega_host_config *megaCtlrs[12] = {0};
X
X /* Change this to 0 if you want to see the raw drives */
-static int use_raid = 1;
+static int use_raid = 1;
X
X /* Queue of pending/completed SCBs */
-static mega_scb *qPending = NULL;
+static mega_scb *qPending = NULL;
X static Scsi_Cmnd *qCompleted = NULL;
X
X volatile static spinlock_t mega_lock;
-static struct tq_struct runq = {0,0,mega_runque,NULL};
+static struct tq_struct runq = {0, 0, mega_runque, NULL};
X
-struct proc_dir_entry proc_scsi_megaraid = {
+struct proc_dir_entry proc_scsi_megaraid =
+{
X PROC_SCSI_MEGARAID, 8, "megaraid",


X S_IFDIR | S_IRUGO | S_IXUGO, 2
X };

X
X #if SERDEBUG
-static char strbuf[MAX_SERBUF+1];
+static char strbuf[MAX_SERBUF + 1];
X
-static void ser_init()
+static void ser_init ()
X {
- unsigned port=COM_BASE;
+ unsigned port = COM_BASE;
X
- outb(0x80,port+3);
- outb(0,port+1);
- /* 9600 Baud, if 19200: outb(6,port) */
- outb(12, port);
- outb(3,port+3);
- outb(0,port+1);
+ outb (0x80, port + 3);
+ outb (0, port + 1);
+ /* 9600 Baud, if 19200: outb(6,port) */
+ outb (12, port);
+ outb (3, port + 3);
+ outb (0, port + 1);
X }
X
-static void ser_puts(char *str)
+static void ser_puts (char *str)
X {
- char *ptr;
+ char *ptr;
X
- ser_init();
- for (ptr=str;*ptr;++ptr)
- ser_putc(*ptr);
+ ser_init ();
+ for (ptr = str; *ptr; ++ptr)
+ ser_putc (*ptr);
X }
X
-static void ser_putc(char c)
+static void ser_putc (char c)
X {
- unsigned port=COM_BASE;
+ unsigned port = COM_BASE;
X
- while ((inb(port+5) & 0x20)==0);
- outb(c,port);
- if (c==0x0a)
- {
- while ((inb(port+5) & 0x20)==0);
- outb(0x0d,port);
- }
+ while ((inb (port + 5) & 0x20) == 0);
+ outb (c, port);
+ if (c == 0x0a) {
+ while ((inb (port + 5) & 0x20) == 0);
+ outb (0x0d, port);
+ }
X }
X
-static int ser_printk(const char *fmt, ...)
+static int ser_printk (const char *fmt,...)
X {
- va_list args;
- int i;
- long flags;
+ va_list args;
+ int i;
+ long flags;
X
- spin_lock_irqsave(mega_lock,flags);
- va_start(args,fmt);
- i = vsprintf(strbuf,fmt,args);
- ser_puts(strbuf);
- va_end(args);
- spin_unlock_irqrestore(&mega_lock,flags);
+ va_start (args, fmt);
+ i = vsprintf (strbuf, fmt, args);
+ ser_puts (strbuf);
+ va_end (args);
X
- return i;
+ return i;
X }
X
X #define TRACE(a) { ser_printk a;}
@@ -280,14 +288,14 @@
X #define TRACE(A)
X #endif
X
-void callDone(Scsi_Cmnd *SCpnt)
+void callDone (Scsi_Cmnd * SCpnt)
X {
X if (SCpnt->result) {
- TRACE(("*** %.08lx %.02x <%d.%d.%d> = %x\n", SCpnt->serial_number,
- SCpnt->cmnd[0], SCpnt->channel, SCpnt->target, SCpnt->lun,
- SCpnt->result));
+ TRACE (("*** %.08lx %.02x <%d.%d.%d> = %x\n", SCpnt->serial_number,
+ SCpnt->cmnd[0], SCpnt->channel, SCpnt->target, SCpnt->lun,
+ SCpnt->result));
X }
- SCpnt->scsi_done(SCpnt);
+ SCpnt->scsi_done (SCpnt);
X }
X
X /*-------------------------------------------------------------------------
@@ -296,82 +304,79 @@
X *
X *-------------------------------------------------------------------------*/
X
-/*================================================
- * Initialize SCB structures
- *================================================*/
-static void initSCB(mega_host_config *megaCfg)
+//================================================
+// Initialize SCB structures
+//================================================
+static void initSCB (mega_host_config * megaCfg)
X {
X int idx;
X

- for(idx=0; idx<megaCfg->max_cmds; idx++) {

- megaCfg->scbList[idx].idx = -1;
- megaCfg->scbList[idx].flag = 0;


+ for (idx = 0; idx < megaCfg->max_cmds; idx++) {

+ megaCfg->scbList[idx].idx = -1;
+ megaCfg->scbList[idx].flag = 0;
X megaCfg->scbList[idx].sgList = NULL;
- megaCfg->scbList[idx].SCpnt = NULL;
+ megaCfg->scbList[idx].SCpnt = NULL;
X }
X }
X
-/*===========================
- * Allocate a SCB structure
- *===========================*/
-static mega_scb *allocateSCB(mega_host_config *megaCfg,Scsi_Cmnd *SCpnt)
+//===========================
+// Allocate a SCB structure
+//===========================
+static mega_scb * allocateSCB (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt)
X {


- int idx;
- long flags;
+ int idx;
+ long flags;
X
- spin_lock_irqsave(&mega_lock,flags);

- for(idx=0; idx<megaCfg->max_cmds; idx++) {

+ spin_lock_irqsave (&mega_lock, flags);


+ for (idx = 0; idx < megaCfg->max_cmds; idx++) {

X if (megaCfg->scbList[idx].idx < 0) {
X
- /* Set Index and SCB pointer */
- megaCfg->scbList[idx].flag = 0;
- megaCfg->scbList[idx].idx = idx;
+ /* Set Index and SCB pointer */
+ megaCfg->scbList[idx].flag = 0;
+ megaCfg->scbList[idx].idx = idx;
X megaCfg->scbList[idx].SCpnt = SCpnt;
- megaCfg->scbList[idx].next = NULL;
- spin_unlock_irqrestore(&mega_lock,flags);
+ megaCfg->scbList[idx].next = NULL;


+ spin_unlock_irqrestore (&mega_lock, flags);
X

X if (megaCfg->scbList[idx].sgList == NULL) {
X megaCfg->scbList[idx].sgList =
- kmalloc(sizeof(mega_sglist)*MAX_SGLIST,GFP_ATOMIC|GFP_DMA);
+ kmalloc (sizeof (mega_sglist) * MAX_SGLIST, GFP_ATOMIC | GFP_DMA);
X }
X
X return &megaCfg->scbList[idx];


X }
X }
- spin_unlock_irqrestore(&mega_lock,flags);
+ spin_unlock_irqrestore (&mega_lock, flags);

+
+ printk (KERN_WARNING "Megaraid: Could not allocate free SCB!!!\n");
X
- printk(KERN_WARNING "Megaraid: Could not allocate free SCB!!!\n");
-

X return NULL;
X }
X

-/*=======================
- * Free a SCB structure
- *=======================*/
-static void freeSCB(mega_scb *scb)
-{
- long flags;
-
- spin_lock_irqsave(&mega_lock,flags);
- scb->flag = 0;
- scb->idx = -1;
- scb->next = NULL;
+//=======================
+// Free a SCB structure
+//=======================
+static void freeSCB (mega_scb * scb)
+{
+ scb->flag = 0;
+ scb->idx = -1;
+ scb->next = NULL;
X scb->SCpnt = NULL;
- spin_unlock_irqrestore(&mega_lock,flags);
X }
X
X /* Run through the list of completed requests */
-static void mega_rundoneq()
+static void mega_rundoneq ()
X {
X mega_host_config *megaCfg;
- Scsi_Cmnd *SCpnt;
- long islogical;
+ Scsi_Cmnd *SCpnt;
+ long islogical;
X
- while(1) {
- DEQUEUE(SCpnt, Scsi_Cmnd, qCompleted, host_scribble);
- if (SCpnt == NULL) return;
+ while (1) {
+ DEQUEUE (SCpnt, Scsi_Cmnd, qCompleted, host_scribble);
+ if (SCpnt == NULL)
+ return;


X
- megaCfg = (mega_host_config *)SCpnt->host->hostdata;
+ megaCfg = (mega_host_config *) SCpnt->host->hostdata;
X

X /* Check if we're allowing access to RAID drives or physical
X * if use_raid == 1 and this wasn't a disk on the max channel or
@@ -380,14 +385,15 @@
X */
X islogical = (SCpnt->channel == megaCfg->host->max_channel) ? 1 : 0;
X if (SCpnt->cmnd[0] == INQUIRY &&
- ((((u_char*)SCpnt->request_buffer)[0] & 0x1F) == TYPE_DISK) &&
+ ((((u_char *) SCpnt->request_buffer)[0] & 0x1F) == TYPE_DISK) &&
X (islogical != use_raid)) {
- SCpnt->result = 0xF0;
+ SCpnt->result = 0xF0;
X }
X
X /* Convert result to error */
- switch(SCpnt->result) {
- case 0x00: case 0x02:
+ switch (SCpnt->result) {
+ case 0x00:
+ case 0x02:
X SCpnt->result |= (DID_OK << 16);
X break;
X case 0x8:
@@ -399,16 +405,20 @@
X }
X
X /* Callback */
- callDone(SCpnt);


+ callDone (SCpnt);
X }
X }
X

X /* Add command to the list of completed requests */
-static void mega_cmd_done(mega_host_config *megaCfg,mega_scb *pScb, int status)
+static void mega_cmd_done (mega_host_config * megaCfg, mega_scb * pScb, int status)
X {
+ long flags;
+
X pScb->SCpnt->result = status;
- ENQUEUE(pScb->SCpnt, Scsi_Cmnd, qCompleted, host_scribble);
- freeSCB(pScb);
+ ENQUEUE (pScb->SCpnt, Scsi_Cmnd, qCompleted, host_scribble);
+ spin_lock_irqsave (&mega_lock, flags);
+ freeSCB (pScb);
+ spin_unlock_irqrestore (&mega_lock, flags);
X }
X
X /*----------------------------------------------------
@@ -416,45 +426,42 @@
X *
X * Run as a scheduled task
X *----------------------------------------------------*/
-static void mega_runque(void *dummy)
+static void mega_runque (void *dummy)


X {
X mega_host_config *megaCfg;
- mega_scb *pScb;

- long flags;
+ mega_scb *pScb;
+ long flags;
X
X /* Take care of any completed requests */
- mega_rundoneq();
+ mega_rundoneq ();
X
- DEQUEUE(pScb,mega_scb,qPending,next);
+ DEQUEUE (pScb, mega_scb, qPending, next);
X
X if (pScb) {
- megaCfg = (mega_host_config *)pScb->SCpnt->host->hostdata;
+ megaCfg = (mega_host_config *) pScb->SCpnt->host->hostdata;
X
- if (megaCfg->mbox->busy || megaCfg->flag & (IN_ISR|PENDING)) {
- printk(KERN_DEBUG "PENDING = %x, IN_ISR = %x, mbox.busy = %x\n",(u_int)(megaCfg->flag
- & PENDING), (u_int)(megaCfg->flag & IN_ISR), megaCfg->mbox->busy);
- TRACE(("%.08lx %.02x <%d.%d.%d> intr%d busy%d isr%d pending%d\n",
- pScb->SCpnt->serial_number,
- pScb->SCpnt->cmnd[0],
- pScb->SCpnt->channel,
- pScb->SCpnt->target,
- pScb->SCpnt->lun,
- intr_count,
- megaCfg->mbox->busy,
- (megaCfg->flag & IN_ISR) ? 1 : 0,
- (megaCfg->flag & PENDING) ? 1 : 0));
+ if (megaCfg->mbox->busy || megaCfg->flag & (IN_ISR | PENDING)) {
+ TRACE (("%.08lx %.02x <%d.%d.%d> busy%d isr%d pending%d\n",
+ pScb->SCpnt->serial_number,
+ pScb->SCpnt->cmnd[0],
+ pScb->SCpnt->channel,
+ pScb->SCpnt->target,
+ pScb->SCpnt->lun,
+ megaCfg->mbox->busy,
+ (megaCfg->flag & IN_ISR) ? 1 : 0,
+ (megaCfg->flag & PENDING) ? 1 : 0));
X }
X
- if (MegaIssueCmd(megaCfg, pScb->mboxData, pScb, 1)) {
- printk(KERN_DEBUG "MegaIssueCmd returned BUSY. Rescheduling command.\n");
+ if (MegaIssueCmd (megaCfg, pScb->mboxData, pScb, 1)) {
X /* We're BUSY... come back later */


- spin_lock_irqsave(&mega_lock,flags);
+ spin_lock_irqsave (&mega_lock, flags);

X pScb->next = qPending;
- qPending = pScb;
- spin_unlock_irqrestore(&mega_lock,flags);
+ qPending = pScb;


+ spin_unlock_irqrestore (&mega_lock, flags);
X

- if (!(megaCfg->flag & PENDING)) { /* If PENDING, irq will schedule task */
- queue_task(&runq, &tq_scheduler);
+ if (!(megaCfg->flag & PENDING)) {
+ /* If PENDING, irq will schedule task */
+ queue_task (&runq, &tq_scheduler);
X }
X }
X }
@@ -468,17 +475,20 @@
X * If NULL is returned, the scsi_done function MUST have been called
X *
X *-------------------------------------------------------------------*/
-static mega_scb *mega_build_cmd(mega_host_config *megaCfg, Scsi_Cmnd *SCpnt)
+static mega_scb * mega_build_cmd (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt)
X {
- mega_scb *pScb;
- mega_mailbox *mbox;
+ mega_scb *pScb;
+ mega_mailbox *mbox;
X mega_passthru *pthru;
- long seg;
+ long seg;
+
+ if (SCpnt->cmnd[0] & 0x80) /* ioctl from megamgr */
+ return mega_ioctl (megaCfg, SCpnt);
X
X /* We don't support multi-luns */
X if (SCpnt->lun != 0) {
X SCpnt->result = (DID_BAD_TARGET << 16);
- callDone(SCpnt);
+ callDone (SCpnt);


X return NULL;
X }
X

@@ -488,44 +498,44 @@
X *
X *-----------------------------------------------------*/
X if (SCpnt->channel == megaCfg->host->max_channel) {
- switch(SCpnt->cmnd[0]) {
+ switch (SCpnt->cmnd[0]) {
X case TEST_UNIT_READY:
- memset(SCpnt->request_buffer, 0, SCpnt->request_bufflen);
+ memset (SCpnt->request_buffer, 0, SCpnt->request_bufflen);
X SCpnt->result = (DID_OK << 16);
- callDone(SCpnt);
+ callDone (SCpnt);
X return NULL;
X
X case MODE_SENSE:
- memset(SCpnt->request_buffer, 0, SCpnt->cmnd[4]);
+ memset (SCpnt->request_buffer, 0, SCpnt->cmnd[4]);
X SCpnt->result = (DID_OK << 16);
- callDone(SCpnt);
+ callDone (SCpnt);
X return NULL;
X
X case READ_CAPACITY:
X case INQUIRY:
X /* Allocate a SCB and initialize passthru */
- if ((pScb = allocateSCB(megaCfg,SCpnt)) == NULL) {
+ if ((pScb = allocateSCB (megaCfg, SCpnt)) == NULL) {
X SCpnt->result = (DID_ERROR << 16);
- callDone(SCpnt);
+ callDone (SCpnt);
X return NULL;
X }
X pthru = &pScb->pthru;
- mbox = (mega_mailbox *)&pScb->mboxData;
+ mbox = (mega_mailbox *) & pScb->mboxData;
X
- memset(mbox, 0, sizeof(pScb->mboxData));
- memset(pthru, 0, sizeof(mega_passthru));
- pthru->timeout = 0;
- pthru->ars = 0;
- pthru->islogical = 1;
- pthru->logdrv = SCpnt->target;
- pthru->cdblen = SCpnt->cmd_len;
- pthru->dataxferaddr = virt_to_bus(SCpnt->request_buffer);
- pthru->dataxferlen = SCpnt->request_bufflen;
- memcpy(pthru->cdb, SCpnt->cmnd, SCpnt->cmd_len);
+ memset (mbox, 0, sizeof (pScb->mboxData));
+ memset (pthru, 0, sizeof (mega_passthru));
+ pthru->timeout = 0;
+ pthru->ars = 0;
+ pthru->islogical = 1;
+ pthru->logdrv = SCpnt->target;
+ pthru->cdblen = SCpnt->cmd_len;
+ pthru->dataxferaddr = virt_to_bus (SCpnt->request_buffer);
+ pthru->dataxferlen = SCpnt->request_bufflen;
+ memcpy (pthru->cdb, SCpnt->cmnd, SCpnt->cmd_len);
X
X /* Initialize mailbox area */
- mbox->cmd = MEGA_MBOXCMD_PASSTHRU;
- mbox->xferaddr = virt_to_bus(pthru);
+ mbox->cmd = MEGA_MBOXCMD_PASSTHRU;
+ mbox->xferaddr = virt_to_bus (pthru);
X
X return pScb;
X
@@ -534,51 +544,51 @@
X case READ_10:
X case WRITE_10:
X /* Allocate a SCB and initialize mailbox */
- if ((pScb = allocateSCB(megaCfg,SCpnt)) == NULL) {
+ if ((pScb = allocateSCB (megaCfg, SCpnt)) == NULL) {
X SCpnt->result = (DID_ERROR << 16);
- callDone(SCpnt);
+ callDone (SCpnt);
X return NULL;
X }
- mbox = (mega_mailbox *)&pScb->mboxData;
+ mbox = (mega_mailbox *) & pScb->mboxData;
X
- memset(mbox, 0, sizeof(pScb->mboxData));
+ memset (mbox, 0, sizeof (pScb->mboxData));
X mbox->logdrv = SCpnt->target;
- mbox->cmd = (*SCpnt->cmnd == READ_6 || *SCpnt->cmnd == READ_10) ?
+ mbox->cmd = (*SCpnt->cmnd == READ_6 || *SCpnt->cmnd == READ_10) ?
X MEGA_MBOXCMD_LREAD : MEGA_MBOXCMD_LWRITE;
-
+
X /* 6-byte */
X if (*SCpnt->cmnd == READ_6 || *SCpnt->cmnd == WRITE_6) {
- mbox->numsectors =
- (u_long)SCpnt->cmnd[4];
- mbox->lba =
- ((u_long)SCpnt->cmnd[1] << 16) |
- ((u_long)SCpnt->cmnd[2] << 8) |
- (u_long)SCpnt->cmnd[3];
+ mbox->numsectors =
+ (u_long) SCpnt->cmnd[4];
+ mbox->lba =
+ ((u_long) SCpnt->cmnd[1] << 16) |
+ ((u_long) SCpnt->cmnd[2] << 8) |
+ (u_long) SCpnt->cmnd[3];
X mbox->lba &= 0x1FFFFF;
X }
-
+
X /* 10-byte */
X if (*SCpnt->cmnd == READ_10 || *SCpnt->cmnd == WRITE_10) {
- mbox->numsectors =
- (u_long)SCpnt->cmnd[8] |
- ((u_long)SCpnt->cmnd[7] << 8);
+ mbox->numsectors =
+ (u_long) SCpnt->cmnd[8] |
+ ((u_long) SCpnt->cmnd[7] << 8);
X mbox->lba =
- ((u_long)SCpnt->cmnd[2] << 24) |
- ((u_long)SCpnt->cmnd[3] << 16) |
- ((u_long)SCpnt->cmnd[4] << 8) |
- (u_long)SCpnt->cmnd[5];
+ ((u_long) SCpnt->cmnd[2] << 24) |
+ ((u_long) SCpnt->cmnd[3] << 16) |
+ ((u_long) SCpnt->cmnd[4] << 8) |
+ (u_long) SCpnt->cmnd[5];
X }
-
+
X /* Calculate Scatter-Gather info */
- mbox->numsgelements = build_sglist(megaCfg, pScb,
- (u_long*)&mbox->xferaddr,
- (u_long*)&seg);
+ mbox->numsgelements = build_sglist (megaCfg, pScb,
+ (u_long *) & mbox->xferaddr,
+ (u_long *) & seg);
X
X return pScb;
-
+
X default:
X SCpnt->result = (DID_BAD_TARGET << 16);
- callDone(SCpnt);
+ callDone (SCpnt);


X return NULL;
X }
X }

@@ -589,31 +599,31 @@
X *-----------------------------------------------------*/
X else {
X /* Allocate a SCB and initialize passthru */
- if ((pScb = allocateSCB(megaCfg,SCpnt)) == NULL) {
+ if ((pScb = allocateSCB (megaCfg, SCpnt)) == NULL) {
X SCpnt->result = (DID_ERROR << 16);
- callDone(SCpnt);
+ callDone (SCpnt);
X return NULL;
X }
X pthru = &pScb->pthru;
- mbox = (mega_mailbox *)pScb->mboxData;
-
- memset(mbox, 0, sizeof(pScb->mboxData));
- memset(pthru, 0, sizeof(mega_passthru));
- pthru->timeout = 0;
- pthru->ars = 0;
+ mbox = (mega_mailbox *) pScb->mboxData;
+
+ memset (mbox, 0, sizeof (pScb->mboxData));
+ memset (pthru, 0, sizeof (mega_passthru));
+ pthru->timeout = 0;
+ pthru->ars = 0;
X pthru->islogical = 0;
- pthru->channel = SCpnt->channel;
- pthru->target = SCpnt->target;
- pthru->cdblen = SCpnt->cmd_len;
- memcpy(pthru->cdb, SCpnt->cmnd, SCpnt->cmd_len);
-
- pthru->numsgelements = build_sglist(megaCfg, pScb,
- (u_long *)&pthru->dataxferaddr,
- (u_long *)&pthru->dataxferlen);
-
+ pthru->channel = SCpnt->channel;
+ pthru->target = SCpnt->target;
+ pthru->cdblen = SCpnt->cmd_len;
+ memcpy (pthru->cdb, SCpnt->cmnd, SCpnt->cmd_len);
+
+ pthru->numsgelements = build_sglist (megaCfg, pScb,
+ (u_long *) & pthru->dataxferaddr,
+ (u_long *) & pthru->dataxferlen);
+
X /* Initialize mailbox */
- mbox->cmd = MEGA_MBOXCMD_PASSTHRU;
- mbox->xferaddr = virt_to_bus(pthru);
+ mbox->cmd = MEGA_MBOXCMD_PASSTHRU;
+ mbox->xferaddr = virt_to_bus (pthru);
X
X return pScb;
X }
@@ -621,81 +631,164 @@
X }
X
X /*--------------------------------------------------------------------
+ * build RAID commands for controller, passed down through ioctl()
+ *--------------------------------------------------------------------*/
+static mega_scb * mega_ioctl (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt)
+{
+ mega_scb *pScb;
+ mega_ioctl_mbox *mbox;
+ mega_mailbox *mailbox;
+ mega_passthru *pthru;
+ long seg;
+
+ if ((pScb = allocateSCB (megaCfg, SCpnt)) == NULL) {
+ SCpnt->result = (DID_ERROR << 16);
+ callDone (SCpnt);


+ return NULL;
+ }
+

+ mbox = (mega_ioctl_mbox *) & pScb->mboxData;
+ mailbox = (mega_mailbox *) & pScb->mboxData;
+ memset (mailbox, 0, sizeof (pScb->mboxData));
+
+ if (SCpnt->cmnd[0] == 0x83) { /* passthrough command */
+ char cdblen = SCpnt->cmnd[2];
+
+ pthru = &pScb->pthru;
+ memset (pthru, 0, sizeof (mega_passthru));
+ pthru->islogical = SCpnt->cmnd[cdblen + 3] & 0x80;
+ pthru->timeout = SCpnt->cmnd[cdblen + 3] & 0x07;
+ pthru->reqsenselen = 10; /* ? MAX_SENSE; */
+ pthru->ars = SCpnt->cmnd[cdblen + 3] & 0x08;
+ pthru->logdrv = SCpnt->cmnd[cdblen + 4];
+ pthru->channel = SCpnt->cmnd[cdblen + 5];
+ pthru->target = SCpnt->cmnd[cdblen + 6];
+ pthru->cdblen = cdblen;
+ memcpy (pthru->cdb, SCpnt->cmnd, SCpnt->cmnd[2]);
+
+ mailbox->cmd = MEGA_MBOXCMD_PASSTHRU;
+ mailbox->xferaddr = virt_to_bus (pthru);
+
+ pthru->numsgelements = build_sglist (megaCfg, pScb,
+ (u_long *) & pthru->dataxferaddr,
+ (u_long *) & pthru->dataxferlen);
+
+ return pScb;
+ }
+ /* else normal (nonpassthru) command */
+
+ mbox->cmd = SCpnt->cmnd[0] & 0x7F;
+ mbox->channel = SCpnt->cmnd[1];
+ mbox->param = SCpnt->cmnd[2];
+ mbox->pad[0] = SCpnt->cmnd[3];
+ mbox->logdrv = SCpnt->cmnd[4];
+
+ mbox->numsgelements = build_sglist (megaCfg, pScb,
+ (u_long *) & mbox->xferaddr,
+ (u_long *) & seg);
+
+ return (pScb);
+}
+
+
+/*--------------------------------------------------------------------
X * Interrupt service routine
X *--------------------------------------------------------------------*/
-static void megaraid_isr(int irq, void *devp, struct pt_regs *regs)
+static void megaraid_isr (int irq, void *devp, struct pt_regs *regs)
X {
- mega_host_config *megaCfg;
- u_char byte, idx, sIdx;
- u_long dword;
- mega_mailbox *mbox;
- mega_scb *pScb;
- long flags;
- int qCnt, qStatus;
+ mega_host_config *megaCfg;
+ u_char byte, idx, sIdx;
+ u_long dword;
+ mega_mailbox *mbox;
+ mega_scb *pScb;
+ long flags;
+ int qCnt, qStatus;
X
- megaCfg = (mega_host_config *)devp;
- mbox = (mega_mailbox *)megaCfg->mbox;
+ megaCfg = (mega_host_config *) devp;
+ mbox = (mega_mailbox *) megaCfg->mbox;
X
X if (megaCfg->host->irq == irq) {
- spin_lock_irqsave(&mega_lock,flags);
+
+#if LINUX_VERSION_CODE >= 0x20100
+ spin_lock_irqsave (&io_request_lock, flags);
+#endif
+


+ spin_lock_irqsave (&mega_lock, flags);
X

X if (megaCfg->flag & IN_ISR) {
- TRACE(("ISR called reentrantly!!\n"));
+ TRACE (("ISR called reentrantly!!\n"));
X }
X
X megaCfg->flag |= IN_ISR;
X
X /* Check if a valid interrupt is pending */


X if (megaCfg->flag & BOARD_QUARTZ) {

- dword = RDOUTDOOR(megaCfg);
- if (dword != 0x10001234) {
- /* Spurious interrupt */
- megaCfg->flag &= ~IN_ISR;
- spin_unlock_irqrestore(&mega_lock,flags);
- return;
- }
- WROUTDOOR(megaCfg,dword);
- } else {
- byte = READ_PORT(megaCfg->host->io_port, INTR_PORT);
- if ((byte & VALID_INTR_BYTE) == 0) {
- /* Spurious interrupt */
- megaCfg->flag &= ~IN_ISR;
- spin_unlock_irqrestore(&mega_lock,flags);
- return;
- }
- WRITE_PORT(megaCfg->host->io_port, INTR_PORT, byte);
+ dword = RDOUTDOOR (megaCfg);
+ if (dword != 0x10001234) {
+ /* Spurious interrupt */
+ megaCfg->flag &= ~IN_ISR;
+ spin_unlock_irqrestore (&mega_lock, flags);
+#if LINUX_VERSION_CODE >= 0x20100
+ spin_unlock_irqrestore (&io_request_lock, flags);
+#endif
+ return;
+ }
+ WROUTDOOR (megaCfg, dword);
+ }
+ else {
+ byte = READ_PORT (megaCfg->host->io_port, INTR_PORT);
+ if ((byte & VALID_INTR_BYTE) == 0) {
+ /* Spurious interrupt */
+ megaCfg->flag &= ~IN_ISR;
+ spin_unlock_irqrestore (&mega_lock, flags);
+#if LINUX_VERSION_CODE >= 0x20100
+ spin_unlock_irqrestore (&io_request_lock, flags);
+#endif
+ return;
+ }
+ WRITE_PORT (megaCfg->host->io_port, INTR_PORT, byte);
X }
-
- qCnt = mbox->numstatus;
+
+ qCnt = mbox->numstatus;
X qStatus = mbox->status;
X
- if (qCnt > 1) {TRACE(("ISR: Received %d status\n", qCnt))
- printk(KERN_DEBUG "Got numstatus = %d\n",qCnt);
+ if (qCnt > 1) {
+ TRACE (("ISR: Received %d status\n", qCnt))
+ printk (KERN_DEBUG "Got numstatus = %d\n", qCnt);
X }
-
- for(idx=0; idx<qCnt; idx++) {
+
+ for (idx = 0; idx < qCnt; idx++) {
X sIdx = mbox->completed[idx];
X if (sIdx > 0) {
- pScb = &megaCfg->scbList[sIdx-1];
- spin_unlock_irqrestore(&mega_lock,flags); /* locks within cmd_done */
- mega_cmd_done(megaCfg,&megaCfg->scbList[sIdx-1], qStatus);
- spin_lock_irqsave(&mega_lock,flags);
+ pScb = &megaCfg->scbList[sIdx - 1];
+ spin_unlock_irqrestore (&mega_lock, flags); /* megalock within cmd_done */
+ mega_cmd_done (megaCfg, &megaCfg->scbList[sIdx - 1], qStatus);


+ spin_lock_irqsave (&mega_lock, flags);
X }

X }


X if (megaCfg->flag & BOARD_QUARTZ) {

- WRINDOOR(megaCfg,virt_to_bus(megaCfg->mbox)|0x2);
- while (RDINDOOR(megaCfg) & 0x02);
- } else {
- CLEAR_INTR(megaCfg->host->io_port);
+ WRINDOOR (megaCfg, virt_to_bus (megaCfg->mbox) | 0x2);
+ while (RDINDOOR (megaCfg) & 0x02);
+ }
+ else {
+ CLEAR_INTR (megaCfg->host->io_port);
X }
X
X megaCfg->flag &= ~IN_ISR;
X megaCfg->flag &= ~PENDING;
X
+ spin_unlock_irqrestore (&mega_lock, flags);
+ mega_runque (NULL);
+
+#if LINUX_VERSION_CODE >= 0x20100
+ spin_unlock_irqrestore (&io_request_lock, flags);
+#endif
+
+#if 0
X /* Queue as a delayed ISR routine */
- queue_task_irq_off(&runq, &tq_immediate);
- mark_bh(IMMEDIATE_BH);
- spin_unlock_irqrestore(&mega_lock,flags);
+ queue_task_irq_off (&runq, &tq_immediate);
+ mark_bh (IMMEDIATE_BH);
+#endif
X
X }
X }
@@ -703,111 +796,128 @@
X /*==================================================*/
X /* Wait until the controller's mailbox is available */
X /*==================================================*/
-static int busyWaitMbox(mega_host_config *megaCfg)
+static int busyWaitMbox (mega_host_config * megaCfg)
X {
- mega_mailbox *mbox = (mega_mailbox *)megaCfg->mbox;
- long counter;
+ mega_mailbox *mbox = (mega_mailbox *) megaCfg->mbox;
+ long counter;
X
- for(counter=0; counter<0xFFFFFF; counter++) {
- if (!mbox->busy) return 0;
+ for (counter = 0; counter < 30000; counter++) {
+ udelay (100);
+ if (!mbox->busy)
+ return 0;
X }


- return -1;
-}
-

-/*=====================================================
- * Post a command to the card
- *
- * Arguments:
- * mega_host_config *megaCfg - Controller structure
- * u_char *mboxData - Mailbox area, 16 bytes
- * mega_scb *pScb - SCB posting (or NULL if N/A)
- * int intr - if 1, interrupt, 0 is blocking
- *=====================================================*/
-static int MegaIssueCmd(mega_host_config *megaCfg,
- u_char *mboxData,
- mega_scb *pScb,
- int intr)
-{
- mega_mailbox *mbox = (mega_mailbox *)megaCfg->mbox;
- long flags;
- u_char byte;
- u_long cmdDone;
+ return -1; /* give up after 3 seconds */
+}
X
- mboxData[0x1] = (pScb ? pScb->idx+1 : 0x00); /* Set cmdid */
- mboxData[0xF] = 1; /* Set busy */
+//=====================================================
+// Post a command to the card
+//
+// Arguments:
+// mega_host_config *megaCfg - Controller structure
+// u_char *mboxData - Mailbox area, 16 bytes
+// mega_scb *pScb - SCB posting (or NULL if N/A)
+// int intr - if 1, interrupt, 0 is blocking
+//=====================================================
+static int MegaIssueCmd (mega_host_config * megaCfg,
+ u_char * mboxData,
+ mega_scb * pScb,
+ int intr)
+{
+ mega_mailbox *mbox = (mega_mailbox *) megaCfg->mbox;
+ long flags;
+ u_char byte;
+ u_long cmdDone;
+
+ mboxData[0x1] = (pScb ? pScb->idx + 1 : 0x00); /* Set cmdid */
+ mboxData[0xF] = 1; /* Set busy */
+
+ spin_lock_irqsave(&mega_lock,flags);
X
X /* one bad report of problem when issuing a command while pending.
X * Wasn't able to duplicate, but it doesn't really affect performance
X * anyway, so don't allow command while PENDING
X */
+
X if (megaCfg->flag & PENDING) {
+ spin_unlock_irqrestore(&mega_lock,flags);


X return -1;
X }
X

X /* Wait until mailbox is free */
- if (busyWaitMbox(megaCfg)) {
+ if (busyWaitMbox (megaCfg)) {
X if (pScb) {
- TRACE(("Mailbox busy %.08lx <%d.%d.%d>\n", pScb->SCpnt->serial_number,
- pScb->SCpnt->channel, pScb->SCpnt->target, pScb->SCpnt->lun));
+ TRACE (("Mailbox busy %.08lx <%d.%d.%d>\n", pScb->SCpnt->serial_number,
+ pScb->SCpnt->channel, pScb->SCpnt->target, pScb->SCpnt->lun));
+ } else {
+ TRACE(("pScb NULL in MegaIssueCmd!\n"));
X }
+ spin_unlock_irqrestore(&mega_lock,flags);


X return -1;
X }
X

X /* Copy mailbox data into host structure */
- spin_lock_irqsave(&mega_lock,flags);
- memset(mbox, 0, sizeof(mega_mailbox));
- memcpy(mbox, mboxData, 16);
- spin_unlock_irqrestore(&mega_lock,flags);
+ memset (mbox, 0, sizeof (mega_mailbox));
+ memcpy (mbox, mboxData, 16);
X
X /* Kick IO */
X megaCfg->flag |= PENDING;
X if (intr) {
X /* Issue interrupt (non-blocking) command */


X if (megaCfg->flag & BOARD_QUARTZ) {

- mbox->mraid_poll = 0;
- mbox->mraid_ack = 0;
- WRINDOOR(megaCfg, virt_to_bus(megaCfg->mbox) | 0x1);
- } else {
- ENABLE_INTR(megaCfg->host->io_port);
- ISSUE_COMMAND(megaCfg->host->io_port);
+ mbox->mraid_poll = 0;
+ mbox->mraid_ack = 0;
+ WRINDOOR (megaCfg, virt_to_bus (megaCfg->mbox) | 0x1);
+ }
+ else {
+ ENABLE_INTR (megaCfg->host->io_port);
+ ISSUE_COMMAND (megaCfg->host->io_port);
X }
+ spin_unlock_irqrestore(&mega_lock,flags);
X }
- else { /* Issue non-ISR (blocking) command */
+ else { /* Issue non-ISR (blocking) command */
X

X if (megaCfg->flag & BOARD_QUARTZ) {

X
- mbox->mraid_poll = 0;
- mbox->mraid_ack = 0;
- WRINDOOR(megaCfg, virt_to_bus(megaCfg->mbox) | 0x1);
+ mbox->mraid_poll = 0;
+ mbox->mraid_ack = 0;
+ WRINDOOR (megaCfg, virt_to_bus (megaCfg->mbox) | 0x1);
X
- while((cmdDone=RDOUTDOOR(megaCfg)) != 0x10001234);
- WROUTDOOR(megaCfg, cmdDone);
+ while ((cmdDone = RDOUTDOOR (megaCfg)) != 0x10001234);
+ WROUTDOOR (megaCfg, cmdDone);
X
+ spin_unlock_irqrestore(&mega_lock,flags);
X if (pScb) {
- mega_cmd_done(megaCfg,pScb, mbox->status);
- mega_rundoneq();
+ mega_cmd_done (megaCfg, pScb, mbox->status);
+ mega_rundoneq ();
X }
X
- WRINDOOR(megaCfg,virt_to_bus(megaCfg->mbox) | 0x2);
- while(RDINDOOR(megaCfg) & 0x2);
+ WRINDOOR (megaCfg, virt_to_bus (megaCfg->mbox) | 0x2);
+ while (RDINDOOR (megaCfg) & 0x2);
X
X megaCfg->flag &= ~PENDING;
+
X }
X else {
- DISABLE_INTR(megaCfg->host->io_port);
- ISSUE_COMMAND(megaCfg->host->io_port);
-
- while(!((byte=READ_PORT(megaCfg->host->io_port,INTR_PORT))&INTR_VALID));
- WRITE_PORT(megaCfg->host->io_port, INTR_PORT, byte);
-
- ENABLE_INTR(megaCfg->host->io_port);
- CLEAR_INTR(megaCfg->host->io_port);
-
+ DISABLE_INTR (megaCfg->host->io_port);
+ ISSUE_COMMAND (megaCfg->host->io_port);
+
+ while (!((byte = READ_PORT (megaCfg->host->io_port, INTR_PORT)) & INTR_VALID));
+ WRITE_PORT (megaCfg->host->io_port, INTR_PORT, byte);
+
+
+ ENABLE_INTR (megaCfg->host->io_port);
+ CLEAR_INTR (megaCfg->host->io_port);
+ megaCfg->flag &= ~PENDING;
+ spin_unlock_irqrestore(&mega_lock,flags);
+
X if (pScb) {
- mega_cmd_done(megaCfg,pScb, mbox->status);
- mega_rundoneq();
+ mega_cmd_done (megaCfg, pScb, mbox->status);
+ mega_rundoneq ();
X }
- megaCfg->flag &= ~PENDING;
+ else {
+ TRACE (("Error: NULL pScb!\n"));


+ }
+
X }
X }
X

@@ -817,40 +927,40 @@
X /*-------------------------------------------------------------------
X * Copies data to SGLIST
X *-------------------------------------------------------------------*/
-static int build_sglist(mega_host_config *megaCfg, mega_scb *scb,
- u_long *buffer, u_long *length)
+static int build_sglist (mega_host_config * megaCfg, mega_scb * scb,
+ u_long * buffer, u_long * length)
X {
X struct scatterlist *sgList;
X int idx;
X
X /* Scatter-gather not used */
X if (scb->SCpnt->use_sg == 0) {
- *buffer = virt_to_bus(scb->SCpnt->request_buffer);
- *length = (u_long)scb->SCpnt->request_bufflen;
+ *buffer = virt_to_bus (scb->SCpnt->request_buffer);
+ *length = (u_long) scb->SCpnt->request_bufflen;


X return 0;
X }
X

- sgList = (struct scatterlist *)scb->SCpnt->buffer;
+ sgList = (struct scatterlist *) scb->SCpnt->buffer;
X if (scb->SCpnt->use_sg == 1) {
- *buffer = virt_to_bus(sgList[0].address);
- *length = (u_long)sgList[0].length;
+ *buffer = virt_to_bus (sgList[0].address);
+ *length = (u_long) sgList[0].length;


X return 0;
X }
X

X /* Copy Scatter-Gather list info into controller structure */
- for(idx=0; idx<scb->SCpnt->use_sg; idx++) {
- scb->sgList[idx].address = virt_to_bus(sgList[idx].address);
- scb->sgList[idx].length = (u_long)sgList[idx].length;
+ for (idx = 0; idx < scb->SCpnt->use_sg; idx++) {
+ scb->sgList[idx].address = virt_to_bus (sgList[idx].address);
+ scb->sgList[idx].length = (u_long) sgList[idx].length;
X }
-
+
X /* Reset pointer and length fields */
- *buffer = virt_to_bus(scb->sgList);
+ *buffer = virt_to_bus (scb->sgList);
X *length = 0;
X
X /* Return count of SG requests */
X return scb->SCpnt->use_sg;
X }
-
+
X /*--------------------------------------------------------------------
X * Initializes the adress of the controller's mailbox register
X * The mailbox register is used to issue commands to the card.
@@ -867,25 +977,25 @@


X * 10 01 numstatus byte
X * 11 01 status byte

X *--------------------------------------------------------------------*/
-static int mega_register_mailbox(mega_host_config *megaCfg, u_long paddr)
+static int mega_register_mailbox (mega_host_config * megaCfg, u_long paddr)
X {
X /* align on 16-byte boundry */
X megaCfg->mbox = &megaCfg->mailbox;
- megaCfg->mbox = (mega_mailbox *) ((((ulong)megaCfg->mbox) + 16)&0xfffffff0);
- paddr = (paddr+16)&0xfffffff0;
+ megaCfg->mbox = (mega_mailbox *) ((((ulong) megaCfg->mbox) + 16) & 0xfffffff0);
+ paddr = (paddr + 16) & 0xfffffff0;
X
X /* Register mailbox area with the firmware */


X if (megaCfg->flag & BOARD_QUARTZ) {

X }
X else {
- WRITE_PORT(megaCfg->host->io_port, MBOX_PORT0, paddr & 0xFF);
- WRITE_PORT(megaCfg->host->io_port, MBOX_PORT1, (paddr >> 8) & 0xFF);
- WRITE_PORT(megaCfg->host->io_port, MBOX_PORT2, (paddr >> 16) & 0xFF);
- WRITE_PORT(megaCfg->host->io_port, MBOX_PORT3, (paddr >> 24) & 0xFF);
- WRITE_PORT(megaCfg->host->io_port, ENABLE_MBOX_REGION, ENABLE_MBOX_BYTE);
-
- CLEAR_INTR(megaCfg->host->io_port);
- ENABLE_INTR(megaCfg->host->io_port);
+ WRITE_PORT (megaCfg->host->io_port, MBOX_PORT0, paddr & 0xFF);
+ WRITE_PORT (megaCfg->host->io_port, MBOX_PORT1, (paddr >> 8) & 0xFF);
+ WRITE_PORT (megaCfg->host->io_port, MBOX_PORT2, (paddr >> 16) & 0xFF);
+ WRITE_PORT (megaCfg->host->io_port, MBOX_PORT3, (paddr >> 24) & 0xFF);
+ WRITE_PORT (megaCfg->host->io_port, ENABLE_MBOX_REGION, ENABLE_MBOX_BYTE);
+
+ CLEAR_INTR (megaCfg->host->io_port);
+ ENABLE_INTR (megaCfg->host->io_port);


X }
X return 0;
X }

@@ -893,77 +1003,79 @@
X /*-------------------------------------------------------------------
X * Issue an adapter info query to the controller
X *-------------------------------------------------------------------*/
-static int mega_i_query_adapter(mega_host_config *megaCfg)
+static int mega_i_query_adapter (mega_host_config * megaCfg)
X {
X mega_RAIDINQ *adapterInfo;
X mega_mailbox *mbox;
- u_char mboxData[16];
- u_long paddr;
+ u_char mboxData[16];
+ u_long paddr;
X
- spin_lock_init(&mega_lock);
+ spin_lock_init (&mega_lock);
X /* Initialize adapter inquiry */
- paddr = virt_to_bus(megaCfg->mega_buffer);


- mbox = (mega_mailbox *)mboxData;

+ paddr = virt_to_bus (megaCfg->mega_buffer);


+ mbox = (mega_mailbox *) mboxData;
X

- memset((void *)megaCfg->mega_buffer, 0, sizeof(megaCfg->mega_buffer));
- memset(mbox, 0, 16);
+ memset ((void *) megaCfg->mega_buffer, 0, sizeof (megaCfg->mega_buffer));


+ memset (mbox, 0, 16);
X

X /* Initialize mailbox registers */
- mbox->cmd = MEGA_MBOXCMD_ADAPTERINQ;
+ mbox->cmd = MEGA_MBOXCMD_ADAPTERINQ;
X mbox->xferaddr = paddr;
X
X /* Issue a blocking command to the card */


- MegaIssueCmd(megaCfg, mboxData, NULL, 0);

-

+ MegaIssueCmd (megaCfg, mboxData, NULL, 0);

+
X /* Initialize host/local structures with Adapter info */


- adapterInfo = (mega_RAIDINQ *)megaCfg->mega_buffer;

+ adapterInfo = (mega_RAIDINQ *) megaCfg->mega_buffer;

X megaCfg->host->max_channel = adapterInfo->AdpInfo.ChanPresent;
- megaCfg->host->max_id = adapterInfo->AdpInfo.MaxTargPerChan;
- megaCfg->numldrv = adapterInfo->LogdrvInfo.NumLDrv;
+/* megaCfg->host->max_id = adapterInfo->AdpInfo.MaxTargPerChan; */
+ megaCfg->host->max_id = 9; /* max logical drives + 1 */
+ megaCfg->numldrv = adapterInfo->LogdrvInfo.NumLDrv;
X
X #if 0
- printk(KERN_DEBUG "---- Logical drive info ----\n");
- for(i=0; i<megaCfg->numldrv; i++) {
- printk(KERN_DEBUG "%d: size: %ld prop: %x state: %x\n",i,
- adapterInfo->LogdrvInfo.LDrvSize[i],
- adapterInfo->LogdrvInfo.LDrvProp[i],
- adapterInfo->LogdrvInfo.LDrvState[i]);
- }
- printk(KERN_DEBUG "---- Physical drive info ----\n");
- for(i=0; i<MAX_PHYSICAL_DRIVES; i++) {
- if (i && !(i % 8)) printk("\n");
- printk("%d: %x ", i, adapterInfo->PhysdrvInfo.PDrvState[i]);
+ printk ("KERN_DEBUG ---- Logical drive info ----\n");
+ for (i = 0; i < megaCfg->numldrv; i++) {
+ printk ("%d: size: %ld prop: %x state: %x\n", i,
+ adapterInfo->LogdrvInfo.LDrvSize[i],
+ adapterInfo->LogdrvInfo.LDrvProp[i],
+ adapterInfo->LogdrvInfo.LDrvState[i]);
+ }
+ printk (KERN_DEBUG "---- Physical drive info ----\n");
+ for (i = 0; i < MAX_PHYSICAL_DRIVES; i++) {
+ if (i && !(i % 8))
+ printk ("\n");
+ printk ("%d: %x ", i, adapterInfo->PhysdrvInfo.PDrvState[i]);
X }
- printk("\n");
+ printk ("\n");
X #endif
X
X megaCfg->max_cmds = adapterInfo->AdpInfo.MaxConcCmds;
X
-#ifdef HP /* use HP firmware and bios version encoding */
- sprintf(megaCfg->fwVer,"%c%d%d.%d%d",
- adapterInfo->AdpInfo.FwVer[2],
- adapterInfo->AdpInfo.FwVer[1] >> 8,
- adapterInfo->AdpInfo.FwVer[1] & 0x0f,
- adapterInfo->AdpInfo.FwVer[2] >> 8,
- adapterInfo->AdpInfo.FwVer[2] & 0x0f);
- sprintf(megaCfg->biosVer,"%c%d%d.%d%d",
- adapterInfo->AdpInfo.BiosVer[2],
- adapterInfo->AdpInfo.BiosVer[1] >> 8,
- adapterInfo->AdpInfo.BiosVer[1] & 0x0f,
- adapterInfo->AdpInfo.BiosVer[2] >> 8,
- adapterInfo->AdpInfo.BiosVer[2] & 0x0f);
+#ifdef HP /* use HP firmware and bios version encoding */
+ sprintf (megaCfg->fwVer, "%c%d%d.%d%d",
+ adapterInfo->AdpInfo.FwVer[2],
+ adapterInfo->AdpInfo.FwVer[1] >> 8,
+ adapterInfo->AdpInfo.FwVer[1] & 0x0f,
+ adapterInfo->AdpInfo.FwVer[2] >> 8,
+ adapterInfo->AdpInfo.FwVer[2] & 0x0f);
+ sprintf (megaCfg->biosVer, "%c%d%d.%d%d",
+ adapterInfo->AdpInfo.BiosVer[2],
+ adapterInfo->AdpInfo.BiosVer[1] >> 8,
+ adapterInfo->AdpInfo.BiosVer[1] & 0x0f,
+ adapterInfo->AdpInfo.BiosVer[2] >> 8,
+ adapterInfo->AdpInfo.BiosVer[2] & 0x0f);
X #else
- memcpy(megaCfg->fwVer, adapterInfo->AdpInfo.FwVer, 4);
- megaCfg->fwVer[4] = 0;
+ memcpy (megaCfg->fwVer, adapterInfo->AdpInfo.FwVer, 4);
+ megaCfg->fwVer[4] = 0;
X
- memcpy(megaCfg->biosVer, adapterInfo->AdpInfo.BiosVer, 4);
- megaCfg->biosVer[4] = 0;
+ memcpy (megaCfg->biosVer, adapterInfo->AdpInfo.BiosVer, 4);
+ megaCfg->biosVer[4] = 0;
X #endif
X
- printk(KERN_INFO "megaraid: [%s:%s] detected %d logical drives" CRLFSTR,
- megaCfg->fwVer,
- megaCfg->biosVer,
- megaCfg->numldrv);
+ printk (KERN_INFO "megaraid: [%s:%s] detected %d logical drives" CRLFSTR,
+ megaCfg->fwVer,
+ megaCfg->biosVer,
+ megaCfg->numldrv);


X return 0;
X }
X

@@ -976,47 +1088,56 @@
X /*----------------------------------------------------------
X * Returns data to be displayed in /proc/scsi/megaraid/X
X *----------------------------------------------------------*/
-int megaraid_proc_info(char *buffer, char **start, off_t offset,
- int length, int inode, int inout)
+int megaraid_proc_info (char *buffer, char **start, off_t offset,
+ int length, int inode, int inout)
X {
X *start = buffer;


X return 0;
X }
X

-int findCard(Scsi_Host_Template *pHostTmpl,
- u_short pciVendor, u_short pciDev,
- long flag)
+int findCard (Scsi_Host_Template * pHostTmpl,
+ u_short pciVendor, u_short pciDev,


SHAR_EOF
true || echo 'restore of patch-2.0.37 failed'
fi

echo 'End of part 28'
echo 'File patch-2.0.37 is continued in part 29'
echo 29 > _shar_seq_.tmp

Thomas...@ciw.uni-karlsruhe.de

unread,
Jun 16, 1999, 3:00:00 AM6/16/99
to
Archive-name: v2.0/patch-2.0.37/part35

#!/bin/sh
# this is part 35 of a 45 - part archive


# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.0.37 continued
if test ! -r _shar_seq_.tmp; then
echo 'Please unpack part 1 first!'
exit 1
fi
(read Scheck

if test "$Scheck" != 35; then


echo Please unpack part "$Scheck" next!
exit 1
else
exit 0
fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.0.37'
else
echo 'x - continuing with patch-2.0.37'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.0.37' &&

+#define PORT_LBA_8 4
+#define PORT_LBA_16 5
+#define PORT_LBA_24 6
+#define PORT_STAT_CMD 7
+#define PORT_STAT_SEL 8
+#define PORT_FAIL 9
+#define PORT_ALT_STAT 10
+
+typedef struct
+ {
+ UCHAR device; // device code
+ UCHAR byte6; // device select register image
+ UCHAR spigot; // spigot number
+ UCHAR sparebyte; // placeholder
+ USHORT sectors; // number of sectors per track
+ USHORT heads; // number of heads
+ USHORT cylinders; // number of cylinders for this device
+ USHORT spareword; // placeholder
+ ULONG blocks; // number of blocks on device
+ } OUR_DEVICE, *POUR_DEVICE;
+
+typedef struct
+ {
+ USHORT ports[12];
+ USHORT regDmaDesc; // address of the DMA discriptor register for direction of transfer
+ USHORT regDmaCmdStat; // Byte #1 of DMA command status register
+ USHORT regDmaAddrPci; // 32 bit register for PCI address of DMA
+ USHORT regDmaAddrLoc; // 32 bit register for local bus address of DMA
+ USHORT regDmaCount; // 32 bit register for DMA transfer count
+ USHORT regDmaMode; // 32 bit register for DMA mode control
+ USHORT regRemap; // 32 bit local space remap
+ USHORT regDesc; // 32 bit local region descriptor
+ USHORT regRange; // 32 bit local range
+ USHORT regIrqControl; // 16 bit Interrupt enable/disable and status
+ USHORT regScratchPad; // scratch pad I/O base address
+ USHORT regBase; // Base I/O register for data space
+ USHORT basePort; // PLX base I/O port
+ USHORT timingMode; // timing mode currently set for adapter
+ ULONG timingAddress; // address to use on adapter for current timing mode
+ OUR_DEVICE device[4];
+ IDE_STRUCT ide;
+ ULONG startSector;
+ USHORT sectorCount;
+ Scsi_Cmnd *SCpnt;
+ VOID *buffer;
+ USHORT expectingIRQ;
+ USHORT readPhase;
+ } ADAPTER2220I, *PADAPTER2220I;
+
+#define HOSTDATA(host) ((PADAPTER2220I)&host->hostdata)


+
+
+static struct Scsi_Host *PsiHost[MAXADAPTER] = {NULL,}; // One for each adapter
+static int NumAdapters = 0;

+static IDENTIFY_DATA identifyData;
+static SETUP DaleSetup;
+
+/****************************************************************
+ * Name: WriteData :LOCAL
+ *
+ * Description: Write data to device.


+ *
+ * Parameters: padapter - Pointer adapter data structure.
+ *

+ * Returns: TRUE if drive does not assert DRQ in time.
+ *
+ ****************************************************************/
+static int WriteData (PADAPTER2220I padapter)
+ {
+ ULONG timer;
+ USHORT *pports = padapter->ports;
+
+ timer = jiffies + TIMEOUT_DRQ; // calculate the timeout value
+ do {
+ if ( inb_p (pports[PORT_STAT_CMD]) & IDE_STATUS_DRQ )
+ {
+ outb_p (0, padapter->regDmaDesc); // write operation
+ outl (padapter->timingAddress, padapter->regDmaAddrLoc);
+ outl (virt_to_bus (padapter->buffer), padapter->regDmaAddrPci);
+ outl ((ULONG)padapter->ide.ide.ide[2] * (ULONG)512, padapter->regDmaCount);
+ outb_p (1, padapter->regDmaMode); // interrupts off
+ outb_p (0x03, padapter->regDmaCmdStat); // kick the DMA engine in gear
+ return 0;
+ }


+ } while ( timer > jiffies ); // test for timeout
+

+ padapter->ide.ide.ides.cmd = 0; // null out the command byte
+ return 1;
+ }
+/****************************************************************
+ * Name: IdeCmd :LOCAL
+ *


+ * Description: Process a queued command from the SCSI manager.
+ *

+ * Parameters: padapter - Pointer adapter data structure.
+ *

+ * Returns: Zero if no error or status register contents on error.
+ *
+ ****************************************************************/
+static UCHAR IdeCmd (PADAPTER2220I padapter)
+ {
+ ULONG timer;
+ USHORT *pports = padapter->ports;
+ UCHAR status;
+
+ outb_p (padapter->ide.ide.ides.spigot, pports[PORT_STAT_SEL]); // select the spigot
+ outb_p (padapter->ide.ide.ide[6], pports[PORT_LBA_24]); // select the drive
+ timer = jiffies + TIMEOUT_READY; // calculate the timeout value
+ DEB(printk ("\npci2220i Issueing new command: 0x%X",padapter->ide.ide.ides.cmd));
+ do {
+ status = inb_p (padapter->ports[PORT_STAT_CMD]);
+ if ( status & IDE_STATUS_DRDY )
+ {
+ outb_p (padapter->ide.ide.ide[2], pports[PORT_SECTOR_COUNT]);
+ outb_p (padapter->ide.ide.ide[3], pports[PORT_LBA_0]);
+ outb_p (padapter->ide.ide.ide[4], pports[PORT_LBA_8]);
+ outb_p (padapter->ide.ide.ide[5], pports[PORT_LBA_16]);
+ padapter->expectingIRQ = 1;
+ outb_p (padapter->ide.ide.ide[7], pports[PORT_STAT_CMD]);
+
+ if ( padapter->ide.ide.ides.cmd == IDE_CMD_WRITE_MULTIPLE )
+ return (WriteData (padapter));
+ return 0;
+ }


+ } while ( timer > jiffies ); // test for timeout
+

+ padapter->ide.ide.ides.cmd = 0; // null out the command byte
+ return status;
+ }
+/****************************************************************
+ * Name: SetupTransfer :LOCAL
+ *
+ * Description: Setup a data transfer command.
+ *


+ * Parameters: padapter - Pointer adapter data structure.

+ * drive - Drive/head register upper nibble only.
+ *
+ * Returns: TRUE if no data to transfer.
+ *
+ ****************************************************************/
+static int SetupTransfer (PADAPTER2220I padapter, UCHAR drive)
+ {
+ if ( padapter->sectorCount )
+ {
+ *(ULONG *)padapter->ide.ide.ides.lba = padapter->startSector;
+ padapter->ide.ide.ide[6] |= drive;
+// padapter->ide.ide.ides.sectors = ( padapter->sectorCount > SECTORSXFER ) ? SECTORSXFER : padapter->sectorCount;
+ padapter->ide.ide.ides.sectors = ( padapter->sectorCount > MAX_BUS_MASTER_BLOCKS ) ? MAX_BUS_MASTER_BLOCKS : padapter->sectorCount;
+ padapter->sectorCount -= padapter->ide.ide.ides.sectors; // bump the start and count for next xfer
+ padapter->startSector += padapter->ide.ide.ides.sectors;
+ return 0;
+ }
+ else
+ {
+ padapter->ide.ide.ides.cmd = 0; // null out the command byte
+ padapter->SCpnt = NULL;
+ return 1;
+ }
+ }
+/****************************************************************
+ * Name: DecodeError :LOCAL
+ *
+ * Description: Decode and process device errors.
+ *
+ * Parameters: pshost - Pointer to host data block.
+ * status - Status register code.
+ *
+ * Returns: The driver status code.
+ *
+ ****************************************************************/
+static ULONG DecodeError (struct Scsi_Host *pshost, UCHAR status)
+ {
+ PADAPTER2220I padapter = HOSTDATA(pshost);
+ UCHAR error;
+
+ padapter->expectingIRQ = 0;
+ padapter->SCpnt = NULL;
+ if ( status & IDE_STATUS_WRITE_FAULT )
+ {
+ return DID_PARITY << 16;
+ }
+ if ( status & IDE_STATUS_BUSY )
+ return DID_BUS_BUSY << 16;
+
+ error = inb_p (padapter->ports[PORT_ERROR]);
+ DEB(printk ("\npci2220i error register: %x", error));
+ switch ( error )
+ {
+ case IDE_ERROR_AMNF:
+ case IDE_ERROR_TKONF:
+ case IDE_ERROR_ABRT:
+ case IDE_ERROR_IDFN:
+ case IDE_ERROR_UNC:
+ case IDE_ERROR_BBK:
+ default:
+ return DID_ERROR << 16;
+ }
+ return DID_ERROR << 16;


+ }
+/****************************************************************
+ * Name: Irq_Handler :LOCAL
+ *
+ * Description: Interrupt handler.
+ *
+ * Parameters: irq - Hardware IRQ number.
+ * dev_id -
+ * regs -
+ *
+ * Returns: TRUE if drive is not ready in time.
+ *
+ ****************************************************************/
+static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
+ {
+ struct Scsi_Host *shost = NULL; // Pointer to host data block

+ PADAPTER2220I padapter; // Pointer to adapter control structure
+ USHORT *pports; // I/O port array
+ Scsi_Cmnd *SCpnt;
+ UCHAR status;
+ int z;
+
+// DEB(printk ("\npci2220i recieved interrupt\n"));
+


+ for ( z = 0; z < NumAdapters; z++ ) // scan for interrupt to process
+ {
+ if ( PsiHost[z]->irq == (UCHAR)(irq & 0xFF) )
+ {

+ if ( inw_p (HOSTDATA(PsiHost[z])->regIrqControl) & 0x8000 )


+ {
+ shost = PsiHost[z];
+ break;
+ }
+ }
+ }
+
+ if ( !shost )
+ {

+ DEB (printk ("\npci2220i: not my interrupt"));


+ return;
+ }
+
+ padapter = HOSTDATA(shost);

+ pports = padapter->ports;
+ SCpnt = padapter->SCpnt;
+
+ if ( !padapter->expectingIRQ )
+ {
+ DEB(printk ("\npci2220i Unsolicited interrupt\n"));
+ return;
+ }
+ padapter->expectingIRQ = 0;
+
+ status = inb_p (padapter->ports[PORT_STAT_CMD]); // read the device status
+ if ( status & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT) )
+ goto irqerror;
+
+ switch ( padapter->ide.ide.ides.cmd ) // decide how to handle the interrupt
+ {
+ case IDE_CMD_READ_MULTIPLE:
+ if ( padapter->readPhase == 1 ) // is this a bus master channel complete?
+ {
+ DEB(printk ("\npci2220i processing read interrupt cleanup"));
+ outb_p (0x08, padapter->regDmaCmdStat); // cancel interrupt from DMA engine
+ padapter->buffer += padapter->ide.ide.ides.sectors * 512;
+ if ( SetupTransfer (padapter, padapter->ide.ide.ide[6] & 0xF0) )
+ {
+ SCpnt->result = DID_OK << 16;
+ padapter->SCpnt = NULL;
+ SCpnt->scsi_done (SCpnt);
+ return;
+ }
+ padapter->readPhase = 0;
+ if ( !(status = IdeCmd (padapter)) )
+ {
+ DEB (printk ("\npci2220i interrupt complete, waiting for another"));
+ return;
+ }
+ }
+ if ( status & IDE_STATUS_DRQ )
+ {
+ DEB(printk ("\npci2220i processing read interrupt start bus master cycle"));
+ outb_p (8, padapter->regDmaDesc); // read operation
+ padapter->readPhase = 1;
+ padapter->expectingIRQ = 1;
+ outl (padapter->timingAddress, padapter->regDmaAddrLoc);
+ outl (virt_to_bus (padapter->buffer), padapter->regDmaAddrPci);
+ outl ((ULONG)padapter->ide.ide.ides.sectors * (ULONG)512, padapter->regDmaCount);
+ outb_p (5, padapter->regDmaMode); // interrupt enable/disable
+ outb_p (0x03, padapter->regDmaCmdStat); // kick the DMA engine in gear
+ return;
+ }
+ break;
+
+ case IDE_CMD_WRITE_MULTIPLE:
+ DEB(printk ("\npci2220i processing write interrupt cleanup"));
+ padapter->buffer += padapter->ide.ide.ides.sectors * 512;
+ if ( SetupTransfer (padapter, padapter->ide.ide.ide[6] & 0xF0) )
+ {
+ SCpnt->result = DID_OK << 16;
+ padapter->SCpnt = NULL;
+ SCpnt->scsi_done (SCpnt);
+ return;
+ }
+ if ( !(status = IdeCmd (padapter)) )
+ {
+ DEB (printk ("\npci2220i interrupt complete, waiting for another"));
+ return;
+ }
+ break;
+
+ case IDE_COMMAND_IDENTIFY:
+ {
+ PINQUIRYDATA pinquiryData = SCpnt->request_buffer;
+
+ DEB(printk ("\npci2220i processing verify interrupt cleanup"));
+ if ( status & IDE_STATUS_DRQ )
+ {
+ insw (pports[PORT_DATA], &identifyData, sizeof (identifyData) >> 1);
+
+ memset (pinquiryData, 0, SCpnt->request_bufflen); // Zero INQUIRY data structure.
+ pinquiryData->DeviceType = 0;
+ pinquiryData->Versions = 2;
+ pinquiryData->AdditionalLength = 35 - 4;
+
+ // Fill in vendor identification fields.
+ for ( z = 0; z < 20; z += 2 )
+ {
+ pinquiryData->VendorId[z] = ((UCHAR *)identifyData.ModelNumber)[z + 1];
+ pinquiryData->VendorId[z + 1] = ((UCHAR *)identifyData.ModelNumber)[z];
+ }
+
+ // Initialize unused portion of product id.
+ for ( z = 0; z < 4; z++ )
+ pinquiryData->ProductId[12 + z] = ' ';
+
+ // Move firmware revision from IDENTIFY data to
+ // product revision in INQUIRY data.
+ for ( z = 0; z < 4; z += 2 )
+ {
+ pinquiryData->ProductRevisionLevel[z] = ((UCHAR *)identifyData.FirmwareRevision)[z + 1];
+ pinquiryData->ProductRevisionLevel[z + 1] = ((UCHAR *)identifyData.FirmwareRevision)[z];
+ }
+
+ SCpnt->result = DID_OK << 16;
+ padapter->SCpnt = NULL;
+ SCpnt->scsi_done (SCpnt);
+ return;


+ }
+ break;
+ }
+

+ default:
+ DEB(printk ("\npci2220i no real process here!"));
+ SCpnt->result = DID_OK << 16;
+ padapter->SCpnt = NULL;
+ SCpnt->scsi_done (SCpnt);
+ return;
+ }
+
+irqerror:;
+ DEB(printk ("\npci2220i error Device Status: %X\n", status));
+ SCpnt->result = DecodeError (shost, status);


+ SCpnt->scsi_done (SCpnt);
+ }
+/****************************************************************

+ * Name: Pci2220i_QueueCommand
+ *
+ * Description: Process a queued command from the SCSI manager.
+ *
+ * Parameters: SCpnt - Pointer to SCSI command structure.
+ * done - Pointer to done function to call.
+ *
+ * Returns: Status code.
+ *
+ ****************************************************************/

+int Pci2220i_QueueCommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))


+ {
+ UCHAR *cdb = (UCHAR *)SCpnt->cmnd; // Pointer to SCSI CDB

+ PADAPTER2220I padapter = HOSTDATA(SCpnt->host); // Pointer to adapter control structure
+ POUR_DEVICE pdev = &padapter->device[SCpnt->target];// Pointer to device information
+ UCHAR rc; // command return code
+


+ SCpnt->scsi_done = done;

+ padapter->ide.ide.ides.spigot = pdev->spigot;
+ padapter->buffer = SCpnt->request_buffer;
+ if (done)
+ {
+ if ( !pdev->device || SCpnt->lun )
+ {
+ SCpnt->result = DID_BAD_TARGET << 16;
+ done (SCpnt);


+ return 0;
+ }
+ }

+ else
+ {
+ printk("pci2220i_queuecommand: %02X: done can't be NULL\n", *cdb);


+ return 0;
+ }
+

+ DEB (if(*cdb) printk ("\nCDB: %X- %X %X %X %X %X %X %X %X %X %X ", SCpnt->cmd_len, cdb[0], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5], cdb[6], cdb[7], cdb[8], cdb[9]));

+ switch ( *cdb )
+ {
+ case SCSIOP_INQUIRY: // inquiry CDB

+ {
+ padapter->ide.ide.ide[6] = pdev->byte6;
+ padapter->ide.ide.ides.cmd = IDE_COMMAND_IDENTIFY;
+ break;
+ }
+


+ case SCSIOP_TEST_UNIT_READY: // test unit ready CDB

+ SCpnt->result = DID_OK << 16;
+ done (SCpnt);
+ return 0;
+


+ case SCSIOP_READ_CAPACITY: // read capctiy CDB

+ {
+ PREAD_CAPACITY_DATA pdata = (PREAD_CAPACITY_DATA)SCpnt->request_buffer;
+
+ pdata->blksiz = 0x20000;
+ XANY2SCSI ((UCHAR *)&pdata->blks, pdev->blocks);
+ SCpnt->result = DID_OK << 16;
+ done (SCpnt);


+ return 0;
+ }
+

+ case SCSIOP_VERIFY: // verify CDB

+ *(ULONG *)padapter->ide.ide.ides.lba = XSCSI2LONG (&cdb[2]);
+ padapter->ide.ide.ide[6] |= pdev->byte6;
+ padapter->ide.ide.ide[2] = (UCHAR)((USHORT)cdb[8] | ((USHORT)cdb[7] << 8));
+ padapter->ide.ide.ides.cmd = IDE_COMMAND_VERIFY;
+ break;
+


+ case SCSIOP_READ: // read10 CDB

+ padapter->startSector = XSCSI2LONG (&cdb[2]);
+ padapter->sectorCount = (USHORT)cdb[8] | ((USHORT)cdb[7] << 8);
+ SetupTransfer (padapter, pdev->byte6);
+ padapter->ide.ide.ides.cmd = IDE_CMD_READ_MULTIPLE;
+ padapter->readPhase = 0;
+ break;
+


+ case SCSIOP_READ6: // read6 CDB

+ padapter->startSector = SCSI2LONG (&cdb[1]);
+ padapter->sectorCount = cdb[4];
+ SetupTransfer (padapter, pdev->byte6);
+ padapter->ide.ide.ides.cmd = IDE_CMD_READ_MULTIPLE;
+ padapter->readPhase = 0;
+ break;
+


+ case SCSIOP_WRITE: // write10 CDB

+ padapter->startSector = XSCSI2LONG (&cdb[2]);
+ padapter->sectorCount = (USHORT)cdb[8] | ((USHORT)cdb[7] << 8);
+ SetupTransfer (padapter, pdev->byte6);
+ padapter->ide.ide.ides.cmd = IDE_CMD_WRITE_MULTIPLE;


+ break;
+ case SCSIOP_WRITE6: // write6 CDB

+ padapter->startSector = SCSI2LONG (&cdb[1]);
+ padapter->sectorCount = cdb[4];
+ SetupTransfer (padapter, pdev->byte6);
+ padapter->ide.ide.ides.cmd = IDE_CMD_WRITE_MULTIPLE;
+ break;
+


+ default:
+ DEB (printk ("pci2220i_queuecommand: Unsupported command %02X\n", *cdb));

+ SCpnt->result = DID_ERROR << 16;
+ done (SCpnt);


+ return 0;
+ }
+

+ padapter->SCpnt = SCpnt; // Save this command data
+
+ rc = IdeCmd (padapter);
+ if ( rc )
+ {
+ padapter->expectingIRQ = 0;
+ DEB (printk ("pci2220i_queuecommand: %02X, %02X: Device failed to respond for command\n", *cdb, padapter->ide.ide.ides.cmd));
+ SCpnt->result = DID_ERROR << 16;
+ done (SCpnt);
+ return 0;
+ }
+ if ( padapter->ide.ide.ides.cmd == IDE_CMD_WRITE_MULTIPLE )
+ {
+ if ( WriteData (padapter) )
+ {
+ padapter->expectingIRQ = 0;
+ DEB (printk ("pci2220i_queuecommand: %02X, %02X: Device failed to accept data\n", *cdb, padapter->ide.ide.ides.cmd));
+ SCpnt->result = DID_ERROR << 16;
+ done (SCpnt);


+ return 0;
+ }
+ }

+ DEB (printk(" now waiting for initial interrupt "));


+ return 0;
+ }
+

+static void internal_done(Scsi_Cmnd * SCpnt)


+ {
+ SCpnt->SCp.Status++;
+ }
+/****************************************************************
+ * Name: Pci2220i_Command
+ *
+ * Description: Process a command from the SCSI manager.
+ *
+ * Parameters: SCpnt - Pointer to SCSI command structure.
+ *
+ * Returns: Status code.
+ *
+ ****************************************************************/

+int Pci2220i_Command (Scsi_Cmnd *SCpnt)
+ {
+ DEB(printk("pci2220i_command: ..calling pci2220i_queuecommand\n"));
+
+ Pci2220i_QueueCommand (SCpnt, internal_done);


+
+ SCpnt->SCp.Status = 0;
+ while (!SCpnt->SCp.Status)
+ barrier ();
+ return SCpnt->result;
+ }
+/****************************************************************

+ * Name: ReadFlash
+ *
+ * Description: Read information from controller Flash memory.
+ *
+ * Parameters: hostdata - Pointer to host interface data structure.
+ * pdata - Pointer to data structures.
+ * base - base address in Flash.
+ * length - lenght of data space in bytes.


+ *
+ * Returns: Nothing.
+ *
+ ****************************************************************/

+VOID ReadFlash (PADAPTER2220I hostdata, VOID *pdata, ULONG base, ULONG length)
+ {
+ ULONG oldremap;
+ UCHAR olddesc;
+ ULONG z;
+ UCHAR *pd = (UCHAR *)pdata;
+
+ oldremap = inl (hostdata->regRemap); // save values to restore later
+ olddesc = inb_p (hostdata->regDesc);
+
+ outl (base | 1, hostdata->regRemap); // remap to Flash space as specified
+ outb_p (0x40, hostdata->regDesc); // describe remap region as 8 bit
+ for ( z = 0; z < length; z++) // get "length" data count
+ *pd++ = inb_p (hostdata->regBase + z); // read in the data
+
+ outl (oldremap, hostdata->regRemap); // restore remap register values
+ outb_p (olddesc, hostdata->regDesc);
+ }


+
+/****************************************************************
+ * Name: Pci2220i_Detect
+ *
+ * Description: Detect and initialize our boards.
+ *
+ * Parameters: tpnt - Pointer to SCSI host template structure.
+ *
+ * Returns: Number of adapters found.
+ *
+ ****************************************************************/

+int Pci2220i_Detect (Scsi_Host_Template *tpnt)


+ {
+ int pci_index = 0;
+ struct Scsi_Host *pshost;

+ PADAPTER2220I hostdata;
+ ULONG modearray[] = {DALE_DATA_MODE2, DALE_DATA_MODE3, DALE_DATA_MODE4, DALE_DATA_MODE4P};
+ int unit;
+ int z;


+ int setirq;
+
+ if ( pcibios_present () )
+ {
+ for ( pci_index = 0; pci_index <= MAXADAPTER; ++pci_index )
+ {
+ UCHAR pci_bus, pci_device_fn;
+

+ if ( pcibios_find_device (VENDOR_PSI, DEVICE_DALE_1, pci_index, &pci_bus, &pci_device_fn) != 0 )
+ break;
+
+ pshost = scsi_register (tpnt, sizeof(ADAPTER2220I));
+ hostdata = HOSTDATA(pshost);
+
+ pcibios_read_config_word (pci_bus, pci_device_fn, PCI_BASE_ADDRESS_1, &hostdata->basePort);
+ hostdata->basePort &= 0xFFFE;
+ DEB (printk ("\nBase Regs = %#04X", hostdata->basePort));
+ hostdata->regRemap = hostdata->basePort + RTR_LOCAL_REMAP; // 32 bit local space remap
+ DEB (printk (" %#04X", hostdata->regRemap));
+ hostdata->regDesc = hostdata->basePort + RTR_REGIONS; // 32 bit local region descriptor
+ DEB (printk (" %#04X", hostdata->regDesc));
+ hostdata->regRange = hostdata->basePort + RTR_LOCAL_RANGE; // 32 bit local range
+ DEB (printk (" %#04X", hostdata->regRange));
+ hostdata->regIrqControl = hostdata->basePort + RTR_INT_CONTROL_STATUS; // 16 bit interupt control and status
+ DEB (printk (" %#04X", hostdata->regIrqControl));
+ hostdata->regScratchPad = hostdata->basePort + RTR_MAILBOX; // 16 byte scratchpad I/O base address
+ DEB (printk (" %#04X", hostdata->regScratchPad));
+
+ pcibios_read_config_word (pci_bus, pci_device_fn, PCI_BASE_ADDRESS_2, &hostdata->regBase);
+ hostdata->regBase &= 0xFFFE;
+ for ( z = 0; z < 9; z++ ) // build regester address array
+ hostdata->ports[z] = hostdata->regBase + 0x80 + (z * 4);
+ hostdata->ports[PORT_FAIL] = hostdata->regBase + REG_FAIL;
+ hostdata->ports[PORT_ALT_STAT] = hostdata->regBase + REG_ALT_STAT;
+ DEB (printk ("\nPorts ="));
+ DEB (for (z=0;z<11;z++) printk(" %#04X", hostdata->ports[z]););
+
+ hostdata->regDmaDesc = hostdata->regBase + RTL_DMA1_DESC_PTR; // address of the DMA discriptor register for direction of transfer
+ DEB (printk ("\nDMA Regs = %#04X", hostdata->regDmaDesc));
+ hostdata->regDmaCmdStat = hostdata->regBase + RTL_DMA_COMMAND_STATUS + 1; // Byte #1 of DMA command status register
+ DEB (printk (" %#04X", hostdata->regDmaCmdStat));
+ hostdata->regDmaAddrPci = hostdata->regBase + RTL_DMA1_PCI_ADDR; // 32 bit register for PCI address of DMA
+ DEB (printk (" %#04X", hostdata->regDmaAddrPci));
+ hostdata->regDmaAddrLoc = hostdata->regBase + RTL_DMA1_LOCAL_ADDR; // 32 bit register for local bus address of DMA
+ DEB (printk (" %#04X", hostdata->regDmaAddrLoc));
+ hostdata->regDmaCount = hostdata->regBase + RTL_DMA1_COUNT; // 32 bit register for DMA transfer count
+ DEB (printk (" %#04X", hostdata->regDmaCount));
+ hostdata->regDmaMode = hostdata->regBase + RTL_DMA1_MODE + 1; // 32 bit register for DMA mode control
+ DEB (printk (" %#04X", hostdata->regDmaMode));
+
+ if ( !inb_p (hostdata->regScratchPad + DALE_NUM_DRIVES) ) // if no devices on this board


+ goto unregister;
+
+ pcibios_read_config_byte (pci_bus, pci_device_fn, PCI_INTERRUPT_LINE, &pshost->irq);
+ setirq = 1;
+ for ( z = 0; z < pci_index; z++ ) // scan for shared interrupts
+ {
+ if ( PsiHost[z]->irq == pshost->irq ) // if shared then, don't posses
+ setirq = 0;
+ }
+ if ( setirq ) // if not shared, posses
+ {

+ if ( request_irq (pshost->irq, Irq_Handler, 0, "pci2220i", NULL) )
+ {
+ printk ("Unable to allocate IRQ for PSI-2220I controller.\n");


+ goto unregister;
+ }
+ }
+ PsiHost[pci_index] = pshost; // save SCSI_HOST pointer
+

+ pshost->unique_id = hostdata->regBase;
+ pshost->max_id = 4;
+
+ outb_p (0x01, hostdata->regRange); // fix our range register because other drivers want to tromp on it
+
+ hostdata->timingMode = inb_p (hostdata->regScratchPad + DALE_TIMING_MODE);
+ hostdata->timingAddress = modearray[hostdata->timingMode - 2];
+ ReadFlash (hostdata, &DaleSetup, DALE_FLASH_SETUP, sizeof (SETUP));
+
+ for ( z = 0; z < inb_p (hostdata->regScratchPad + DALE_NUM_DRIVES); ++z )
+ {
+ unit = inb_p (hostdata->regScratchPad + DALE_CHANNEL_DEVICE_0 + z) & 0x0F;
+ hostdata->device[unit].device = inb_p (hostdata->regScratchPad + DALE_SCRATH_DEVICE_0 + unit);
+ hostdata->device[unit].byte6 = (UCHAR)(((unit & 1) << 4) | 0xE0);
+ hostdata->device[unit].spigot = (UCHAR)(1 << (unit >> 1));
+ hostdata->device[unit].sectors = DaleSetup.setupDevice[unit].sectors;
+ hostdata->device[unit].heads = DaleSetup.setupDevice[unit].heads;
+ hostdata->device[unit].cylinders = DaleSetup.setupDevice[unit].cylinders;
+ hostdata->device[unit].blocks = DaleSetup.setupDevice[unit].blocks;
+ DEB (printk ("\nHOSTDATA->device = %X", hostdata->device[unit].device));
+ DEB (printk ("\n byte6 = %X", hostdata->device[unit].byte6));
+ DEB (printk ("\n spigot = %X", hostdata->device[unit].spigot));
+ DEB (printk ("\n sectors = %X", hostdata->device[unit].sectors));
+ DEB (printk ("\n heads = %X", hostdata->device[unit].heads));
+ DEB (printk ("\n cylinders = %X", hostdata->device[unit].cylinders));
+ DEB (printk ("\n blocks = %lX", hostdata->device[unit].blocks));
+ }
+
+ printk("\nPSI-2220I EIDE CONTROLLER: at I/O = %X/%X IRQ = %d\n", hostdata->basePort, hostdata->regBase, pshost->irq);
+ printk("(C) 1997 Perceptive Solutions, Inc. All rights reserved\n\n");
+
+ NumAdapters++;


+ continue;
+unregister:;
+ scsi_unregister (pshost);
+ }
+ }

+ return NumAdapters;


+ }
+/****************************************************************
+ * Name: Pci2220i_Abort
+ *
+ * Description: Process the Abort command from the SCSI manager.
+ *
+ * Parameters: SCpnt - Pointer to SCSI command structure.
+ *
+ * Returns: Allways snooze.
+ *
+ ****************************************************************/

+int Pci2220i_Abort (Scsi_Cmnd *SCpnt)
+ {
+ DEB (printk ("pci2220i_abort\n"));


+ return SCSI_ABORT_SNOOZE;
+ }
+/****************************************************************
+ * Name: Pci2220i_Reset
+ *
+ * Description: Process the Reset command from the SCSI manager.
+ *
+ * Parameters: SCpnt - Pointer to SCSI command structure.
+ * flags - Flags about the reset command
+ *
+ * Returns: No active command at this time, so this means
+ * that each time we got some kind of response the
+ * last time through. Tell the mid-level code to
+ * request sense information in order to decide what
+ * to do next.
+ *
+ ****************************************************************/

+int Pci2220i_Reset (Scsi_Cmnd *SCpnt, unsigned int reset_flags)


+ {
+ return SCSI_RESET_PUNT;
+ }
+
+#include "sd.h"
+
+/****************************************************************
+ * Name: Pci2220i_BiosParam
+ *
+ * Description: Process the biosparam request from the SCSI manager to
+ * return C/H/S data.
+ *
+ * Parameters: disk - Pointer to SCSI disk structure.
+ * dev - Major/minor number from kernel.
+ * geom - Pointer to integer array to place geometry data.
+ *
+ * Returns: zero.
+ *
+ ****************************************************************/

+int Pci2220i_BiosParam (Scsi_Disk *disk, kdev_t dev, int geom[])
+ {
+ POUR_DEVICE pdev;
+
+ pdev = &(HOSTDATA(disk->device->host)->device[disk->device->id]);
+
+ geom[0] = pdev->heads;
+ geom[1] = pdev->sectors;
+ geom[2] = pdev->cylinders;


+ return 0;
+ }
+
+
+#ifdef MODULE
+/* Eventually this will go into an include file, but this will be later */

+Scsi_Host_Template driver_template = PCI2220I;


+
+#include "scsi_module.c"
+#endif
+

diff -u --recursive --new-file v2.0.36/linux/drivers/scsi/pci2220i.h linux/drivers/scsi/pci2220i.h
--- v2.0.36/linux/drivers/scsi/pci2220i.h Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/pci2220i.h Sun Jun 13 10:21:02 1999
@@ -0,0 +1,345 @@


+/*+M*************************************************************************
+ * Perceptive Solutions, Inc. PCI-2000 device driver proc support for Linux.
+ *
+ * Copyright (c) 1997 Perceptive Solutions, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *

+ * File Name: pci2220i.h
+ *
+ * Description: Header file for the SCSI driver for the PCI2220I
+ * EIDE interface card.


+ *
+ *-M*************************************************************************/
+

+#ifndef _PCI2220I_H
+#define _PCI2220I_H


+
+#include <linux/types.h>
+#include <linux/kdev_t.h>
+
+#ifndef PSI_EIDE_SCSIOP
+#define PSI_EIDE_SCSIOP 1
+
+/************************************************/

+/* Some defines that we like */


+/************************************************/
+#define CHAR char
+#define UCHAR unsigned char
+#define SHORT short
+#define USHORT unsigned short

+#define BOOL unsigned short


+#define LONG long
+#define ULONG unsigned long
+#define VOID void
+

+/************************************************/
+/* Timeout konstants */
+/************************************************/
+#define TIMEOUT_READY 10 // 100 mSec
+#define TIMEOUT_DRQ 40 // 400 mSec

+// IDE command definitions
+#define IDE_COMMAND_ATAPI_RESET 0x08
+#define IDE_COMMAND_READ 0x20
+#define IDE_COMMAND_WRITE 0x30
+#define IDE_COMMAND_RECALIBRATE 0x10
+#define IDE_COMMAND_SEEK 0x70
+#define IDE_COMMAND_SET_PARAMETERS 0x91
+#define IDE_COMMAND_VERIFY 0x40
+#define IDE_COMMAND_ATAPI_PACKET 0xA0
+#define IDE_COMMAND_ATAPI_IDENTIFY 0xA1
+#define IDE_CMD_READ_MULTIPLE 0xC4
+#define IDE_CMD_WRITE_MULTIPLE 0xC5
+#define IDE_CMD_SET_MULTIPLE 0xC6
+#define IDE_COMMAND_WRITE_DMA 0xCA
+#define IDE_COMMAND_READ_DMA 0xC8
+#define IDE_COMMAND_IDENTIFY 0xEC
+
+// IDE status definitions
+#define IDE_STATUS_ERROR 0x01
+#define IDE_STATUS_INDEX 0x02
+#define IDE_STATUS_CORRECTED_ERROR 0x04
+#define IDE_STATUS_DRQ 0x08
+#define IDE_STATUS_DSC 0x10
+#define IDE_STATUS_WRITE_FAULT 0x20
+#define IDE_STATUS_DRDY 0x40
+#define IDE_STATUS_BUSY 0x80
+
+// IDE error definitions
+#define IDE_ERROR_AMNF 0x01
+#define IDE_ERROR_TKONF 0x02
+#define IDE_ERROR_ABRT 0x04
+#define IDE_ERROR_MCR 0x08
+#define IDE_ERROR_IDFN 0x10
+#define IDE_ERROR_MC 0x20
+#define IDE_ERROR_UNC 0x40
+#define IDE_ERROR_BBK 0x80
+
+// IDE interface structure
+typedef struct _IDE_STRUCT
+ {
+ union
+ {
+ UCHAR ide[9];
+ struct
+ {
+ USHORT data;
+ UCHAR sectors;
+ UCHAR lba[4];
+ UCHAR cmd;
+ UCHAR spigot;
+ } ides;
+ } ide;
+ } IDE_STRUCT;

+// IDE IDENTIFY data
+typedef struct _IDENTIFY_DATA
+ {
+ USHORT GeneralConfiguration; // 00
+ USHORT NumberOfCylinders; // 02
+ USHORT Reserved1; // 04
+ USHORT NumberOfHeads; // 06
+ USHORT UnformattedBytesPerTrack; // 08
+ USHORT UnformattedBytesPerSector; // 0A
+ USHORT SectorsPerTrack; // 0C
+ USHORT VendorUnique1[3]; // 0E
+ USHORT SerialNumber[10]; // 14
+ USHORT BufferType; // 28
+ USHORT BufferSectorSize; // 2A
+ USHORT NumberOfEccBytes; // 2C
+ USHORT FirmwareRevision[4]; // 2E
+ USHORT ModelNumber[20]; // 36
+ UCHAR MaximumBlockTransfer; // 5E
+ UCHAR VendorUnique2; // 5F
+ USHORT DoubleWordIo; // 60
+ USHORT Capabilities; // 62
+ USHORT Reserved2; // 64
+ UCHAR VendorUnique3; // 66
+ UCHAR PioCycleTimingMode; // 67
+ UCHAR VendorUnique4; // 68
+ UCHAR DmaCycleTimingMode; // 69
+ USHORT TranslationFieldsValid:1; // 6A
+ USHORT Reserved3:15;
+ USHORT NumberOfCurrentCylinders; // 6C
+ USHORT NumberOfCurrentHeads; // 6E
+ USHORT CurrentSectorsPerTrack; // 70
+ ULONG CurrentSectorCapacity; // 72
+ USHORT Reserved4[197]; // 76
+ } IDENTIFY_DATA, *PIDENTIFY_DATA;
+
+// Identify data without the Reserved4.
+typedef struct _IDENTIFY_DATA2 {
+ USHORT GeneralConfiguration; // 00
+ USHORT NumberOfCylinders; // 02
+ USHORT Reserved1; // 04
+ USHORT NumberOfHeads; // 06
+ USHORT UnformattedBytesPerTrack; // 08
+ USHORT UnformattedBytesPerSector; // 0A
+ USHORT SectorsPerTrack; // 0C
+ USHORT VendorUnique1[3]; // 0E
+ USHORT SerialNumber[10]; // 14
+ USHORT BufferType; // 28
+ USHORT BufferSectorSize; // 2A
+ USHORT NumberOfEccBytes; // 2C
+ USHORT FirmwareRevision[4]; // 2E
+ USHORT ModelNumber[20]; // 36
+ UCHAR MaximumBlockTransfer; // 5E
+ UCHAR VendorUnique2; // 5F
+ USHORT DoubleWordIo; // 60
+ USHORT Capabilities; // 62
+ USHORT Reserved2; // 64
+ UCHAR VendorUnique3; // 66
+ UCHAR PioCycleTimingMode; // 67
+ UCHAR VendorUnique4; // 68
+ UCHAR DmaCycleTimingMode; // 69
+ USHORT TranslationFieldsValid:1; // 6A
+ USHORT Reserved3:15;
+ USHORT NumberOfCurrentCylinders; // 6C
+ USHORT NumberOfCurrentHeads; // 6E
+ USHORT CurrentSectorsPerTrack; // 70
+ ULONG CurrentSectorCapacity; // 72
+ } IDENTIFY_DATA2, *PIDENTIFY_DATA2;
+
+#endif // PSI_EIDE_SCSIOP
+
+// function prototypes
+int Pci2220i_Detect (Scsi_Host_Template *tpnt);
+int Pci2220i_Command (Scsi_Cmnd *SCpnt);
+int Pci2220i_QueueCommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *));
+int Pci2220i_Abort (Scsi_Cmnd *SCpnt);
+int Pci2220i_Reset (Scsi_Cmnd *SCpnt, unsigned int flags);
+int Pci2220i_BiosParam (Disk *disk, kdev_t dev, int geom[]);


+
+#ifndef NULL
+ #define NULL 0
+#endif
+

+extern struct proc_dir_entry Proc_Scsi_Pci2220i;
+
+#define PCI2220I { NULL, NULL, \
+ &Proc_Scsi_Pci2220i,/* proc_dir_entry */ \
+ NULL, \
+ "PCI-2220I EIDE Disk Controller", \
+ Pci2220i_Detect, \
+ NULL, \
+ NULL, \
+ Pci2220i_Command, \
+ Pci2220i_QueueCommand, \
+ Pci2220i_Abort, \
+ Pci2220i_Reset, \
+ NULL, \
+ Pci2220i_BiosParam, \
+ 1, \
+ -1, \
+ SG_NONE, \


+ 1, \
+ 0, \
+ 0, \
+ DISABLE_CLUSTERING }
+
+#endif

diff -u --recursive --new-file v2.0.36/linux/drivers/scsi/psi240i.c linux/drivers/scsi/psi240i.c
--- v2.0.36/linux/drivers/scsi/psi240i.c Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/psi240i.c Sun Jun 13 10:21:02 1999
@@ -0,0 +1,717 @@
+/*+M*************************************************************************
+ * Perceptive Solutions, Inc. PSI-240I device driver proc support for Linux.


+ *
+ * Copyright (c) 1997 Perceptive Solutions, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *

+ * File Name: psi240i.c
+ *
+ * Description: SCSI driver for the PSI240I EIDE interface card.


+ *
+ *-M*************************************************************************/
+
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/head.h>
+#include <linux/types.h>
+#include <linux/string.h>

+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <asm/dma.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <linux/blk.h>
+#include "scsi.h"
+#include "hosts.h"
+

+#include "psi240i.h"
+#include "psi_chip.h"
+
+#include<linux/stat.h>
+
+struct proc_dir_entry Proc_Scsi_Psi240i =
+ { PROC_SCSI_PSI240I, 7, "psi240i", S_IFDIR | S_IRUGO | S_IXUGO, 2 };


+
+//#define DEBUG 1
+
+#ifdef DEBUG
+#define DEB(x) x

+#else
+#define DEB(x)
+#endif
+
+#define MAXBOARDS 2 /* Increase this and the sizes of the arrays below, if you need more. */
+


+#define PORT_DATA 0
+#define PORT_ERROR 1
+#define PORT_SECTOR_COUNT 2
+#define PORT_LBA_0 3

+#define PORT_LBA_8 4
+#define PORT_LBA_16 5
+#define PORT_LBA_24 6
+#define PORT_STAT_CMD 7
+#define PORT_SEL_FAIL 8
+#define PORT_IRQ_STATUS 9
+#define PORT_ADDRESS 10
+#define PORT_FAIL 11
+#define PORT_ALT_STAT 12
+
+typedef struct
+ {
+ UCHAR device; // device code
+ UCHAR byte6; // device select register image
+ UCHAR spigot; // spigot number
+ UCHAR expectingIRQ; // flag for expecting and interrupt
+ USHORT sectors; // number of sectors per track
+ USHORT heads; // number of heads
+ USHORT cylinders; // number of cylinders for this device
+ USHORT spareword; // placeholder
+ ULONG blocks; // number of blocks on device
+ } OUR_DEVICE, *POUR_DEVICE;
+
+typedef struct
+ {
+ USHORT ports[13];
+ OUR_DEVICE device[8];
+ Scsi_Cmnd *pSCmnd;
+ IDE_STRUCT ide;
+ ULONG startSector;
+ USHORT sectorCount;
+ Scsi_Cmnd *SCpnt;
+ VOID *buffer;
+ USHORT expectingIRQ;
+ } ADAPTER240I, *PADAPTER240I;
+
+#define HOSTDATA(host) ((PADAPTER240I)&host->hostdata)
+
+static struct Scsi_Host *PsiHost[6] = {NULL,}; /* One for each IRQ level (10-15) */
+static IDENTIFY_DATA identifyData;
+static SETUP ChipSetup;
+
+static USHORT portAddr[6] = {CHIP_ADRS_0, CHIP_ADRS_1, CHIP_ADRS_2, CHIP_ADRS_3, CHIP_ADRS_4, CHIP_ADRS_5};
+
+/****************************************************************
+ * Name: WriteData :LOCAL
+ *
+ * Description: Write data to device.


+ *
+ * Parameters: padapter - Pointer adapter data structure.
+ *

+ * Returns: TRUE if drive does not assert DRQ in time.
+ *
+ ****************************************************************/
+static int WriteData (PADAPTER240I padapter)
+ {
+ ULONG timer;
+ USHORT *pports = padapter->ports;
+
+ timer = jiffies + TIMEOUT_DRQ; // calculate the timeout value
+ do {
+ if ( inb_p (pports[PORT_STAT_CMD]) & IDE_STATUS_DRQ )
+ {
+ outsw (pports[PORT_DATA], padapter->buffer, (USHORT)padapter->ide.ide.ide[2] * 256);
+ return 0;
+ }


+ } while ( timer > jiffies ); // test for timeout
+

+ padapter->ide.ide.ides.cmd = 0; // null out the command byte
+ return 1;
+ }
+/****************************************************************
+ * Name: IdeCmd :LOCAL
+ *


+ * Description: Process a queued command from the SCSI manager.
+ *

+ * Parameters: padapter - Pointer adapter data structure.
+ *

+ * Returns: Zero if no error or status register contents on error.
+ *
+ ****************************************************************/
+static UCHAR IdeCmd (PADAPTER240I padapter)
+ {
+ ULONG timer;
+ USHORT *pports = padapter->ports;
+ UCHAR status;
+
+ outb_p (padapter->ide.ide.ides.spigot, pports[PORT_SEL_FAIL]); // select the spigot
+ outb_p (padapter->ide.ide.ide[6], pports[PORT_LBA_24]); // select the drive
+ timer = jiffies + TIMEOUT_READY; // calculate the timeout value
+ do {
+ status = inb_p (padapter->ports[PORT_STAT_CMD]);
+ if ( status & IDE_STATUS_DRDY )
+ {
+ outb_p (padapter->ide.ide.ide[2], pports[PORT_SECTOR_COUNT]);
+ outb_p (padapter->ide.ide.ide[3], pports[PORT_LBA_0]);
+ outb_p (padapter->ide.ide.ide[4], pports[PORT_LBA_8]);
+ outb_p (padapter->ide.ide.ide[5], pports[PORT_LBA_16]);
+ padapter->expectingIRQ = 1;
+ outb_p (padapter->ide.ide.ide[7], pports[PORT_STAT_CMD]);
+
+ if ( padapter->ide.ide.ides.cmd == IDE_CMD_WRITE_MULTIPLE )
+ return (WriteData (padapter));
+
+ return 0;
+ }


+ } while ( timer > jiffies ); // test for timeout
+

+ padapter->ide.ide.ides.cmd = 0; // null out the command byte
+ return status;
+ }
+/****************************************************************
+ * Name: SetupTransfer :LOCAL
+ *
+ * Description: Setup a data transfer command.
+ *


+ * Parameters: padapter - Pointer adapter data structure.

+ * drive - Drive/head register upper nibble only.
+ *
+ * Returns: TRUE if no data to transfer.
+ *
+ ****************************************************************/
+static int SetupTransfer (PADAPTER240I padapter, UCHAR drive)
+ {
+ if ( padapter->sectorCount )
+ {
+ *(ULONG *)padapter->ide.ide.ides.lba = padapter->startSector;
+ padapter->ide.ide.ide[6] |= drive;
+ padapter->ide.ide.ides.sectors = ( padapter->sectorCount > SECTORSXFER ) ? SECTORSXFER : padapter->sectorCount;
+ padapter->sectorCount -= padapter->ide.ide.ides.sectors; // bump the start and count for next xfer
+ padapter->startSector += padapter->ide.ide.ides.sectors;
+ return 0;
+ }
+ else
+ {
+ padapter->ide.ide.ides.cmd = 0; // null out the command byte
+ padapter->SCpnt = NULL;
+ return 1;
+ }
+ }
+/****************************************************************
+ * Name: DecodeError :LOCAL
+ *
+ * Description: Decode and process device errors.
+ *
+ * Parameters: pshost - Pointer to host data block.
+ * status - Status register code.
+ *
+ * Returns: The driver status code.
+ *
+ ****************************************************************/
+static ULONG DecodeError (struct Scsi_Host *pshost, UCHAR status)
+ {
+ PADAPTER240I padapter = HOSTDATA(pshost);
+ UCHAR error;
+
+ padapter->expectingIRQ = 0;
+ padapter->SCpnt = NULL;
+ if ( status & IDE_STATUS_WRITE_FAULT )
+ {
+ return DID_PARITY << 16;
+ }
+ if ( status & IDE_STATUS_BUSY )
+ return DID_BUS_BUSY << 16;
+
+ error = inb_p (padapter->ports[PORT_ERROR]);
+ DEB(printk ("\npsi240i error register: %x", error));
+ switch ( error )
+ {
+ case IDE_ERROR_AMNF:
+ case IDE_ERROR_TKONF:
+ case IDE_ERROR_ABRT:
+ case IDE_ERROR_IDFN:
+ case IDE_ERROR_UNC:
+ case IDE_ERROR_BBK:
+ default:
+ return DID_ERROR << 16;
+ }
+ return DID_ERROR << 16;


+ }
+/****************************************************************
+ * Name: Irq_Handler :LOCAL
+ *
+ * Description: Interrupt handler.
+ *
+ * Parameters: irq - Hardware IRQ number.
+ * dev_id -
+ * regs -
+ *
+ * Returns: TRUE if drive is not ready in time.
+ *
+ ****************************************************************/
+static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
+ {

+ struct Scsi_Host *shost; // Pointer to host data block
+ PADAPTER240I padapter; // Pointer to adapter control structure
+ USHORT *pports; // I/O port array
+ Scsi_Cmnd *SCpnt;
+ UCHAR status;
+ int z;
+
+ DEB(printk ("\npsi240i recieved interrupt\n"));
+
+ shost = PsiHost[irq - 10];


+ if ( !shost )

+ panic ("Splunge!");


+
+ padapter = HOSTDATA(shost);

+ pports = padapter->ports;
+ SCpnt = padapter->SCpnt;
+
+ if ( !padapter->expectingIRQ )
+ {
+ DEB(printk ("\npsi240i Unsolicited interrupt\n"));
+ return;
+ }
+ padapter->expectingIRQ = 0;
+
+ status = inb_p (padapter->ports[PORT_STAT_CMD]); // read the device status
+ if ( status & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT) )
+ goto irqerror;
+
+ DEB(printk ("\npsi240i processing interrupt"));
+ switch ( padapter->ide.ide.ides.cmd ) // decide how to handle the interrupt
+ {
+ case IDE_CMD_READ_MULTIPLE:
+ if ( status & IDE_STATUS_DRQ )
+ {
+ insw (pports[PORT_DATA], padapter->buffer, (USHORT)padapter->ide.ide.ides.sectors * 256);
+ padapter->buffer += padapter->ide.ide.ides.sectors * 512;
+ if ( SetupTransfer (padapter, padapter->ide.ide.ide[6] & 0xF0) )
+ {
+ SCpnt->result = DID_OK << 16;
+ padapter->SCpnt = NULL;
+ SCpnt->scsi_done (SCpnt);
+ return;
+ }
+ if ( !(status = IdeCmd (padapter)) )
+ return;
+ }
+ break;
+
+ case IDE_CMD_WRITE_MULTIPLE:
+ padapter->buffer += padapter->ide.ide.ides.sectors * 512;
+ if ( SetupTransfer (padapter, padapter->ide.ide.ide[6] & 0xF0) )
+ {
+ SCpnt->result = DID_OK << 16;
+ padapter->SCpnt = NULL;
+ SCpnt->scsi_done (SCpnt);
+ return;
+ }
+ if ( !(status = IdeCmd (padapter)) )
+ return;
+ break;
+
+ case IDE_COMMAND_IDENTIFY:
+ {
+ PINQUIRYDATA pinquiryData = SCpnt->request_buffer;
+
+ if ( status & IDE_STATUS_DRQ )
+ {
+ insw (pports[PORT_DATA], &identifyData, sizeof (identifyData) >> 1);
+
+ memset (pinquiryData, 0, SCpnt->request_bufflen); // Zero INQUIRY data structure.
+ pinquiryData->DeviceType = 0;
+ pinquiryData->Versions = 2;
+ pinquiryData->AdditionalLength = 35 - 4;
+
+ // Fill in vendor identification fields.
+ for ( z = 0; z < 20; z += 2 )
+ {
+ pinquiryData->VendorId[z] = ((UCHAR *)identifyData.ModelNumber)[z + 1];
+ pinquiryData->VendorId[z + 1] = ((UCHAR *)identifyData.ModelNumber)[z];
+ }
+
+ // Initialize unused portion of product id.
+ for ( z = 0; z < 4; z++ )
+ pinquiryData->ProductId[12 + z] = ' ';
+
+ // Move firmware revision from IDENTIFY data to
+ // product revision in INQUIRY data.
+ for ( z = 0; z < 4; z += 2 )
+ {
+ pinquiryData->ProductRevisionLevel[z] = ((UCHAR *)identifyData.FirmwareRevision)[z + 1];
+ pinquiryData->ProductRevisionLevel[z + 1] = ((UCHAR *)identifyData.FirmwareRevision)[z];
+ }
+
+ SCpnt->result = DID_OK << 16;
+ padapter->SCpnt = NULL;
+ SCpnt->scsi_done (SCpnt);
+ return;


+ }
+ break;
+ }
+

+ default:
+ SCpnt->result = DID_OK << 16;
+ padapter->SCpnt = NULL;
+ SCpnt->scsi_done (SCpnt);
+ return;
+ }
+
+irqerror:;
+ DEB(printk ("\npsi240i error Device Status: %X\n", status));
+ SCpnt->result = DecodeError (shost, status);


+ SCpnt->scsi_done (SCpnt);
+ }
+/****************************************************************

+ * Name: Psi240i_QueueCommand


+ *
+ * Description: Process a queued command from the SCSI manager.
+ *
+ * Parameters: SCpnt - Pointer to SCSI command structure.
+ * done - Pointer to done function to call.
+ *
+ * Returns: Status code.
+ *
+ ****************************************************************/

+int Psi240i_QueueCommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))


+ {
+ UCHAR *cdb = (UCHAR *)SCpnt->cmnd; // Pointer to SCSI CDB

+ PADAPTER240I padapter = HOSTDATA(SCpnt->host); // Pointer to adapter control structure
+ POUR_DEVICE pdev = &padapter->device[SCpnt->target];// Pointer to device information
+ UCHAR rc; // command return code
+


+ SCpnt->scsi_done = done;

+ padapter->ide.ide.ides.spigot = pdev->spigot;
+ padapter->buffer = SCpnt->request_buffer;
+ if (done)
+ {
+ if ( !pdev->device || SCpnt->lun )
+ {
+ SCpnt->result = DID_BAD_TARGET << 16;
+ done (SCpnt);


+ return 0;
+ }
+ }

+ else
+ {
+ printk("psi240i_queuecommand: %02X: done can't be NULL\n", *cdb);


+ return 0;
+ }
+

+ switch ( *cdb )
+ {
+ case SCSIOP_INQUIRY: // inquiry CDB

+ {
+ padapter->ide.ide.ide[6] = pdev->byte6;
+ padapter->ide.ide.ides.cmd = IDE_COMMAND_IDENTIFY;
+ break;
+ }
+


+ case SCSIOP_TEST_UNIT_READY: // test unit ready CDB

+ SCpnt->result = DID_OK << 16;
+ done (SCpnt);
+ return 0;
+


+ case SCSIOP_READ_CAPACITY: // read capctiy CDB

+ {
+ PREAD_CAPACITY_DATA pdata = (PREAD_CAPACITY_DATA)SCpnt->request_buffer;
+
+ pdata->blksiz = 0x20000;
+ XANY2SCSI ((UCHAR *)&pdata->blks, pdev->blocks);
+ SCpnt->result = DID_OK << 16;
+ done (SCpnt);


+ return 0;
+ }
+

+ case SCSIOP_VERIFY: // verify CDB

+ *(ULONG *)padapter->ide.ide.ides.lba = XSCSI2LONG (&cdb[2]);
+ padapter->ide.ide.ide[6] |= pdev->byte6;
+ padapter->ide.ide.ide[2] = (UCHAR)((USHORT)cdb[8] | ((USHORT)cdb[7] << 8));
+ padapter->ide.ide.ides.cmd = IDE_COMMAND_VERIFY;
+ break;
+


+ case SCSIOP_READ: // read10 CDB

+ padapter->startSector = XSCSI2LONG (&cdb[2]);
+ padapter->sectorCount = (USHORT)cdb[8] | ((USHORT)cdb[7] << 8);
+ SetupTransfer (padapter, pdev->byte6);
+ padapter->ide.ide.ides.cmd = IDE_CMD_READ_MULTIPLE;
+ break;
+


+ case SCSIOP_READ6: // read6 CDB

+ padapter->startSector = SCSI2LONG (&cdb[1]);
+ padapter->sectorCount = cdb[4];
+ SetupTransfer (padapter, pdev->byte6);
+ padapter->ide.ide.ides.cmd = IDE_CMD_READ_MULTIPLE;
+ break;
+


+ case SCSIOP_WRITE: // write10 CDB

+ padapter->startSector = XSCSI2LONG (&cdb[2]);
+ padapter->sectorCount = (USHORT)cdb[8] | ((USHORT)cdb[7] << 8);
+ SetupTransfer (padapter, pdev->byte6);
+ padapter->ide.ide.ides.cmd = IDE_CMD_WRITE_MULTIPLE;


+ break;
+ case SCSIOP_WRITE6: // write6 CDB

+ padapter->startSector = SCSI2LONG (&cdb[1]);
+ padapter->sectorCount = cdb[4];
+ SetupTransfer (padapter, pdev->byte6);
+ padapter->ide.ide.ides.cmd = IDE_CMD_WRITE_MULTIPLE;
+ break;
+
+ default:
+ DEB (printk ("psi240i_queuecommand: Unsupported command %02X\n", *cdb));
+ SCpnt->result = DID_ERROR << 16;
+ done (SCpnt);


+ return 0;
+ }
+

+ padapter->SCpnt = SCpnt; // Save this command data
+
+ rc = IdeCmd (padapter);
+ if ( rc )
+ {
+ padapter->expectingIRQ = 0;
+ DEB (printk ("psi240i_queuecommand: %02X, %02X: Device failed to respond for command\n", *cdb, padapter->ide.ide.ides.cmd));
+ SCpnt->result = DID_ERROR << 16;
+ done (SCpnt);
+ return 0;
+ }
+ DEB (printk("psi240i_queuecommand: %02X, %02X now waiting for interrupt ", *cdb, padapter->ide.ide.ides.cmd));


+ return 0;
+ }
+

+static void internal_done(Scsi_Cmnd * SCpnt)


+ {
+ SCpnt->SCp.Status++;
+ }
+/****************************************************************

+ * Name: Psi240i_Command


+ *
+ * Description: Process a command from the SCSI manager.
+ *
+ * Parameters: SCpnt - Pointer to SCSI command structure.
+ *
+ * Returns: Status code.
+ *
+ ****************************************************************/

+int Psi240i_Command (Scsi_Cmnd *SCpnt)
+ {
+ DEB(printk("psi240i_command: ..calling psi240i_queuecommand\n"));
+
+ Psi240i_QueueCommand (SCpnt, internal_done);


+
+ SCpnt->SCp.Status = 0;
+ while (!SCpnt->SCp.Status)
+ barrier ();
+ return SCpnt->result;
+ }

+/***************************************************************************
+ * Name: ReadChipMemory
+ *
+ * Description: Read information from controller memory.
+ *
+ * Parameters: psetup - Pointer to memory image of setup information.
+ * base - base address of memory.
+ * length - lenght of data space in bytes.
+ * port - I/O address of data port.


+ *
+ * Returns: Nothing.
+ *

+ **************************************************************************/
+void ReadChipMemory (void *pdata, USHORT base, USHORT length, USHORT port)
+ {
+ USHORT z, zz;
+ UCHAR *pd = (UCHAR *)pdata;
+ outb_p (SEL_NONE, port + REG_SEL_FAIL); // setup data port
+ zz = 0;
+ while ( zz < length )
+ {
+ outw_p (base, port + REG_ADDRESS); // setup address
+
+ for ( z = 0; z < 8; z++ )
+ {
+ if ( (zz + z) < length )
+ *pd++ = inb_p (port + z); // read data byte
+ }
+ zz += 8;
+ base += 8;
+ }
+ }
+/****************************************************************
+ * Name: Psi240i_Detect


+ *
+ * Description: Detect and initialize our boards.
+ *
+ * Parameters: tpnt - Pointer to SCSI host template structure.
+ *
+ * Returns: Number of adapters found.
+ *
+ ****************************************************************/

+int Psi240i_Detect (Scsi_Host_Template *tpnt)
+ {
+ int board;


+ int count = 0;

+ int unit;
+ int z;
+ USHORT port;
+ CHIP_CONFIG_N chipConfig;
+ CHIP_DEVICE_N chipDevice[8];
+ struct Scsi_Host *pshost;
+ ULONG flags;
+
+ for ( board = 0; board < 6; board++ ) // scan for I/O ports
+ {
+ port = portAddr[board]; // get base address to test
+ if ( check_region (port, 16) ) // test for I/O addresses available
+ continue; // nope
+ if ( inb_p (port + REG_FAIL) != CHIP_ID ) // do the first test for likley hood that it is us
+ continue;
+ outb_p (SEL_NONE, port + REG_SEL_FAIL); // setup EEPROM/RAM access
+ outw (0, port + REG_ADDRESS); // setup EEPROM address zero
+ if ( inb_p (port) != 0x55 ) // test 1st byte
+ continue; // nope
+ if ( inb_p (port + 1) != 0xAA ) // test 2nd byte
+ continue; // nope
+
+ // at this point our board is found and can be accessed. Now we need to initialize
+ // our informatation and register with the kernel.
+
+
+ ReadChipMemory (&chipConfig, CHIP_CONFIG, sizeof (chipConfig), port);
+ ReadChipMemory (&chipDevice, CHIP_DEVICE, sizeof (chipDevice), port);
+ ReadChipMemory (&ChipSetup, CHIP_EEPROM_DATA, sizeof (ChipSetup), port);
+
+ if ( !chipConfig.numDrives ) // if no devices on this board
+ continue;
+
+ pshost = scsi_register (tpnt, sizeof(ADAPTER240I));
+
+ save_flags (flags);
+ cli ();
+ if ( request_irq (chipConfig.irq, Irq_Handler, 0, "psi240i", NULL) )
+ {
+ printk ("Unable to allocate IRQ for PSI-240I controller.\n");
+ restore_flags (flags);


+ goto unregister;
+ }
+

+ PsiHost[chipConfig.irq - 10] = pshost;
+ pshost->unique_id = port;
+ pshost->io_port = port;
+ pshost->n_io_port = 16; /* Number of bytes of I/O space used */
+ pshost->irq = chipConfig.irq;
+
+ for ( z = 0; z < 11; z++ ) // build regester address array
+ HOSTDATA(pshost)->ports[z] = port + z;
+ HOSTDATA(pshost)->ports[11] = port + REG_FAIL;
+ HOSTDATA(pshost)->ports[12] = port + REG_ALT_STAT;
+ DEB (printk ("\nPorts ="));
+ DEB (for (z=0;z<13;z++) printk(" %#04X",HOSTDATA(pshost)->ports[z]););
+
+ for ( z = 0; z < chipConfig.numDrives; ++z )
+ {
+ unit = chipDevice[z].channel & 0x0F;
+ HOSTDATA(pshost)->device[unit].device = ChipSetup.setupDevice[unit].device;


SHAR_EOF
true || echo 'restore of patch-2.0.37 failed'
fi

echo 'End of part 35'
echo 'File patch-2.0.37 is continued in part 36'
echo 36 > _shar_seq_.tmp

Thomas...@ciw.uni-karlsruhe.de

unread,
Jun 16, 1999, 3:00:00 AM6/16/99
to
Archive-name: v2.0/patch-2.0.37/part36

#!/bin/sh
# this is part 36 of a 45 - part archive


# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.0.37 continued
if test ! -r _shar_seq_.tmp; then
echo 'Please unpack part 1 first!'
exit 1
fi
(read Scheck

if test "$Scheck" != 36; then


echo Please unpack part "$Scheck" next!
exit 1
else
exit 0
fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.0.37'
else
echo 'x - continuing with patch-2.0.37'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.0.37' &&

+ HOSTDATA(pshost)->device[unit].byte6 = (UCHAR)(((unit & 1) << 4) | 0xE0);
+ HOSTDATA(pshost)->device[unit].spigot = (UCHAR)(1 << (unit >> 1));
+ HOSTDATA(pshost)->device[unit].sectors = ChipSetup.setupDevice[unit].sectors;
+ HOSTDATA(pshost)->device[unit].heads = ChipSetup.setupDevice[unit].heads;
+ HOSTDATA(pshost)->device[unit].cylinders = ChipSetup.setupDevice[unit].cylinders;
+ HOSTDATA(pshost)->device[unit].blocks = ChipSetup.setupDevice[unit].blocks;
+ DEB (printk ("\nHOSTDATA->device = %X", HOSTDATA(pshost)->device[unit].device));
+ DEB (printk ("\n byte6 = %X", HOSTDATA(pshost)->device[unit].byte6));
+ DEB (printk ("\n spigot = %X", HOSTDATA(pshost)->device[unit].spigot));
+ DEB (printk ("\n sectors = %X", HOSTDATA(pshost)->device[unit].sectors));
+ DEB (printk ("\n heads = %X", HOSTDATA(pshost)->device[unit].heads));
+ DEB (printk ("\n cylinders = %X", HOSTDATA(pshost)->device[unit].cylinders));
+ DEB (printk ("\n blocks = %lX", HOSTDATA(pshost)->device[unit].blocks));
+ }
+
+ restore_flags (flags);
+ printk("\nPSI-240I EIDE CONTROLLER: at I/O = %x IRQ = %d\n", port, chipConfig.irq);


+ printk("(C) 1997 Perceptive Solutions, Inc. All rights reserved\n\n");

+ count++;
+ continue;
+


+unregister:;
+ scsi_unregister (pshost);
+ }

+ return count;
+ }
+/****************************************************************
+ * Name: Psi240i_Abort


+ *
+ * Description: Process the Abort command from the SCSI manager.
+ *
+ * Parameters: SCpnt - Pointer to SCSI command structure.
+ *
+ * Returns: Allways snooze.
+ *
+ ****************************************************************/

+int Psi240i_Abort (Scsi_Cmnd *SCpnt)
+ {
+ DEB (printk ("psi240i_abort\n"));


+ return SCSI_ABORT_SNOOZE;
+ }
+/****************************************************************

+ * Name: Psi240i_Reset


+ *
+ * Description: Process the Reset command from the SCSI manager.
+ *
+ * Parameters: SCpnt - Pointer to SCSI command structure.
+ * flags - Flags about the reset command
+ *
+ * Returns: No active command at this time, so this means
+ * that each time we got some kind of response the
+ * last time through. Tell the mid-level code to
+ * request sense information in order to decide what
+ * to do next.
+ *
+ ****************************************************************/

+int Psi240i_Reset (Scsi_Cmnd *SCpnt, unsigned int reset_flags)


+ {
+ return SCSI_RESET_PUNT;
+ }
+
+#include "sd.h"
+
+/****************************************************************

+ * Name: Psi240i_BiosParam


+ *
+ * Description: Process the biosparam request from the SCSI manager to
+ * return C/H/S data.
+ *
+ * Parameters: disk - Pointer to SCSI disk structure.
+ * dev - Major/minor number from kernel.
+ * geom - Pointer to integer array to place geometry data.
+ *
+ * Returns: zero.
+ *
+ ****************************************************************/

+int Psi240i_BiosParam (Scsi_Disk *disk, kdev_t dev, int geom[])


+ {
+ POUR_DEVICE pdev;
+
+ pdev = &(HOSTDATA(disk->device->host)->device[disk->device->id]);
+
+ geom[0] = pdev->heads;
+ geom[1] = pdev->sectors;
+ geom[2] = pdev->cylinders;
+ return 0;
+ }
+
+
+#ifdef MODULE
+/* Eventually this will go into an include file, but this will be later */

+Scsi_Host_Template driver_template = PSI240I;


+
+#include "scsi_module.c"
+#endif
+

diff -u --recursive --new-file v2.0.36/linux/drivers/scsi/psi240i.h linux/drivers/scsi/psi240i.h
--- v2.0.36/linux/drivers/scsi/psi240i.h Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/psi240i.h Sun Jun 13 10:21:02 1999
@@ -0,0 +1,344 @@


+/*+M*************************************************************************
+ * Perceptive Solutions, Inc. PSI-240I device driver proc support for Linux.
+ *
+ * Copyright (c) 1997 Perceptive Solutions, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *

+ * File Name: psi240i.h
+ *
+ * Description: Header file for the SCSI driver for the PSI240I


+ * EIDE interface card.
+ *
+ *-M*************************************************************************/

+#ifndef _PSI240I_H
+#define _PSI240I_H

+int Psi240i_Detect (Scsi_Host_Template *tpnt);
+int Psi240i_Command (Scsi_Cmnd *SCpnt);
+int Psi240i_QueueCommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *));
+int Psi240i_Abort (Scsi_Cmnd *SCpnt);
+int Psi240i_Reset (Scsi_Cmnd *SCpnt, unsigned int flags);
+int Psi240i_BiosParam (Disk *disk, kdev_t dev, int geom[]);


+
+#ifndef NULL
+ #define NULL 0
+#endif
+

+extern struct proc_dir_entry Proc_Scsi_Psi240i;
+
+#define PSI240I { NULL, NULL, \
+ &Proc_Scsi_Psi240i,/* proc_dir_entry */ \
+ NULL, \
+ "PSI-240I EIDE Disk Controller", \
+ Psi240i_Detect, \
+ NULL, \
+ NULL, \
+ Psi240i_Command, \
+ Psi240i_QueueCommand, \
+ Psi240i_Abort, \
+ Psi240i_Reset, \
+ NULL, \
+ Psi240i_BiosParam, \


+ 1, \
+ -1, \
+ SG_NONE, \
+ 1, \
+ 0, \
+ 0, \
+ DISABLE_CLUSTERING }
+
+#endif

diff -u --recursive --new-file v2.0.36/linux/drivers/scsi/psi_chip.h linux/drivers/scsi/psi_chip.h
--- v2.0.36/linux/drivers/scsi/psi_chip.h Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/psi_chip.h Sun Jun 13 10:21:02 1999
@@ -0,0 +1,194 @@


+/*+M*************************************************************************
+ * Perceptive Solutions, Inc. PSI-240I device driver proc support for Linux.
+ *
+ * Copyright (c) 1997 Perceptive Solutions, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *

+ * File Name: psi_chip.h
+ *
+ * Description: This file contains the interface defines and
+ * error codes.
+ *
+ *-M*************************************************************************/
+#ifndef PSI_CHIP
+#define PSI_CHIP
+
+/************************************************/
+/* Misc konstants */
+/************************************************/
+#define CHIP_MAXDRIVES 8
+
+/************************************************/
+/* Chip I/O addresses */
+/************************************************/
+#define CHIP_ADRS_0 0x0130
+#define CHIP_ADRS_1 0x0150
+#define CHIP_ADRS_2 0x0190
+#define CHIP_ADRS_3 0x0210
+#define CHIP_ADRS_4 0x0230
+#define CHIP_ADRS_5 0x0250
+
+/************************************************/
+/* EEPROM locations */
+/************************************************/
+#define CHIP_EEPROM_BIOS 0x0000 // BIOS base address
+#define CHIP_EEPROM_DATA 0x2000 // SETUP data base address
+#define CHIP_EEPROM_FACTORY 0x2400 // FACTORY data base address
+#define CHIP_EEPROM_SETUP 0x3000 // SETUP PROGRAM base address
+
+#define CHIP_EEPROM_SIZE 32768U // size of the entire EEPROM
+#define CHIP_EEPROM_BIOS_SIZE 8192 // size of the BIOS in bytes
+#define CHIP_EEPROM_DATA_SIZE 4096 // size of factory, setup, log data block in bytes
+#define CHIP_EEPROM_SETUP_SIZE 20480U // size of the setup program in bytes
+
+/************************************************/
+/* Chip Interrupts */
+/************************************************/
+#define CHIP_IRQ_10 0x72
+#define CHIP_IRQ_11 0x73
+#define CHIP_IRQ_12 0x74
+
+/************************************************/
+/* Chip Setup addresses */
+/************************************************/
+#define CHIP_SETUP_BASE 0x0000C000L
+
+/************************************************/
+/* Chip Register address offsets */
+/************************************************/
+#define REG_DATA 0x00
+#define REG_ERROR 0x01
+#define REG_SECTOR_COUNT 0x02
+#define REG_LBA_0 0x03
+#define REG_LBA_8 0x04
+#define REG_LBA_16 0x05
+#define REG_LBA_24 0x06
+#define REG_STAT_CMD 0x07
+#define REG_SEL_FAIL 0x08
+#define REG_IRQ_STATUS 0x09
+#define REG_ADDRESS 0x0A
+#define REG_FAIL 0x0C
+#define REG_ALT_STAT 0x0E
+#define REG_DRIVE_ADRS 0x0F
+
+/************************************************/
+/* Chip RAM locations */
+/************************************************/
+#define CHIP_DEVICE 0x8000
+#define CHIP_DEVICE_0 0x8000
+#define CHIP_DEVICE_1 0x8008
+#define CHIP_DEVICE_2 0x8010
+#define CHIP_DEVICE_3 0x8018
+#define CHIP_DEVICE_4 0x8020
+#define CHIP_DEVICE_5 0x8028
+#define CHIP_DEVICE_6 0x8030
+#define CHIP_DEVICE_7 0x8038
+typedef struct
+ {
+ UCHAR channel; // channel of this device (0-8).
+ UCHAR spt; // Sectors Per Track.
+ ULONG spc; // Sectors Per Cylinder.
+ } CHIP_DEVICE_N;
+
+#define CHIP_CONFIG 0x8100 // address of boards configuration.
+typedef struct
+ {
+ UCHAR irq; // interrupt request channel number
+ UCHAR numDrives; // Number of accessable drives
+ UCHAR fastFormat; // Boolean for fast format enable
+ } CHIP_CONFIG_N;
+
+#define CHIP_MAP 0x8108 // eight byte device type map.
+
+
+#define CHIP_RAID 0x8120 // array of RAID signature structures and LBA
+#define CHIP_RAID_1 0x8120
+#define CHIP_RAID_2 0x8130
+#define CHIP_RAID_3 0x8140
+#define CHIP_RAID_4 0x8150
+
+/************************************************/
+/* Chip Register Masks */
+/************************************************/
+#define CHIP_ID 0x7B
+#define SEL_RAM 0x8000
+#define MASK_FAIL 0x80
+
+/************************************************/
+/* Chip cable select bits */
+/************************************************/
+#define SECTORSXFER 8
+
+/************************************************/
+/* Chip cable select bits */
+/************************************************/
+#define SEL_NONE 0x00
+#define SEL_1 0x01
+#define SEL_2 0x02
+#define SEL_3 0x04
+#define SEL_4 0x08
+
+/************************************************/
+/* Programmable Interrupt Controller*/
+/************************************************/
+#define PIC1 0x20 // first 8259 base port address
+#define PIC2 0xA0 // second 8259 base port address
+#define INT_OCW1 1 // Operation Control Word 1: IRQ mask
+#define EOI 0x20 // non-specific end-of-interrupt
+
+/************************************************/
+/* Device/Geometry controls */
+/************************************************/
+#define GEOMETRY_NONE 0x0 // No device
+#define GEOMETRY_AUTO 0x1 // Geometry set automatically
+#define GEOMETRY_USER 0x2 // User supplied geometry
+
+#define DEVICE_NONE 0x0 // No device present
+#define DEVICE_INACTIVE 0x1 // device present but not registered active
+#define DEVICE_ATAPI 0x2 // ATAPI device (CD_ROM, Tape, Etc...)
+#define DEVICE_DASD_NONLBA 0x3 // Non LBA incompatible device
+#define DEVICE_DASD_LBA 0x4 // LBA compatible device
+
+/************************************************/
+/* Setup Structure Definitions */
+/************************************************/
+typedef struct // device setup parameters
+ {
+ UCHAR geometryControl; // geometry control flags


+ UCHAR device; // device code

+ USHORT sectors; // number of sectors per track
+ USHORT heads; // number of heads
+ USHORT cylinders; // number of cylinders for this device

+ ULONG blocks; // number of blocks on device

+ USHORT spare1;
+ USHORT spare2;
+ } SETUP_DEVICE, *PSETUP_DEVICE;
+
+typedef struct // master setup structure
+ {
+ USHORT startupDelay;
+ USHORT promptBIOS;
+ USHORT fastFormat;
+ USHORT spare2;
+ USHORT spare3;
+ USHORT spare4;
+ USHORT spare5;
+ USHORT spare6;
+ SETUP_DEVICE setupDevice[8];
+ } SETUP, *PSETUP;
+
+#endif
\ No newline at end of file
diff -u --recursive --new-file v2.0.36/linux/drivers/scsi/psi_dale.h linux/drivers/scsi/psi_dale.h
--- v2.0.36/linux/drivers/scsi/psi_dale.h Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/psi_dale.h Sun Jun 13 10:21:02 1999
@@ -0,0 +1,187 @@


+/*+M*************************************************************************
+ * Perceptive Solutions, Inc. PCI-2000 device driver proc support for Linux.
+ *
+ * Copyright (c) 1997 Perceptive Solutions, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *

+ * File Name: psi_dale.h
+ *
+ * Description: This file contains the interface defines and
+ * error codes.


+ *
+ *-M*************************************************************************/
+

+#ifndef PSI_DALE
+#define PSI_DALE
+
+/************************************************/
+/* Dale PCI setup */
+/************************************************/
+#define VENDOR_PSI 0x1256
+#define DEVICE_DALE_1 0x4401 /* 'D1' */
+
+/************************************************/
+/* Misc konstants */
+/************************************************/
+#define DALE_MAXDRIVES 4
+#define SECTORSXFER 8
+#define BYTES_PER_SECTOR 512
+#define DEFAULT_TIMING_MODE 5
+
+/************************************************/
+/* EEPROM locations */
+/************************************************/
+#define DALE_FLASH_PAGE_SIZE 128 // number of bytes per page
+#define DALE_FLASH_SIZE 65536L
+
+#define DALE_FLASH_BIOS 0x00080000L // BIOS base address
+#define DALE_FLASH_SETUP 0x00088000L // SETUP PROGRAM base address offset from BIOS
+#define DALE_FLASH_RAID 0x00088400L // RAID signature storage
+#define DALE_FLASH_FACTORY 0x00089000L // FACTORY data base address offset from BIOS
+
+#define DALE_FLASH_BIOS_SIZE 32768U // size of FLASH BIOS REGION
+
+/************************************************/
+/* DALE Register address offsets */
+/************************************************/
+#define REG_DATA 0x80
+#define REG_ERROR 0x84
+#define REG_SECTOR_COUNT 0x88
+#define REG_LBA_0 0x8C
+#define REG_LBA_8 0x90
+#define REG_LBA_16 0x94
+#define REG_LBA_24 0x98
+#define REG_STAT_CMD 0x9C
+#define REG_STAT_SEL 0xA0
+#define REG_FAIL 0xB0
+#define REG_ALT_STAT 0xB8
+#define REG_DRIVE_ADRS 0xBC
+
+#define DALE_DATA_SLOW 0x00040000L
+#define DALE_DATA_MODE2 0x00040000L
+#define DALE_DATA_MODE3 0x00050000L
+#define DALE_DATA_MODE4 0x00060000L
+#define DALE_DATA_MODE4P 0x00070000L
+
+#define RTR_LOCAL_RANGE 0x000
+#define RTR_LOCAL_REMAP 0x004
+#define RTR_EXP_RANGE 0x010
+#define RTR_EXP_REMAP 0x014
+#define RTR_REGIONS 0x018
+#define RTR_DM_MASK 0x01C
+#define RTR_DM_LOCAL_BASE 0x020
+#define RTR_DM_IO_BASE 0x024
+#define RTR_DM_PCI_REMAP 0x028
+#define RTR_DM_IO_CONFIG 0x02C
+#define RTR_MAILBOX 0x040
+#define RTR_LOCAL_DOORBELL 0x060
+#define RTR_PCI_DOORBELL 0x064
+#define RTR_INT_CONTROL_STATUS 0x068
+#define RTR_EEPROM_CONTROL_STATUS 0x06C
+
+#define RTL_DMA0_MODE 0x00
+#define RTL_DMA0_PCI_ADDR 0x04
+#define RTL_DMA0_LOCAL_ADDR 0x08
+#define RTL_DMA0_COUNT 0x0C
+#define RTL_DMA0_DESC_PTR 0x10
+#define RTL_DMA1_MODE 0x14
+#define RTL_DMA1_PCI_ADDR 0x18
+#define RTL_DMA1_LOCAL_ADDR 0x1C
+#define RTL_DMA1_COUNT 0x20
+#define RTL_DMA1_DESC_PTR 0x24
+#define RTL_DMA_COMMAND_STATUS 0x28
+#define RTL_DMA_ARB0 0x2C
+#define RTL_DMA_ARB1 0x30
+
+/************************************************/
+/* Dale Scratchpad locations */
+/************************************************/
+#define DALE_CHANNEL_DEVICE_0 0 // device channel locations
+#define DALE_CHANNEL_DEVICE_1 1
+#define DALE_CHANNEL_DEVICE_2 2
+#define DALE_CHANNEL_DEVICE_3 3
+
+#define DALE_SCRATH_DEVICE_0 4 // device type codes
+#define DALE_SCRATH_DEVICE_1 5
+#define DALE_SCRATH_DEVICE_2 6
+#define DALE_SCRATH_DEVICE_3 7
+
+#define DALE_RAID_0_STATUS 8
+#define DALE_RAID_1_STATUS 9
+
+#define DALE_TIMING_MODE 12 // bus master timing mode (2, 3, 4, 5)
+#define DALE_NUM_DRIVES 13 // number of addressable drives on this board
+#define DALE_RAID_ON 14 // RAID status On
+#define DALE_LAST_ERROR 15 // Last error code from BIOS
+
+/************************************************/
+/* Dale cable select bits */
+/************************************************/
+#define SEL_NONE 0x00
+#define SEL_1 0x01
+#define SEL_2 0x02
+
+/************************************************/
+/* Programmable Interrupt Controller */
+/************************************************/
+#define PIC1 0x20 // first 8259 base port address
+#define PIC2 0xA0 // second 8259 base port address
+#define INT_OCW1 1 // Operation Control Word 1: IRQ mask
+#define EOI 0x20 // non-specific end-of-interrupt
+
+/************************************************/
+/* Device/Geometry controls */
+/************************************************/
+#define GEOMETRY_NONE 0x0 // No device
+#define GEOMETRY_SET 0x1 // Geometry set
+#define GEOMETRY_LBA 0x2 // Geometry set in default LBA mode
+#define GEOMETRY_PHOENIX 0x3 // Geometry set in Pheonix BIOS compatibility mode
+
+#define DEVICE_NONE 0x0 // No device present
+#define DEVICE_INACTIVE 0x1 // device present but not registered active
+#define DEVICE_ATAPI 0x2 // ATAPI device (CD_ROM, Tape, Etc...)
+#define DEVICE_DASD_NONLBA 0x3 // Non LBA incompatible device
+#define DEVICE_DASD_LBA 0x4 // LBA compatible device
+
+/************************************************/
+/* Setup Structure Definitions */
+/************************************************/
+typedef struct // device setup parameters
+ {
+ UCHAR geometryControl; // geometry control flags


+ UCHAR device; // device code

+ USHORT sectors; // number of sectors per track
+ USHORT heads; // number of heads
+ USHORT cylinders; // number of cylinders for this device

+ ULONG blocks; // number of blocks on device

+ ULONG realCapacity; // number of real blocks on this device for drive changed testing
+ } SETUP_DEVICE, *PSETUP_DEVICE;
+
+typedef struct // master setup structure
+ {
+ USHORT startupDelay;
+ BOOL promptBIOS;
+ BOOL fastFormat;
+ BOOL shareInterrupt;
+ BOOL rebootRebuil;
+ USHORT timingMode;
+ USHORT spare5;
+ USHORT spare6;
+ SETUP_DEVICE setupDevice[4];
+ } SETUP, *PSETUP;
+
+#endif
diff -u --recursive --new-file v2.0.36/linux/drivers/scsi/psi_roy.h linux/drivers/scsi/psi_roy.h
--- v2.0.36/linux/drivers/scsi/psi_roy.h Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/psi_roy.h Sun Jun 13 10:21:02 1999
@@ -0,0 +1,337 @@


+/*+M*************************************************************************
+ * Perceptive Solutions, Inc. PCI-2000 device driver proc support for Linux.
+ *
+ * Copyright (c) 1997 Perceptive Solutions, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *

+ * File Name: psi_roy.h
+ *
+ * Description: This file contains the host interface command and
+ * error codes.


+ *
+ *-M*************************************************************************/
+

+#ifndef ROY_HOST
+#define ROY_HOST
+
+/************************************************/
+/* PCI setup */
+/************************************************/
+#define VENDOR_PSI 0x1256
+#define DEVICE_ROY_1 0x5201 /* 'R1' */
+
+/************************************************/
+/* controller constants */
+/************************************************/
+#define MAXADAPTER 4 // Increase this and the sizes of the arrays below, if you need more.
+#define MAX_BUS 2
+#define MAX_UNITS 16
+#define TIMEOUT_COMMAND 30 // number of jiffies for command busy timeout
+
+/************************************************/
+/* I/O address offsets */
+/************************************************/
+#define RTR_MAILBOX 0x040
+#define RTR_LOCAL_DOORBELL 0x060
+#define RTR_PCI_DOORBELL 0x064
+
+/************************************************/
+/* */
+/* Host command codes */
+/* */
+/************************************************/
+#define CMD_READ_CHS 0x01 /* read sectors as specified (CHS mode) */
+#define CMD_READ 0x02 /* read sectors as specified (RBA mode) */
+#define CMD_READ_SG 0x03 /* read sectors using scatter/gather list */
+#define CMD_WRITE_CHS 0x04 /* write sectors as specified (CHS mode) */
+#define CMD_WRITE 0x05 /* write sectors as specified (RBA mode) */
+#define CMD_WRITE_SG 0x06 /* write sectors using scatter/gather list (LBA mode) */
+#define CMD_READ_CHS_SG 0x07 /* read sectors using scatter/gather list (CHS mode) */
+#define CMD_WRITE_CHS_SG 0x08 /* write sectors using scatter/gather list (CHS mode) */
+#define CMD_VERIFY_CHS 0x09 /* verify data on sectors as specified (CHS mode) */
+#define CMD_VERIFY 0x0A /* verify data on sectors as specified (RBA mode) */
+#define CMD_DASD_CDB 0x0B /* process CDB for a DASD device */
+#define CMD_DASD_CDB_SG 0x0C /* process CDB for a DASD device with scatter/gather */
+
+#define CMD_READ_ABS 0x10 /* read absolute disk */
+#define CMD_WRITE_ABS 0x11 /* write absolute disk */
+#define CMD_VERIFY_ABS 0x12 /* verify absolute disk */
+#define CMD_TEST_READY 0x13 /* test unit ready and return status code */
+#define CMD_LOCK_DOOR 0x14 /* lock device door */
+#define CMD_UNLOCK_DOOR 0x15 /* unlock device door */
+#define CMD_EJECT_MEDIA 0x16 /* eject the media */
+#define CMD_UPDATE_CAP 0x17 /* update capacity information */
+#define CMD_TEST_PRIV 0x18 /* test and setup private format media */
+
+
+#define CMD_SCSI_THRU 0x30 /* SCSI pass through CDB */
+#define CMD_SCSI_THRU_SG 0x31 /* SCSI pass through CDB with scatter/gather */
+#define CMD_SCSI_REQ_SENSE 0x32 /* SCSI pass through request sense after check condition */
+
+#define CMD_DASD_RAID_RQ 0x35 /* request DASD RAID drive data */
+#define CMD_DASD_RAID_RQ0 0x31 /* byte 1 subcommand to query for RAID 0 informatation */
+#define CMD_DASD_RAID_RQ1 0x32 /* byte 1 subcommand to query for RAID 1 informatation */
+#define CMD_DASD_RAID_RQ5 0x33 /* byte 1 subcommand to query for RAID 5 informatation */
+
+#define CMD_DASD_SCSI_INQ 0x36 /* do DASD inquire and return in SCSI format */
+#define CMD_DASD_CAP 0x37 /* read DASD capacity */
+#define CMD_DASD_INQ 0x38 /* do DASD inquire for type data and return SCSI/EIDE inquiry */
+#define CMD_SCSI_INQ 0x39 /* do SCSI inquire */
+#define CMD_READ_SETUP 0x3A /* Get setup structures from controller */
+#define CMD_WRITE_SETUP 0x3B /* Put setup structures in controller and burn in flash */
+#define CMD_READ_CONFIG 0x3C /* Get the entire configuration and setup structures */
+#define CMD_WRITE_CONFIG 0x3D /* Put the entire configuration and setup structures in flash */
+
+#define CMD_TEXT_DEVICE 0x3E /* obtain device text */
+#define CMD_TEXT_SIGNON 0x3F /* get sign on banner */
+
+#define CMD_QUEUE 0x40 /* any command below this generates a queue tag interrupt to host*/
+
+#define CMD_PREFETCH 0x40 /* prefetch sectors as specified */
+#define CMD_TEST_WRITE 0x41 /* Test a device for write protect */
+#define CMD_LAST_STATUS 0x42 /* get last command status and error data*/
+#define CMD_ABORT 0x43 /* abort command as specified */
+#define CMD_ERROR 0x44 /* fetch error code from a tagged op */
+#define CMD_DONE 0x45 /* done with operation */
+#define CMD_DIAGNOSTICS 0x46 /* execute controller diagnostics and wait for results */
+#define CMD_FEATURE_MODE 0x47 /* feature mode control word */
+#define CMD_DASD_INQUIRE 0x48 /* inquire as to DASD SCSI device (32 possible) */
+#define CMD_FEATURE_QUERY 0x49 /* query the feature control word */
+#define CMD_DASD_EJECT 0x4A /* Eject removable media for DASD type */
+#define CMD_DASD_LOCK 0x4B /* Lock removable media for DASD type */
+#define CMD_DASD_TYPE 0x4C /* obtain DASD device type */
+#define CMD_NUM_DEV 0x4D /* obtain the number of devices connected to the controller */
+#define CMD_GET_PARMS 0x4E /* obtain device parameters */
+#define CMD_SPECIFY 0x4F /* specify operating system for scatter/gather operations */
+
+#define CMD_RAID_GET_DEV 0x50 /* read RAID device geometry */
+#define CMD_RAID_READ 0x51 /* read RAID 1 parameter block */
+#define CMD_RAID_WRITE 0x52 /* write RAID 1 parameter block */
+#define CMD_RAID_LITEUP 0x53 /* Light up the drive light for identification */
+#define CMD_RAID_REBUILD 0x54 /* issue a RAID 1 pair rebuild */
+#define CMD_RAID_MUTE 0x55 /* mute RAID failure alarm */
+#define CMD_RAID_FAIL 0x56 /* induce a RAID failure */
+#define CMD_RAID_STATUS 0x57 /* get status of RAID pair */
+#define CMD_RAID_STOP 0x58 /* stop any reconstruct in progress */
+#define CMD_RAID_START 0x59 /* start reconstruct */
+#define CMD_RAID0_READ 0x5A /* read RAID 0 parameter block */
+#define CMD_RAID0_WRITE 0x5B /* write RAID 0 parameter block */
+#define CMD_RAID5_READ 0x5C /* read RAID 5 parameter block */
+#define CMD_RAID5_WRITE 0x5D /* write RAID 5 parameter block */
+
+#define CMD_ERASE_TABLES 0x5F /* erase partition table and RAID signatutures */
+
+#define CMD_SCSI_GET 0x60 /* get SCSI pass through devices */
+#define CMD_SCSI_TIMEOUT 0x61 /* set SCSI pass through timeout */
+#define CMD_SCSI_ERROR 0x62 /* get SCSI pass through request sense length and residual data count */
+#define CMD_GET_SPARMS 0x63 /* get SCSI bus and user parms */
+#define CMD_SCSI_ABORT 0x64 /* abort by setting time-out to zero */
+
+#define CMD_CHIRP_CHIRP 0x77 /* make a chirp chirp sound */
+#define CMD_GET_LAST_DONE 0x78 /* get tag of last done in progress */
+#define CMD_GET_FEATURES 0x79 /* get feature code and ESN */
+#define CMD_CLEAR_CACHE 0x7A /* Clear cache on specified device */
+#define CMD_BIOS_TEST 0x7B /* Test whether or not to load BIOS */
+#define CMD_WAIT_FLUSH 0x7C /* wait for cache flushed and invalidate read cache */
+#define CMD_RESET_BUS 0x7D /* reset the SCSI bus */
+#define CMD_STARTUP_QRY 0x7E /* startup in progress query */
+#define CMD_RESET 0x7F /* reset the controller */
+
+#define CMD_RESTART_RESET 0x80 /* reload and restart the controller at any reset issued */
+#define CMD_SOFT_RESET 0x81 /* do a soft reset NOW! */
+
+/************************************************/
+/* */
+/* Host return errors */
+/* */
+/************************************************/
+#define ERR08_TAGGED 0x80 /* doorbell error ored with tag */
+
+#define ERR16_NONE 0x0000 /* no errors */
+#define ERR16_SC_COND_MET 0x0004 /* SCSI status - Condition Met */
+#define ERR16_CMD 0x0101 /* command error */
+#define ERR16_SC_CHECK_COND 0x0002 /* SCSI status - Check Condition */
+#define ERR16_CMD_NOT 0x0201 /* command not supported */
+#define ERR16_NO_DEVICE 0x0301 /* invalid device selection */
+#define ERR16_SECTOR 0x0202 /* bad sector */
+#define ERR16_PROTECT 0x0303 /* write protected */
+#define ERR16_NOSECTOR 0x0404 /* sector not found */
+#define ERR16_MEDIA 0x0C0C /* invalid media */
+#define ERR16_CONTROL 0x2020 /* controller error */
+#define ERR16_CONTROL_DMA 0x2120 /* controller DMA engine error */
+#define ERR16_NO_ALARM 0x2220 /* alarm is not active */
+#define ERR16_OP_BUSY 0x2320 /* operation busy */
+#define ERR16_SEEK 0x4040 /* seek failure */
+#define ERR16_DEVICE_FAIL 0x4140 /* device has failed */
+#define ERR16_TIMEOUT 0x8080 /* timeout error */
+#define ERR16_DEV_NOT_READY 0xAAAA /* drive not ready */
+#define ERR16_UNDEFINED 0xBBBB /* undefined error */
+#define ERR16_WRITE_FAULT 0xCCCC /* write fault */
+#define ERR16_INVALID_DEV 0x4001 /* invalid device access */
+#define ERR16_DEVICE_BUSY 0x4002 /* device is busy */
+#define ERR16_MEMORY 0x4003 /* device pass thru requires too much memory */
+#define ERR16_NO_FEATURE 0x40FA /* feature no implemented */
+#define ERR16_NOTAG 0x40FD /* no tag space available */
+#define ERR16_NOT_READY 0x40FE /* controller not ready error */
+#define ERR16_SETUP_FLASH 0x5050 /* error when writing setup to flash memory */
+#define ERR16_SETUP_SIZE 0x5051 /* setup block size error */
+#define ERR16_SENSE 0xFFFF /* sense opereration failed */
+#define ERR16_SC_BUSY 0x0008 /* SCSI status - Busy */
+#define ERR16_SC_RES_CONFL 0x0018 /* SCSI status - Reservation Conflict */
+#define ERR16_SC_CMD_TERM 0x0022 /* SCSI status - Command Terminated */
+#define ERR16_SC_OTHER 0x00FF /* SCSI status - not recognized (any value masked) */
+#define ERR16_MEDIA_CHANGED 0x8001 /* devices media has been changed */
+
+#define ERR32_NONE 0x00000000 /* no errors */
+#define ERR32_SC_COND_MET 0x00000004 /* SCSI status - Condition Met */
+#define ERR32_CMD 0x00010101 /* command error */
+#define ERR32_SC_CHECK_COND 0x00020002 /* SCSI status - Check Condition */
+#define ERR32_CMD_NOT 0x00030201 /* command not supported */
+#define ERR32_NO_DEVICE 0x00040301 /* invalid device selection */
+#define ERR32_SECTOR 0x00050202 /* bad sector */
+#define ERR32_PROTECT 0x00060303 /* write protected */
+#define ERR32_NOSECTOR 0x00070404 /* sector not found */
+#define ERR32_MEDIA 0x00080C0C /* invalid media */
+#define ERR32_CONTROL 0x00092020 /* controller error */
+#define ERR32_CONTROL_DMA 0x000A2120 /* Controller DMA error */
+#define ERR32_NO_ALARM 0x000B2220 /* alarm is not active */
+#define ERR32_OP_BUSY 0x000C2320 /* operation busy */
+#define ERR32_SEEK 0x000D4040 /* seek failure */
+#define ERR32_DEVICE_FAIL 0x000E4140 /* device has failed */
+#define ERR32_TIMEOUT 0x000F8080 /* timeout error */
+#define ERR32_DEV_NOT_READY 0x0010AAAA /* drive not ready */
+#define ERR32_UNDEFINED 0x0011BBBB /* undefined error */
+#define ERR32_WRITE_FAULT 0x0012CCCC /* write fault */
+#define ERR32_INVALID_DEV 0x00134001 /* invalid device access */
+#define ERR32_DEVICE_BUSY 0x00144002 /* device is busy */
+#define ERR32_MEMORY 0x00154003 /* device pass thru requires too much memory */
+#define ERR32_NO_FEATURE 0x001640FA /* feature no implemented */
+#define ERR32_NOTAG 0x001740FD /* no tag space available */
+#define ERR32_NOT_READY 0x001840FE /* controller not ready error */
+#define ERR32_SETUP_FLASH 0x00195050 /* error when writing setup to flash memory */
+#define ERR32_SETUP_SIZE 0x001A5051 /* setup block size error */
+#define ERR32_SENSE 0x001BFFFF /* sense opereration failed */
+#define ERR32_SC_BUSY 0x001C0008 /* SCSI status - Busy */
+#define ERR32_SC_RES_CONFL 0x001D0018 /* SCSI status - Reservation Conflict */
+#define ERR32_SC_CMD_TERM 0x001E0022 /* SCSI status - Command Terminated */
+#define ERR32_SC_OTHER 0x001F00FF /* SCSI status - not recognized (any value masked) */
+#define ERR32_MEDIA_CHANGED 0x00208001 /* devices media has been changed */
+
+/************************************************/
+/* */
+/* Host Operating System specification codes */
+/* */
+/************************************************/
+#define SPEC_INTERRUPT 0x80 /* specification requires host interrupt */
+#define SPEC_BACKWARD_SG 0x40 /* specification requires scatter/gather items reversed */
+#define SPEC_DOS_BLOCK 0x01 /* DOS DASD blocking on pass through */
+#define SPEC_OS2_V3 0x02 /* OS/2 Warp */
+#define SPCE_SCO_3242 0x04 /* SCO 3.4.2.2 */
+#define SPEC_QNX_4X 0x05 /* QNX 4.XX */
+#define SPEC_NOVELL_NWPA 0x08 /* Novell NWPA scatter/gather support */
+
+/************************************************/
+/* */
+/* Inquire structures */
+/* */
+/************************************************/
+typedef struct _CNT_SCSI_INQ
+ {
+ UCHAR devt; /* 00: device type */
+ UCHAR devtm; /* 01: device type modifier */
+ UCHAR svers; /* 02: SCSI version */
+ UCHAR rfmt; /* 03: response data format */
+ UCHAR adlen; /* 04: additional length of data */
+ UCHAR res1; /* 05: */
+ UCHAR res2; /* 06: */
+ UCHAR fncs; /* 07: functional capabilities */
+ UCHAR vid[8]; /* 08: vendor ID */
+ UCHAR pid[16]; /* 10: product ID */
+ UCHAR rev[4]; /* 20: product revision */
+ } CNT_SCSI_INQ;
+
+typedef struct _CNT_IDE_INQ
+ {
+ USHORT GeneralConfiguration; /* 00 */
+ USHORT NumberOfCylinders; /* 02 */
+ USHORT Reserved1; /* 04 */
+ USHORT NumberOfHeads; /* 06 */
+ USHORT UnformattedBytesPerTrack; /* 08 */
+ USHORT UnformattedBytesPerSector; /* 0A */
+ USHORT SectorsPerTrack; /* 0C */
+ USHORT VendorUnique1[3]; /* 0E */
+ USHORT SerialNumber[10]; /* 14 */
+ USHORT BufferType; /* 28 */
+ USHORT BufferSectorSize; /* 2A */
+ USHORT NumberOfEccBytes; /* 2C */
+ USHORT FirmwareRevision[4]; /* 2E */
+ USHORT ModelNumber[20]; /* 36 */
+ UCHAR MaximumBlockTransfer; /* 5E */
+ UCHAR VendorUnique2; /* 5F */
+ USHORT DoubleWordIo; /* 60 */
+ USHORT Capabilities; /* 62 */
+ USHORT Reserved2; /* 64 */
+ UCHAR VendorUnique3; /* 66 */
+ UCHAR PioCycleTimingMode; /* 67 */
+ UCHAR VendorUnique4; /* 68 */
+ UCHAR DmaCycleTimingMode; /* 69 */
+ USHORT TranslationFieldsValid; /* 6A */
+ USHORT NumberOfCurrentCylinders; /* 6C */
+ USHORT NumberOfCurrentHeads; /* 6E */
+ USHORT CurrentSectorsPerTrack; /* 70 */
+ ULONG CurrentSectorCapacity; /* 72 */
+ } CNT_IDE_INQ;
+
+typedef struct _DASD_INQUIRE
+ {
+ ULONG type; /* 0 = SCSI, 1 = IDE */
+ union
+ {
+ CNT_SCSI_INQ scsi; /* SCSI inquire data */
+ CNT_IDE_INQ ide; /* IDE inquire data */
+ } inq;
+ } DASD_INQUIRE;
+
+/************************************************/
+/* */
+/* Device Codes */
+/* */
+/************************************************/
+#define DEVC_DASD 0x00 /* Direct-access Storage Device */
+#define DEVC_SEQACESS 0x01 /* Sequential-access device */
+#define DEVC_PRINTER 0x02 /* Printer device */
+#define DEVC_PROCESSOR 0x03 /* Processor device */
+#define DEVC_WRITEONCE 0x04 /* Write-once device */
+#define DEVC_CDROM 0x05 /* CD-ROM device */
+#define DEVC_SCANNER 0x06 /* Scanner device */
+#define DEVC_OPTICAL 0x07 /* Optical memory device */
+#define DEVC_MEDCHGR 0x08 /* Medium changer device */
+#define DEVC_DASD_REMOVABLE 0x80 /* Direct-access storage device, Removable */
+#define DEVC_NONE 0xFF /* no device */
+
+// SCSI controls for RAID
+#define SC_MY_RAID 0xBF // our special CDB command byte for Win95... interface
+#define MY_SCSI_QUERY0 0x31 // byte 1 subcommand to query driver for RAID 0 informatation
+#define MY_SCSI_QUERY1 0x32 // byte 1 subcommand to query driver for RAID 1 informatation
+#define MY_SCSI_QUERY5 0x33 // byte 1 subcommand to query driver for RAID 5 informatation
+#define MY_SCSI_REBUILD 0x40 // byte 1 subcommand to reconstruct a mirrored pair
+#define MY_SCSI_DEMOFAIL 0x54 // byte 1 subcommand for RAID failure demonstration
+#define MY_SCSI_ALARMMUTE 0x60 // byte 1 subcommand to mute any alarm currently on
+
+
+#endif
+
diff -u --recursive --new-file v2.0.36/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c
--- v2.0.36/linux/drivers/scsi/scsi.c Sun Nov 15 21:51:47 1998
+++ linux/drivers/scsi/scsi.c Sun Jun 13 10:21:02 1999
@@ -288,12 +288,14 @@
X {"PIONEER","CD-ROM DRM-600","*", BLIST_FORCELUN | BLIST_SINGLELUN},
X {"PIONEER","CD-ROM DRM-602X","*", BLIST_FORCELUN | BLIST_SINGLELUN},
X {"PIONEER","CD-ROM DRM-604X","*", BLIST_FORCELUN | BLIST_SINGLELUN},
+{"PIONEER","CD-ROM DRM-1804X","*", BLIST_FORCELUN | BLIST_SINGLELUN},
X {"EMULEX","MD21/S2 ESDI","*", BLIST_SINGLELUN},
X {"CANON","IPUBJD","*", BLIST_SPARSELUN},
X {"MATSHITA","PD","*", BLIST_FORCELUN | BLIST_SINGLELUN},
X {"YAMAHA","CDR100","1.00", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */
X {"YAMAHA","CDR102","1.00", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */
X {"nCipher","Fastness Crypto","*", BLIST_FORCELUN},
+{"iomega","jaz 1GB","J.86", BLIST_NOTQ | BLIST_NOLUN},
X /*
X * Must be at end of list...
X */
diff -u --recursive --new-file v2.0.36/linux/drivers/scsi/scsi_syms.c linux/drivers/scsi/scsi_syms.c
--- v2.0.36/linux/drivers/scsi/scsi_syms.c Mon Jul 13 13:46:36 1998
+++ linux/drivers/scsi/scsi_syms.c Sun Jun 13 10:21:02 1999
@@ -26,13 +26,11 @@
X #include "constants.h"
X
X #include "sd.h"
+#include <scsi/scsicam.h>
X /*
X * This source file contains the symbol table used by scsi loadable
X * modules.
X */
-extern int scsicam_bios_param (Disk * disk,
- int dev, int *ip );
-
X
X extern void print_command (unsigned char *command);
X extern void print_sense(const char * devclass, Scsi_Cmnd * SCpnt);
@@ -47,6 +45,7 @@
X X(scsi_register),
X X(scsi_unregister),
X X(scsicam_bios_param),
+ X(scsi_partsize),
X X(allocate_device),
X X(scsi_do_cmd),
X X(scsi_command_size),
diff -u --recursive --new-file v2.0.36/linux/drivers/scsi/scsicam.c linux/drivers/scsi/scsicam.c
--- v2.0.36/linux/drivers/scsi/scsicam.c Sun Nov 15 21:51:47 1998
+++ linux/drivers/scsi/scsicam.c Sun Jun 13 10:21:02 1999
@@ -26,9 +26,8 @@


X #include "scsi.h"
X #include "hosts.h"

X #include "sd.h"
+#include <scsi/scsicam.h>
X
-static int partsize(struct buffer_head *bh, unsigned long capacity,
- unsigned int *cyls, unsigned int *hds, unsigned int *secs);
X static int setsize(unsigned long capacity,unsigned int *cyls,unsigned int *hds,
X unsigned int *secs);
X
@@ -56,7 +55,7 @@
X return -1;
X
X /* try to infer mapping from partition table */
- ret_code = partsize (bh, (unsigned long) size, (unsigned int *) ip + 2,
+ ret_code = scsi_partsize (bh, (unsigned long) size, (unsigned int *) ip + 2,
X (unsigned int *) ip + 0, (unsigned int *) ip + 1);
X brelse (bh);
X
@@ -85,7 +84,7 @@
X }
X
X /*
- * Function : static int partsize(struct buffer_head *bh, unsigned long
+ * Function : static int scsi_partsize(struct buffer_head *bh, unsigned long
X * capacity,unsigned int *cyls, unsigned int *hds, unsigned int *secs);
X *
X * Purpose : to determine the BIOS mapping used to create the partition
@@ -95,7 +94,7 @@
X *
X */
X
-static int partsize(struct buffer_head *bh, unsigned long capacity,
+int scsi_partsize(struct buffer_head *bh, unsigned long capacity,
X unsigned int *cyls, unsigned int *hds, unsigned int *secs) {
X struct partition *p, *largest = NULL;
X int i, largest_cyl;
diff -u --recursive --new-file v2.0.36/linux/drivers/scsi/scsiiom.c linux/drivers/scsi/scsiiom.c
--- v2.0.36/linux/drivers/scsi/scsiiom.c Thu Aug 14 10:31:20 1997
+++ linux/drivers/scsi/scsiiom.c Sun Jun 13 10:21:03 1999
@@ -4,203 +4,264 @@
X * Description: Device Driver for Tekram DC-390 (T) PCI SCSI *
X * Bus Master Host Adapter *
X ***********************************************************************/
+/* $Id: scsiiom.c,v 2.15 1998/12/25 17:33:27 garloff Exp $ */
X
-
-static USHORT
-DC390_StartSCSI( PACB pACB, PDCB pDCB, PSRB pSRB )
+UCHAR
+dc390_StartSCSI( PACB pACB, PDCB pDCB, PSRB pSRB )
X {
- USHORT ioport, rc;
- UCHAR bval, bval1, i, cnt;
- PUCHAR ptr;
- ULONG wlval;
+ USHORT wlval;
+ UCHAR bval, bval1;
X
X pSRB->TagNumber = 31;
- ioport = pACB->IOPortBase;
- bval = pDCB->UnitSCSIID;
- outb(bval,ioport+Scsi_Dest_ID);
- bval = pDCB->SyncPeriod;
- outb(bval,ioport+Sync_Period);
- bval = pDCB->SyncOffset;
- outb(bval,ioport+Sync_Offset);
- bval = pDCB->CtrlR1;
- outb(bval,ioport+CtrlReg1);
- bval = pDCB->CtrlR3;
- outb(bval,ioport+CtrlReg3);
- bval = pDCB->CtrlR4;
- outb(bval,ioport+CtrlReg4);
- bval = CLEAR_FIFO_CMD; /* Flush FIFO */
- outb(bval,ioport+ScsiCmd);
-
+ DC390_write8 (Scsi_Dest_ID, pDCB->UnitSCSIID);
+ DC390_write8 (Sync_Period, pDCB->SyncPeriod);
+ DC390_write8 (Sync_Offset, pDCB->SyncOffset);
+ DC390_write8 (CtrlReg1, pDCB->CtrlR1);
+ DC390_write8 (CtrlReg3, pDCB->CtrlR3);
+ DC390_write8 (CtrlReg4, pDCB->CtrlR4);
+ DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); /* Flush FIFO */
+ DEBUG1(printk (KERN_INFO "DC390: Start SCSI command: %02x (Sync:%02x)\n",\
+ pSRB->CmdBlock[0], pDCB->SyncMode);)
X pSRB->ScsiPhase = SCSI_NOP0;
+ //pSRB->MsgOutBuf[0] = MSG_NOP;
+ //pSRB->MsgCnt = 0;
X bval = pDCB->IdentifyMsg;
- if( !(pDCB->SyncMode & EN_ATN_STOP) )
+ if( !(pDCB->SyncMode & EN_ATN_STOP) ) /* Don't always try send Extended messages on arbitration */
X {
X if( (pSRB->CmdBlock[0] == INQUIRY) ||
X (pSRB->CmdBlock[0] == REQUEST_SENSE) ||
X (pSRB->SRBFlag & AUTO_REQSENSE) )
X {
- bval &= 0xBF; /* NO disconnection */
- outb(bval,ioport+ScsiFifo);
- bval1 = SELECT_W_ATN;
+ bval &= 0xBF; /* No DisConn */
+ DC390_write8 (ScsiFifo, bval);
+ bval1 = SEL_W_ATN;
X pSRB->SRBState = SRB_START_;
+ DEBUG1(printk (KERN_DEBUG "DC390: No DisCn, No TagQ (%02x, %02x)\n", bval, bval1);)
X if( pDCB->SyncMode & SYNC_ENABLE )
- {
- if( !(pDCB->IdentifyMsg & 7) ||
+ {
+ if( !(pDCB->IdentifyMsg & 7) || /* LUN == 0 || Cmd != INQUIRY */
X (pSRB->CmdBlock[0] != INQUIRY) )
X {
- bval1 = SEL_W_ATN_STOP;
+ bval1 = SEL_W_ATN_STOP; /* Try to establish SYNC nego */
X pSRB->SRBState = SRB_MSGOUT;
X }
X }
X }
- else
+ else /* TagQ ? */
X {
- if(pDCB->SyncMode & EN_TAG_QUEUING)
+ DC390_write8 (ScsiFifo, bval);
+ if(pDCB->SyncMode & EN_TAG_QUEUEING)
X {
- outb(bval,ioport+ScsiFifo);
- bval = MSG_SIMPLE_QTAG;
- outb(bval,ioport+ScsiFifo);
- wlval = 1;
- bval = 0;
- while( wlval & pDCB->TagMask )
- {
- wlval = wlval << 1;
- bval++;
- }
- outb(bval,ioport+ScsiFifo);
+ DC390_write8 (ScsiFifo, MSG_SIMPLE_QTAG);
+ DEBUG1(printk (KERN_DEBUG "DC390: %sDisCn, TagQ (%02x, %02x, %08lx)\n", (bval&0x40?"":"No "), bval, SEL_W_ATN3, pDCB->TagMask);)
+ bval = 0; wlval = 1;
+ while (wlval & pDCB->TagMask)
+ { bval++; wlval <<= 1; };
X pDCB->TagMask |= wlval;
+ DC390_write8 (ScsiFifo, bval);
X pSRB->TagNumber = bval;
- bval1 = SEL_W_ATN2;
+ DEBUG1(printk (KERN_DEBUG "DC390: SRB %p (Cmd %li), Tag %02x queued\n", pSRB, pSRB->pcmd->pid, bval);)
+ bval1 = SEL_W_ATN3;
X pSRB->SRBState = SRB_START_;
X }
- else
+ else /* No TagQ */
X {
- outb(bval,ioport+ScsiFifo);
- bval1 = SELECT_W_ATN;
+ bval1 = SEL_W_ATN;
+ DEBUG1(printk (KERN_DEBUG "DC390: %sDisCn, No TagQ (%02x, %02x, %08lx)\n", (bval&0x40?"":"No "), bval, bval1, pDCB->TagMask);)
X pSRB->SRBState = SRB_START_;
X }
X }
X
- if( pSRB->SRBFlag & AUTO_REQSENSE )
- {
- bval = REQUEST_SENSE;
- outb(bval,ioport+ScsiFifo);
- bval = pDCB->IdentifyMsg << 5;
- outb(bval,ioport+ScsiFifo);
- bval = 0;
- outb(bval,ioport+ScsiFifo);
- outb(bval,ioport+ScsiFifo);
- bval = sizeof(pSRB->pcmd->sense_buffer);
- outb(bval,ioport+ScsiFifo);
- bval = 0;
- outb(bval,ioport+ScsiFifo);
- }
- else
- {
- cnt = pSRB->ScsiCmdLen;
- ptr = (PUCHAR) pSRB->CmdBlock;
- for(i=0; i<cnt; i++)
- {
- bval = *ptr++;
- outb(bval,ioport+ScsiFifo);
- }
- }
X }
- else /* ATN_STOP */
+ else /* ATN_STOP: Always try to establish Sync nego */
X {
X if( (pSRB->CmdBlock[0] == INQUIRY) ||
X (pSRB->CmdBlock[0] == REQUEST_SENSE) ||
X (pSRB->SRBFlag & AUTO_REQSENSE) )
X {
- bval &= 0xBF;
- outb(bval,ioport+ScsiFifo);
- bval1 = SELECT_W_ATN;
+ bval &= 0xBF; /* No DisConn */
+ DC390_write8 (ScsiFifo, bval);
+ bval1 = SEL_W_ATN;
+ DEBUG1(printk (KERN_DEBUG "DC390: No DisCn, No TagQ (%02x, %02x)\n", bval, bval1);)
X pSRB->SRBState = SRB_START_;
+ /* ??? */
X if( pDCB->SyncMode & SYNC_ENABLE )
X {
- if( !(pDCB->IdentifyMsg & 7) ||
+ if( !(pDCB->IdentifyMsg & 7) || /* LUN == 0 || Cmd != INQUIRY */
X (pSRB->CmdBlock[0] != INQUIRY) )
X {
- bval1 = SEL_W_ATN_STOP;
+ bval1 = SEL_W_ATN_STOP; /* Try to establish Sync nego */
X pSRB->SRBState = SRB_MSGOUT;
X }
X }
X }
- else
+ else /* TagQ ? */
X {
- if(pDCB->SyncMode & EN_TAG_QUEUING)
+ DC390_write8 (ScsiFifo, bval);
+ if(pDCB->SyncMode & EN_TAG_QUEUEING)
X {
- outb(bval,ioport+ScsiFifo);
X pSRB->MsgOutBuf[0] = MSG_SIMPLE_QTAG;
- wlval = 1;
- bval = 0;
- while( wlval & pDCB->TagMask )
- {
- wlval = wlval << 1;
- bval++;
- }
+ DEBUG1(printk (KERN_DEBUG "DC390: %sDisCn, TagQ (%02x, %02x, %08lx)\n", (bval&0x40?"":"No "), bval, SEL_W_ATN_STOP, pDCB->TagMask);)
+ bval = 0; wlval = 1;
+ while (wlval & pDCB->TagMask)
+ { bval++; wlval <<= 1; };
X pDCB->TagMask |= wlval;
X pSRB->TagNumber = bval;
+ DEBUG1(printk (KERN_DEBUG "DC390: SRB %p (Cmd %li), Tag %02x queued\n", pSRB, pSRB->pcmd->pid, bval);)
X pSRB->MsgOutBuf[1] = bval;
X pSRB->MsgCnt = 2;
X bval1 = SEL_W_ATN_STOP;
- pSRB->SRBState = SRB_START_;
+ pSRB->SRBState = SRB_START_; /* ?? */
X }
- else
+ else /* No TagQ */
X {
- outb(bval,ioport+ScsiFifo);
X pSRB->MsgOutBuf[0] = MSG_NOP;
X pSRB->MsgCnt = 1;
X pSRB->SRBState = SRB_START_;
X bval1 = SEL_W_ATN_STOP;
- }
+ DEBUG1(printk (KERN_DEBUG "DC390: %sDisCn, No TagQ (%02x, %02x, %08lx)\n", (bval&0x40?"":"No "), bval, bval1, pDCB->TagMask);)
+ };
X }
X }
- bval = inb( ioport+Scsi_Status );
- if( bval & INTERRUPT )
+ if (bval1 != SEL_W_ATN_STOP)
+ { /* Command is written in CommandPhase, if SEL_W_ATN_STOP ... */
+ if( pSRB->SRBFlag & AUTO_REQSENSE )
+ {
+ bval = 0;
+ DC390_write8 (ScsiFifo, REQUEST_SENSE);
+ DC390_write8 (ScsiFifo, pDCB->IdentifyMsg << 5);
+ DC390_write8 (ScsiFifo, bval);
+ DC390_write8 (ScsiFifo, bval);
+ DC390_write8 (ScsiFifo, sizeof(pSRB->pcmd->sense_buffer));
+ DC390_write8 (ScsiFifo, bval);
+ DEBUG1(printk (KERN_DEBUG "DC390: AutoReqSense !\n");)
+ }
+ else /* write cmnd to bus */
+ {
+ PUCHAR ptr; UCHAR i;
+ ptr = (PUCHAR) pSRB->CmdBlock;
+ for (i=0; i<pSRB->ScsiCmdLen; i++)
+ DC390_write8 (ScsiFifo, *(ptr++));
+ };
+ }
+
+ /* Check if we can't win arbitration */


SHAR_EOF
true || echo 'restore of patch-2.0.37 failed'
fi

echo 'End of part 36'
echo 'File patch-2.0.37 is continued in part 37'
echo 37 > _shar_seq_.tmp

Thomas...@ciw.uni-karlsruhe.de

unread,
Jun 16, 1999, 3:00:00 AM6/16/99
to
Archive-name: v2.0/patch-2.0.37/part40

#!/bin/sh
# this is part 40 of a 45 - part archive


# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.0.37 continued
if test ! -r _shar_seq_.tmp; then
echo 'Please unpack part 1 first!'
exit 1
fi
(read Scheck

if test "$Scheck" != 40; then


echo Please unpack part "$Scheck" next!
exit 1
else
exit 0
fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.0.37'
else
echo 'x - continuing with patch-2.0.37'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.0.37' &&

- {
- io_port =DC390_inDword(MechNum,PCI_BASE_ADDRESS_0) & 0xFFFE;
- irq = DC390_inByte( MechNum, PCI_INTERRUPT_LINE);
-#ifdef DC390_DEBUG0
- printk("DC390: IO_PORT=%4x,IRQ=%x,\n",(UINT) io_port, irq);
-#endif
- if( !DC390_init(psht, io_port, irq, pci_index, MechNum) )
- {
- adaptCnt++;
- pci_index++;
- istatus = inb( (USHORT)io_port+INT_Status ); /* Reset Pending INT */
-#ifdef DC390_DEBUG0
- printk("DC390: Mech=%2x,\n",(UCHAR) MechNum);
-#endif
- }
- }
- }
- if( BusDevFunNum != 0xfff8 )
- BusDevFunNum += 8; /* next device # */
- else
- break;
- }
- }
+ DC390_LOCK_IO; /* Remove this when going to new eh */
+ PCI_GET_IO_AND_IRQ;
+ DEBUG0(printk(KERN_INFO "DC390(%i): IO_PORT=%04x,IRQ=%x\n", dc390_adapterCnt, (UINT) io_port, irq);)
X
-#ifdef FOR_PCI_OK
- if ( pcibios_present() )
- {
- for (i = 0; i < MAX_ADAPTER_NUM; ++i)
- {
- if( !pcibios_find_device( PCI_VENDOR_ID_AMD,
- PCI_DEVICE_ID_AMD53C974,
- pci_index, &pci_bus, &pci_device_fn) )
+ if( !DC390_init(psht, io_port, irq, PDEV, dc390_adapterCnt))
X {
- chipType = PCI_DEVICE_ID_AMD53C974;
- pci_index++;
- }
-
- if( chipType )
- {
-
- error = pcibios_read_config_dword(pci_bus, pci_device_fn,
- PCI_BASE_ADDRESS_0, &io_port);
- error |= pcibios_read_config_byte(pci_bus, pci_device_fn,
- PCI_INTERRUPT_LINE, &irq);
- if( error )
- {
- printk("DC390_detect: reading configuration registers error!\n");
- InitialTime = 0;
- return( 0 );
- }
-
- (USHORT) io_port = (USHORT) io_port & 0xFFFE;
-#ifdef DC390_DEBUG0
- printk("DC390: IO_PORT=%4x,IRQ=%x,\n",(UINT) io_port, irq);
-#endif
- if( !DC390_init(psht, io_port, irq, i) )
- adaptCnt++;
- chipType = 0;
- }
- else
- break;
+ PCI_SET_MASTER;
+ dc390_set_pci_cfg (PDEV);
+ dc390_adapterCnt++;
+ };
+ DC390_UNLOCK_IO; /* Remove when going to new eh */
X }
- }
-#endif
-
- InitialTime = 0;
- adapterCnt = adaptCnt;
- return( adaptCnt );
+ else
+ printk (KERN_ERR "DC390: No PCI BIOS found!\n");
+
+ if (dc390_adapterCnt)
+ psht->proc_dir = &DC390_proc_scsi_tmscsim;
+
+ printk(KERN_INFO "DC390: %i adapters found\n", dc390_adapterCnt);
+ DC390_UNLOCK_DRV;
+ return( dc390_adapterCnt );
X }
X
X
-#ifndef VERSION_ELF_1_2_13
+/***********************************************************************
+ * Functions: dc390_inquiry(), dc390_inquiry_done()
+ *
+ * Purpose: When changing speed etc., we have to issue an INQUIRY
+ * command to make sure, we agree upon the nego parameters
+ * with the device
+ ***********************************************************************/
+
+static void dc390_inquiry_done (Scsi_Cmnd* cmd)
+{
+ printk (KERN_INFO "DC390: INQUIRY (ID %02x LUN %02x) returned %08x\n",
+ cmd->target, cmd->lun, cmd->result);
+ if (cmd->result)
+ {
+ PACB pACB = (PACB)cmd->host->hostdata;
+ PDCB pDCB = dc390_findDCB (pACB, cmd);
+ printk ("DC390: Unsetting DsCn, Sync and TagQ!\n");
+ if (pDCB)
+ {
+ pDCB->DevMode &= ~(SYNC_NEGO_ | TAG_QUEUEING_ | EN_DISCONNECT_ );
+ dc390_updateDCB (pACB, pDCB);
+ };
+ };
+ kfree (cmd->buffer);
+ kfree (cmd);
+};
+
+void dc390_inquiry (PACB pACB, PDCB pDCB)
+{
+ char* buffer;
+ Scsi_Cmnd* cmd;
+ buffer = kmalloc (256, GFP_ATOMIC);
+ cmd = kmalloc (sizeof (Scsi_Cmnd), GFP_ATOMIC);
+
+ memset (buffer, 0, 256);
+ memset (cmd, 0, sizeof(Scsi_Cmnd));
+ cmd->cmnd[0] = INQUIRY;
+ cmd->cmnd[1] = (pDCB->UnitSCSILUN << 5) & 0xe0;
+ cmd->cmnd[4] = 0xff;
+
+ cmd->cmd_len = 6; cmd->old_cmd_len = 6;
+ cmd->host = pACB->pScsiHost;
+ cmd->target = pDCB->UnitSCSIID;
+ cmd->lun = pDCB->UnitSCSILUN;
+ cmd->serial_number = 1;
+ cmd->bufflen = 128;
+ cmd->buffer = buffer;
+ cmd->request_bufflen = 128;
+ cmd->request_buffer = &buffer[128];
+ cmd->done = dc390_inquiry_done;
+ cmd->scsi_done = dc390_inquiry_done;
+ cmd->timeout_per_command = HZ;
+
+ cmd->request.rq_status = RQ_SCSI_BUSY;
+
+ printk (KERN_INFO "DC390: Queue INQUIRY command to dev ID %02x LUN %02x\n",
+ pDCB->UnitSCSIID, pDCB->UnitSCSILUN);
+ DC390_queue_command (cmd, dc390_inquiry_done);
+};
X
X /********************************************************************
- * Function: tmscsim_set_info()
+ * Function: dc390_set_info()
X *
- * Purpose: Set adapter info (!)
- *
- * Not yet implemented
+ * Purpose: Change adapter config
X *
+ * Strings are parsed similar to the output of tmscsim_proc_info ()
+ * '-' means no change
X *******************************************************************/
X
-int tmscsim_set_info(char *buffer, int length, struct Scsi_Host *shpnt)
+static int dc390_scanf (char** p1, char** p2, int* var)
X {
- return(-ENOSYS); /* Currently this is a no-op */
-}
+ *p2 = *p1;
+ *var = simple_strtoul (*p2, p1, 10);
+ if (*p2 == *p1) return -1;
+ *p1 = strtok (0, " \t\n:=,;.");


+ return 0;
+};
+

+#define SCANF(p1, p2, var, min, max) \
+if (dc390_scanf (&p1, &p2, &var)) goto einv; \
+else if (var<min || var>max) goto einv2
+
+static int dc390_yesno (char** p, char* var, char bmask)
+{
+ switch (**p)
+ {
+ case 'Y': *var |= bmask; break;
+ case 'N': *var &= ~bmask; break;
+ case '-': break;
+ default: return -1;
+ }
+ *p = strtok (0, " \t\n:=,;");


+ return 0;
+};
+

+#define YESNO(p, var, bmask) \
+if (dc390_yesno (&p, &var, bmask)) goto einv; \
+else dc390_updateDCB (pACB, pDCB); \
+if (!p) goto ok
+
+static int dc390_search (char **p1, char **p2, char *var, char* txt, int max, int scale, char* ign)
+{
+ int dum;
+ if (! memcmp (*p1, txt, strlen(txt)))
+ {
+ *p2 = strtok (0, " \t\n:=,;");
+ if (!*p2) return -1;
+ dum = simple_strtoul (*p2, p1, 10);
+ if (*p2 == *p1) return -1;
+ if (dum >= 0 && dum <= max)
+ { *var = (dum * 100) / scale; }
+ else return -2;
+ *p1 = strtok (0, " \t\n:=,;");
+ if (*ign && *p1 && strlen(*p1) >= strlen(ign) &&
+ !(memcmp (*p1, ign, strlen(ign))))
+ *p1 = strtok (0, " \t\n:=,;");
+
+ }


+ return 0;
+};
+

+#define SEARCH(p1, p2, var, txt, max) \
+if (dc390_search (&p1, &p2, (PUCHAR)(&var), txt, max, 100, "")) goto einv2; \
+else if (!p1) goto ok2
+
+#define SEARCH2(p1, p2, var, txt, max, scale) \
+if (dc390_search (&p1, &p2, &var, txt, max, scale, "")) goto einv2; \
+else if (!p1) goto ok2
+
+#define SEARCH3(p1, p2, var, txt, max, scale, ign) \
+if (dc390_search (&p1, &p2, &var, txt, max, scale, ign)) goto einv2; \
+else if (!p1) goto ok2
+
+
+#ifdef DC390_PARSEDEBUG
+static char _prstr[256];
+char* prstr (char* p, char* e)
+{
+ char* c = _prstr;
+ while (p < e)
+ if (*p == 0) { *c++ = ':'; p++; }
+ else if (*p == 10) { *c++ = '\\'; *c++ = 'n'; p++; }
+ else *c++ = *p++;
+ *c = 0;
+ return _prstr;
+};
+#endif
+
+int dc390_set_info (char *buffer, int length, PACB pACB)
+{
+ char *pos = buffer, *p0 = buffer;
+ char needs_inquiry = 0;
+ int dum = 0;
+ char dev;
+ PDCB pDCB = pACB->pLinkDCB;
+ DC390_IFLAGS
+ DC390_AFLAGS
+ pos[length] = 0;
+
+ DC390_LOCK_IO;
+ DC390_LOCK_ACB;
+ /* UPPERCASE */
+ /* Don't use kernel toupper, because of 2.0.x bug: ctmp unexported */
+ while (*pos)
+ { if (*pos >='a' && *pos <= 'z') *pos = *pos + 'A' - 'a'; pos++; };
+
+ /* We should protect __strtok ! */
+ /* spin_lock (strtok_lock); */
+
+ /* Remove WS */
+ pos = strtok (buffer, " \t:\n=,;");
+ if (!pos) goto ok;
+
+ next:
+ if (!memcmp (pos, "RESET", 5)) goto reset;
+ else if (!memcmp (pos, "INQUIRY", 7)) goto inquiry;
+ else if (!memcmp (pos, "REMOVE", 6)) goto remove;
+
+ if (isdigit (*pos))
+ {
+ /* Device config line */
+ int dev, id, lun; char* pdec;
+ char olddevmode;
+
+ SCANF (pos, p0, dev, 0, pACB->DCBCnt-1);
+ if (pos) { SCANF (pos, p0, id, 0, 7); } else goto einv;
+ if (pos) { SCANF (pos, p0, lun, 0, 7); } else goto einv;
+ if (!pos) goto einv;
+
+ PARSEDEBUG(printk (KERN_INFO "DC390: config line %i %i %i:\"%s\"\n", dev, id, lun, prstr (pos, &buffer[length]));)
+ pDCB = pACB->pLinkDCB;
+ for (dum = 0; dum < dev; dum++) pDCB = pDCB->pNextDCB;
+ /* Sanity Check */
+ if (pDCB->UnitSCSIID != id || pDCB->UnitSCSILUN != lun)
+ {
+ printk (KERN_ERR "DC390: no such device: Idx=%02i ID=%02i LUN=%02i\n",
+ dev, id, lun);
+ goto einv2;
+ };
+
+ olddevmode = pDCB->DevMode;
+ YESNO (pos, pDCB->DevMode, PARITY_CHK_);
+ needs_inquiry++;
+ YESNO (pos, pDCB->DevMode, SYNC_NEGO_);
+ if ((olddevmode & SYNC_NEGO_) == (pDCB->DevMode & SYNC_NEGO_)) needs_inquiry--;
+ needs_inquiry++;
+ YESNO (pos, pDCB->DevMode, EN_DISCONNECT_);
+ if ((olddevmode & EN_DISCONNECT_) == (pDCB->DevMode & EN_DISCONNECT_)) needs_inquiry--;
+ YESNO (pos, pDCB->DevMode, SEND_START_);
+ needs_inquiry++;
+ YESNO (pos, pDCB->DevMode, TAG_QUEUEING_);
+ if ((olddevmode & TAG_QUEUEING_) == (pDCB->DevMode & TAG_QUEUEING_)) needs_inquiry--;
+ YESNO (pos, pDCB->SyncMode, EN_ATN_STOP);
+
+ dc390_updateDCB (pACB, pDCB);
+ if (!pos) goto ok;
+
+ olddevmode = pDCB->NegoPeriod;
+ /* Look for decimal point (Speed) */
+ pdec = pos;
+ while (pdec++ < &buffer[length]) if (*pdec == '.') break;
+ /* NegoPeriod */
+ if (*pos != '-')
+ {
+ SCANF (pos, p0, dum, 72, 800);
+ pDCB->NegoPeriod = dum >> 2;
+ if (pDCB->NegoPeriod != olddevmode) needs_inquiry++;
+ if (!pos) goto ok;
+ if (memcmp (pos, "NS", 2) == 0) pos = strtok (0, " \t\n:=,;.");
+ }
+ else pos = strtok (0, " \t\n:=,;.");
+ if (!pos) goto ok;
+
+ /* Speed: NegoPeriod */
+ if (*pos != '-')
+ {
+ SCANF (pos, p0, dum, 1, 13);
+ pDCB->NegoPeriod = (1000/dum) >> 2;
+ if (pDCB->NegoPeriod != olddevmode && !pos) needs_inquiry++;
+ if (!pos) goto ok;
+ /* decimal */
+ if (pos-1 == pdec)
+ {
+ int dumold = dum;
+ dum = simple_strtoul (pos, &p0, 10) * 10;
+ for (; p0-pos > 1; p0--) dum /= 10;
+ pDCB->NegoPeriod = (100000/(100*dumold + dum)) >> 2;
+ if (pDCB->NegoPeriod < 19) pDCB->NegoPeriod = 19;
+ if (pDCB->NegoPeriod != olddevmode) needs_inquiry++;
+ pos = strtok (0, " \t\n:=,;");
+ if (!pos) goto ok;
+ };
+ if (*pos == 'M') pos = strtok (0, " \t\n:=,;");
+ }
+ else pos = strtok (0, " \t\n:=,;");
+ /* dc390_updateDCB (pACB, pDCB); */
+ if (!pos) goto ok;
+
+ olddevmode = pDCB->SyncOffset;
+ /* SyncOffs */
+ if (*pos != '-')
+ {
+ SCANF (pos, p0, dum, 0, 0x0f);
+ pDCB->SyncOffset = dum;
+ if (pDCB->SyncOffset > olddevmode) needs_inquiry++;
+ }
+ else pos = strtok (0, " \t\n:=,;");
+ dc390_updateDCB (pACB, pDCB);
+ }
+ else
+ {
+ char* p1 = pos; UCHAR dum;
+ PARSEDEBUG(printk (KERN_INFO "DC390: chg adapt cfg \"%s\"\n", prstr (pos, &buffer[length]));)
+ dum = GLITCH_TO_NS (pACB->glitch_cfg);
+ /* Adapter setting */
+ SEARCH (pos, p0, pACB->pScsiHost->max_id, "MAXID", 8);
+ SEARCH (pos, p0, pACB->pScsiHost->max_lun, "MAXLUN", 8);
+ SEARCH (pos, p0, pACB->pScsiHost->this_id, "ADAPTERID", 7);
+ SEARCH (pos, p0, pACB->TagMaxNum, "TAGMAXNUM", 32);
+ SEARCH (pos, p0, pACB->ACBFlag, "ACBFLAG", 255);
+ SEARCH3 (pos, p0, dum, "GLITCHEATER", 40, 1000, "NS");
+ SEARCH3 (pos, p0, pACB->sel_timeout, "SELTIMEOUT", 400, 163, "MS");
+ ok2:
+ pACB->glitch_cfg = NS_TO_GLITCH (dum);
+ if (pACB->sel_timeout < 60) pACB->sel_timeout = 60;
+ dum = 0; while (1 << dum <= pACB->TagMaxNum) dum ++;
+ pACB->TagMaxNum &= (1 << --dum);
+ if (pos == p1) goto einv;
+ dc390_updateDCBs (pACB);
+ }
+ if (pos) goto next;
+
+ ok:
+ /* spin_unlock (strtok_lock); */
+ DC390_UNLOCK_ACB;
+ if (needs_inquiry)
+ { dc390_updateDCB (pACB, pDCB); dc390_inquiry (pACB, pDCB); };
+ DC390_UNLOCK_IO;
+ return (length);
+
+ einv2:
+ pos = p0;
+ einv:
+ /* spin_unlock (strtok_lock); */
+ DC390_UNLOCK_ACB;
+ DC390_UNLOCK_IO;
+ printk (KERN_WARNING "DC390: parse error near \"%s\"\n", (pos? pos: "NULL"));
+ return (-EINVAL);
+
+ reset:
+ {
+ Scsi_Cmnd cmd; cmd.host = pACB->pScsiHost;
+ printk (KERN_WARNING "DC390: Driver reset requested!\n");
+ DC390_UNLOCK_ACB;
+ DC390_reset (&cmd, 0);
+ DC390_UNLOCK_IO;
+ };
+ return (length);
+
+ inquiry:
+ {
+ pos = strtok (0, " \t\n.:;="); if (!pos) goto einv;
+ dev = simple_strtoul (pos, &p0, 10);
+ if (dev >= pACB->DCBCnt) goto einv_dev;
+ for (dum = 0; dum < dev; dum++) pDCB = pDCB->pNextDCB;
+ printk (KERN_NOTICE " DC390: Issue INQUIRY command to Dev(Idx) %i SCSI ID %i LUN %i\n",
+ dev, pDCB->UnitSCSIID, pDCB->UnitSCSILUN);
+ DC390_UNLOCK_ACB;
+ dc390_inquiry (pACB, pDCB);
+ DC390_UNLOCK_IO;
+ };
+ return (length);
+
+ remove:
+ {
+ pos = strtok (0, " \t\n.:;="); if (!pos) goto einv;
+ dev = simple_strtoul (pos, &p0, 10);
+ if (dev >= pACB->DCBCnt) goto einv_dev;
+ for (dum = 0; dum < dev; dum++) pDCB = pDCB->pNextDCB;
+ printk (KERN_NOTICE " DC390: Remove DCB for Dev(Idx) %i SCSI ID %i LUN %i\n",
+ dev, pDCB->UnitSCSIID, pDCB->UnitSCSILUN);
+ dc390_remove_dev (pACB, pDCB);
+ DC390_UNLOCK_ACB;
+ DC390_UNLOCK_IO;
+ };
+ return (length);
+
+ einv_dev:
+ printk (KERN_WARNING "DC390: Ignore cmnd to illegal Dev(Idx) %i. Valid range: 0 - %i.\n",
+ dev, pACB->DCBCnt - 1);
+ DC390_UNLOCK_ACB;
+ DC390_UNLOCK_IO;
+ return (-EINVAL);
+
+
+}
+
+#undef SEARCH
+#undef YESNO
+#undef SCANF
X
X /********************************************************************
- * Function: tmscsim_proc_info(char* buffer, char **start,
+ * Function: DC390_proc_info(char* buffer, char **start,
X * off_t offset, int length, int hostno, int inout)
X *
X * Purpose: return SCSI Adapter/Device Info
@@ -1763,84 +2412,89 @@
X *
X ********************************************************************/
X
-/* KG: proc_info taken from driver aha152x.c */
-
X #undef SPRINTF
X #define SPRINTF(args...) pos += sprintf(pos, ## args)
X
-#define YESNO(YN)\
-if (YN) SPRINTF(" Yes ");\
-else SPRINTF(" No ")
+#define YESNO(YN) \
+ if (YN) SPRINTF(" Yes "); \
+ else SPRINTF(" No ")
+
X
-int tmscsim_proc_info(char *buffer, char **start,
- off_t offset, int length, int hostno, int inout)
+int DC390_proc_info (char *buffer, char **start,
+ off_t offset, int length, int hostno, int inout)
X {
X int dev, spd, spd1;
X char *pos = buffer;
X PSH shpnt;
- PACB acbpnt;
- PDCB dcbpnt;
- unsigned long flags;
-/* Scsi_Cmnd *ptr; */
+ PACB pACB;
+ PDCB pDCB;
+ DC390_AFLAGS
X
- acbpnt = pACB_start;
+ pACB = dc390_pACB_start;
X
- while(acbpnt != (PACB)-1)
+ while(pACB != (PACB)-1)
X {
- shpnt = acbpnt->pScsiHost;
+ shpnt = pACB->pScsiHost;
X if (shpnt->host_no == hostno) break;
- acbpnt = acbpnt->pNextACB;
+ pACB = pACB->pNextACB;
X }
X
- if (acbpnt == (PACB)-1) return(-ESRCH);
+ if (pACB == (PACB)-1) return(-ESRCH);
X if(!shpnt) return(-ESRCH);
X
X if(inout) /* Has data been written to the file ? */
- return(tmscsim_set_info(buffer, length, shpnt));
+ return dc390_set_info(buffer, length, pACB);
+
+ SPRINTF("Tekram DC390/AM53C974 PCI SCSI Host Adapter, ");
+ SPRINTF("Driver Version %s\n", DC390_VERSION);
X
- SPRINTF("Tekram DC390(T) PCI SCSI Host Adadpter, ");
- SPRINTF("Driver Version 1.10, 1996/12/05\n");
-
- save_flags(flags);
- cli();
+ DC390_LOCK_ACB;
X
X SPRINTF("SCSI Host Nr %i, ", shpnt->host_no);
- SPRINTF("DC390 Adapter Nr %i\n", acbpnt->AdapterIndex);
- SPRINTF("IOPortBase 0x%04x, ", acbpnt->IOPortBase);
- SPRINTF("IRQLevel 0x%02x\n", acbpnt->IRQLevel);
-
- SPRINTF("MaxID %i, MaxLUN %i, ",acbpnt->max_id, acbpnt->max_lun);
- SPRINTF("AdapterID %i, AdapterLUN %i\n", acbpnt->AdaptSCSIID, acbpnt->AdaptSCSILUN);
-
- SPRINTF("TagMaxNum %i, Status %i\n", acbpnt->TagMaxNum, acbpnt->status);
-
- SPRINTF("Nr of attached devices: %i\n", acbpnt->DeviceCnt);
+ SPRINTF("%s Adapter Nr %i\n", dc390_adapname, pACB->AdapterIndex);
+ SPRINTF("IOPortBase 0x%04x, ", pACB->IOPortBase);
+ SPRINTF("IRQLevel 0x%02x\n", pACB->IRQLevel);
+
+ SPRINTF("MaxID %i, MaxLUN %i, ", shpnt->max_id, shpnt->max_lun);
+ SPRINTF("AdapterID %i, SelTimeout %i ms\n",
+ shpnt->this_id, (pACB->sel_timeout*164)/100);
+
+ SPRINTF("TagMaxNum %i, Status %i, ACBFlag %i, GlitchEater %i ns\n",
+ pACB->TagMaxNum, pACB->status, pACB->ACBFlag, GLITCH_TO_NS(pACB->glitch_cfg)*12);
+
+ SPRINTF("Statistics: Cmnds %li, Cmnds not sent directly %li, Out of SRB conds %li\n",
+ pACB->Cmds, pACB->CmdInQ, pACB->CmdOutOfSRB);
+ SPRINTF(" Lost arbitrations %li\n", pACB->SelLost);
+
+ SPRINTF("Nr of attached devices: %i, Nr of DCBs: %i\n", pACB->DeviceCnt, pACB->DCBCnt);
X
- SPRINTF("Un ID LUN Prty Sync DsCn SndS TagQ NegoPeriod SyncSpeed SyncOffs\n");
+ SPRINTF("Idx ID LUN Prty Sync DsCn SndS TagQ STOP NegoPeriod SyncSpeed SyncOffs\n");
X
- dcbpnt = acbpnt->pLinkDCB;
- for (dev = 0; dev < acbpnt->DeviceCnt; dev++)
+ pDCB = pACB->pLinkDCB;
+ for (dev = 0; dev < pACB->DCBCnt; dev++)
X {
- SPRINTF("%02i %02i %02i ", dev, dcbpnt->UnitSCSIID, dcbpnt->UnitSCSILUN);
- YESNO(dcbpnt->DevMode & PARITY_CHK_);
- YESNO(dcbpnt->SyncMode & SYNC_NEGO_DONE);
- YESNO(dcbpnt->DevMode & EN_DISCONNECT_);
- YESNO(dcbpnt->DevMode & SEND_START_);
- YESNO(dcbpnt->SyncMode & EN_TAG_QUEUING);
- SPRINTF(" %03i ns ", (dcbpnt->NegoPeriod) << 2);
- if (dcbpnt->SyncOffset & 0x0f)
+ SPRINTF("%02i %02i %02i ", dev, pDCB->UnitSCSIID, pDCB->UnitSCSILUN);
+ YESNO(pDCB->DevMode & PARITY_CHK_);
+ YESNO(pDCB->SyncMode & SYNC_NEGO_DONE);
+ YESNO(pDCB->DevMode & EN_DISCONNECT_);
+ //YESNO(pDCB->SyncMode & EN_ATN_STOP);
+ YESNO(pDCB->DevMode & SEND_START_);
+ YESNO(pDCB->SyncMode & EN_TAG_QUEUEING);
+ YESNO(pDCB->SyncMode & EN_ATN_STOP);
+ if (pDCB->SyncOffset & 0x0f)
X {
- spd = 1000/(dcbpnt->NegoPeriod <<2);
- spd1 = 1000%(dcbpnt->NegoPeriod <<2);
- spd1 = (spd1 * 10)/(dcbpnt->NegoPeriod <<2);
- SPRINTF(" %2i.%1i M %02i\n", spd, spd1, (dcbpnt->SyncOffset & 0x0f));
+ int sp = pDCB->SyncPeriod; if (! (pDCB->CtrlR3 & FAST_SCSI)) sp++;
+ SPRINTF(" %03i ns ", (pDCB->NegoPeriod) << 2);
+ spd = 40/(sp); spd1 = 40%(sp);
+ spd1 = (spd1 * 10 + sp/2) / (sp);
+ SPRINTF(" %2i.%1i M %02i\n", spd, spd1, (pDCB->SyncOffset & 0x0f));
X }
- else SPRINTF("\n");
+ else SPRINTF(" (%03i ns)\n", (pDCB->NegoPeriod) << 2);
X /* Add more info ...*/
- dcbpnt = dcbpnt->pNextDCB;
+ pDCB = pDCB->pNextDCB;
X }
X
- restore_flags(flags);
+ DC390_UNLOCK_ACB;
X *start = buffer + offset;
X
X if (pos - buffer < offset)
@@ -1850,81 +2504,93 @@
X else
X return length;
X }
-#endif /* VERSION_ELF_1_2_13 */
X
+#undef YESNO
+#undef SPRINTF


X
X #ifdef MODULE
X

X /***********************************************************************
- * Function : static int DC390_shutdown (struct Scsi_Host *host)
+ * Function : static int dc390_shutdown (struct Scsi_Host *host)
X *
X * Purpose : does a clean (we hope) shutdown of the SCSI chip.
X * Use prior to dumping core, unloading the driver, etc.
X *
X * Returns : 0 on success
X ***********************************************************************/
-static int
-DC390_shutdown (struct Scsi_Host *host)
+static int dc390_shutdown (struct Scsi_Host *host)
X {
X UCHAR bval;
- USHORT ioport;
- unsigned long flags;
X PACB pACB = (PACB)(host->hostdata);
-
- ioport = (unsigned int) pACB->IOPortBase;
-
- save_flags (flags);
- cli();
-
+
X /* pACB->soft_reset(host); */
X
-#ifdef DC390_DEBUG0
- printk("DC390: shutdown,");
-#endif
+ printk(KERN_INFO "DC390: shutdown\n");
X
- bval = inb(ioport+CtrlReg1);
+ pACB->ACBFlag = RESET_DONE;
+ bval = DC390_read8 (CtrlReg1);
X bval |= DIS_INT_ON_SCSI_RST;
- outb(bval,ioport+CtrlReg1); /* disable interrupt */
- DC390_ResetSCSIBus( pACB );
+ DC390_write8 (CtrlReg1, bval); /* disable interrupt */
+ if (pACB->Gmode2 & RST_SCSI_BUS)
+ dc390_ResetSCSIBus (pACB);
X
- restore_flags (flags);
X return( 0 );
X }
X
+void dc390_freeDCBs (struct Scsi_Host *host)
+{
+ PDCB pDCB, nDCB;
+ PACB pACB = (PACB)(host->hostdata);
+
+ pDCB = pACB->pLinkDCB;
+ if (!pDCB) return;
+ do
+ {
+ nDCB = pDCB->pNextDCB;
+ DCBDEBUG(printk (KERN_INFO "DC390: Free DCB (ID %i, LUN %i): 0x%08x\n",\
+ pDCB->UnitSCSIID, pDCB->UnitSCSILUN, (int)pDCB);)
+ kfree (pDCB);
+ pDCB = nDCB;
+ } while (pDCB && pDCB != pACB->pLinkDCB);
+
+};
X
X int DC390_release(struct Scsi_Host *host)
X {
- int irq_count;
- struct Scsi_Host *tmp;
+ int irq_count;
+ PACB pACB;
+ DC390_AFLAGS DC390_IFLAGS
+#if USE_SPINLOCKS > 1
+ PACB pACB = (PACB)(host->hostdata);
+#endif
X
- DC390_shutdown (host);
+ DC390_LOCK_IO;
+ DC390_LOCK_ACB;
+
+ dc390_shutdown (host);
X
X if (host->irq != IRQ_NONE)
X {
- for (irq_count = 0, tmp = pSH_start; tmp; tmp = tmp->next)
+ for (irq_count = 0, pACB = dc390_pACB_start;
+ pACB; pACB = pACB->pNextACB)
X {
- if ( tmp->irq == host->irq )
+ if ( pACB->IRQLevel == host->irq )
X ++irq_count;
X }
X if (irq_count == 1)
X {
-#ifdef DC390_DEBUG0
- printk("DC390: Free IRQ %i.",host->irq);
-#endif
-#ifndef VERSION_ELF_1_2_13
+ DEBUG0(printk(KERN_INFO "DC390: Free IRQ %i\n",host->irq);)
X free_irq(host->irq,NULL);
-#else
- free_irq(host->irq);
-#endif
X }
X }
X
X release_region(host->io_port,host->n_io_port);
-
+ dc390_freeDCBs (host);
+ DC390_UNLOCK_ACB;
+ DC390_UNLOCK_IO;
X return( 1 );
X }
X
X Scsi_Host_Template driver_template = DC390_T;
X #include "scsi_module.c"
X #endif /* def MODULE */
-
diff -u --recursive --new-file v2.0.36/linux/drivers/scsi/tmscsim.h linux/drivers/scsi/tmscsim.h
--- v2.0.36/linux/drivers/scsi/tmscsim.h Thu Aug 14 10:31:20 1997
+++ linux/drivers/scsi/tmscsim.h Sun Jun 13 10:21:03 1999
@@ -3,12 +3,23 @@
X ;* TEKRAM DC-390(T) PCI SCSI Bus Master Host Adapter *
X ;* Device Driver *
X ;***********************************************************************/
+/* $Id: tmscsim.h,v 2.4 1998/12/25 17:33:27 garloff Exp $ */
X
-#ifndef TMSCSIM_H
-#define TMSCSIM_H
+#ifndef _TMSCSIM_H
+#define _TMSCSIM_H
X
X #define IRQ_NONE 255
X
+#define MAX_ADAPTER_NUM 4
+#define MAX_SG_LIST_BUF 16
+#define MAX_CMD_PER_LUN 8
+#define MAX_CMD_QUEUE 2*MAX_CMD_PER_LUN+1
+#define MAX_SCSI_ID 8
+#define MAX_SRB_CNT MAX_CMD_QUEUE+1 /* Max number of started commands */
+#define END_SCAN 2
+
+#define SEL_TIMEOUT 153 /* 250 ms selection timeout (@ 40 MHz) */
+
X typedef unsigned char UCHAR;
X typedef unsigned short USHORT;
X typedef unsigned long ULONG;
@@ -54,17 +65,6 @@
X } SGentry1, *PSGE;
X
X
-#define MAX_ADAPTER_NUM 4
-#define MAX_DEVICES 10
-#define MAX_SG_LIST_BUF 16
-#define MAX_CMD_QUEUE 20
-#define MAX_CMD_PER_LUN 8
-#define MAX_SCSI_ID 8
-#define MAX_SRB_CNT MAX_CMD_QUEUE+4
-#define END_SCAN 2
-
-#define SEL_TIMEOUT 153 /* 250 ms selection timeout (@ 40 MHz) */
-
X /*
X ;-----------------------------------------------------------------------
X ; SCSI Request Block
@@ -79,40 +79,44 @@
X PSCSICMD pcmd;
X PSGL pSegmentList;
X
-ULONG PhysSRB;
+ULONG Segment0[2];
+ULONG Segment1[2];
+
+/* 0x2c:*/
X ULONG TotalXferredLen;
-ULONG SGPhysAddr; /*;a segment starting address */
+ULONG SGBusAddr; /*;a segment starting address as seen by AM53C974A*/
X ULONG SGToBeXferLen; /*; to be xfer length */
+ULONG SRBState;
X
-SGL Segmentx; /* make a one entry of S/G list table */
-
-PUCHAR pMsgPtr;
-USHORT SRBState;
-USHORT Revxx2; /* ??? */
-
+/* 0x3c: */
X UCHAR MsgInBuf[6];
X UCHAR MsgOutBuf[6];
X
+/* 0x48: */
+SGL Segmentx; /* make a one entry of S/G list table */
+
+UCHAR ScsiCmdLen;
+UCHAR ScsiPhase;
+
X UCHAR AdaptStatus;
X UCHAR TargetStatus;
+
+/* 0x58: */
X UCHAR MsgCnt;
X UCHAR EndMessage;
+UCHAR RetryCnt;
+UCHAR SRBFlag; /*; b0-AutoReqSense,b6-Read,b7-write */
+ /*; b4-settimeout,b5-Residual valid */
X UCHAR TagNumber;
X UCHAR SGcount;
X UCHAR SGIndex;
-UCHAR IORBFlag; /*;81h-Reset, 2-retry */
-
X UCHAR SRBStatus;
-UCHAR RetryCnt;
-UCHAR SRBFlag; /*; b0-AutoReqSense,b6-Read,b7-write */
- /*; b4-settimeout,b5-Residual valid */
-UCHAR ScsiCmdLen;
-UCHAR ScsiPhase;
-UCHAR Reserved3[3]; /*;for dword alignment */
-ULONG Segment0[2];
-ULONG Segment1[2];
+ //UCHAR IORBFlag; /*;81h-Reset, 2-retry */
+
+/* 0x60: */
X };
X
+
X typedef struct _SRB DC390_SRB, *PSRB;
X
X /*
@@ -129,42 +133,44 @@
X PSCSICMD pQIORBtail;
X PSCSICMD AboIORBhead;
X PSCSICMD AboIORBtail;
-USHORT QIORBCnt;
-USHORT AboIORBcnt;
+ULONG QIORBCnt;
+ULONG AboIORBcnt;
X
+/* 0x20: */
X PSRB pWaitingSRB;
X PSRB pWaitLast;
X PSRB pGoingSRB;
X PSRB pGoingLast;
X PSRB pActiveSRB;
-USHORT GoingSRBCnt;
-USHORT WaitSRBCnt; /* ??? */
+UCHAR GoingSRBCnt;
+UCHAR WaitSRBCnt; /* ??? */
+UCHAR DevType;
+UCHAR MaxCommand;
X
+/* 0x38: */
X ULONG TagMask;
X
-USHORT MaxCommand;
-USHORT AdaptIndex; /*; UnitInfo struc start */
-USHORT UnitIndex; /*; nth Unit on this card */
X UCHAR UnitSCSIID; /*; SCSI Target ID (SCSI Only) */
X UCHAR UnitSCSILUN; /*; SCSI Log. Unit (SCSI Only) */
-
+UCHAR DevMode;
X UCHAR IdentifyMsg;
+
X UCHAR CtrlR1;
X UCHAR CtrlR3;
X UCHAR CtrlR4;
X
-UCHAR InqDataBuf[8];
-UCHAR CapacityBuf[8];
-UCHAR DevMode;
-UCHAR AdpMode;
+UCHAR DCBFlag;
+
+/* 0x44: */
X UCHAR SyncMode; /*; 0:async mode */
X UCHAR NegoPeriod; /*;for nego. */
X UCHAR SyncPeriod; /*;for reg. */
X UCHAR SyncOffset; /*;for reg. and nego.(low nibble) */
-UCHAR UnitCtrlFlag;
-UCHAR DCBFlag;
-UCHAR DevType;
-UCHAR Reserved2[3]; /*;for dword alignment */
+
+/* 0x48:*/
+//UCHAR InqDataBuf[8];
+//UCHAR CapacityBuf[8];
+/* 0x58: */
X };
X
X typedef struct _DCB DC390_DCB, *PDCB;
@@ -175,40 +181,57 @@
X */
X struct _ACB
X {
-ULONG PhysACB;
X PSH pScsiHost;
X struct _ACB *pNextACB;
X USHORT IOPortBase;
-USHORT Revxx1; /* ??? */
+UCHAR IRQLevel;
+UCHAR status;
+
+UCHAR SRBCount;
+UCHAR AdapterIndex; /*; nth Adapter this driver */
+UCHAR DeviceCnt;
+UCHAR DCBCnt;
+
+/* 0x10: */
+UCHAR TagMaxNum;
+UCHAR ACBFlag;
+UCHAR Gmode2;
+UCHAR scan_devices;
X
X PDCB pLinkDCB;
+PDCB pLastDCB;
X PDCB pDCBRunRobin;
X PDCB pActiveDCB;
-PDCB pDCB_free;
X PSRB pFreeSRB;
X PSRB pTmpSRB;
-USHORT SRBCount;
-USHORT AdapterIndex; /*; nth Adapter this driver */
-USHORT max_id;
-USHORT max_lun;
+
+/* 0x2c: */
X
X UCHAR msgin123[4];
-UCHAR status;
-UCHAR AdaptSCSIID; /*; Adapter SCSI Target ID */
-UCHAR AdaptSCSILUN; /*; Adapter SCSI LUN */
-UCHAR DeviceCnt;
-UCHAR IRQLevel;
-UCHAR TagMaxNum;
-UCHAR ACBFlag;
-UCHAR Gmode2;
-UCHAR LUNchk;
-UCHAR scan_devices;
-UCHAR HostID_Bit;
-UCHAR Reserved1[1]; /*;for dword alignment */
X UCHAR DCBmap[MAX_SCSI_ID];
-DC390_DCB DCB_array[MAX_DEVICES]; /* +74h, Len=3E8 */
-DC390_SRB SRB_array[MAX_SRB_CNT]; /* +45Ch, Len= */
+
+#if defined(USE_SPINLOCKS) && USE_SPINLOCKS > 1 && (defined(__SMP__) || DEBUG_SPINLOCKS > 0)
+spinlock_t lock;
+#endif
+UCHAR sel_timeout;
+UCHAR glitch_cfg;
+
+UCHAR MsgLen;
+UCHAR Ignore_IRQ; /* Not used */
+
+PDEVDECL1; /* Pointer to PCI cfg. space */
+/* 0x40/0x3c: */
+ULONG Cmds;
+ULONG CmdInQ;
+ULONG CmdOutOfSRB;
+ULONG SelLost;
+
+
+/* 0x50/0x4c: */
X DC390_SRB TmpSRB;
+/* 0xb4/0xb0: */
+DC390_SRB SRB_array[MAX_SRB_CNT]; /* 18 SRBs */
+/* 0x7bc/0x7b8: */
X };
X
X typedef struct _ACB DC390_ACB, *PACB;
@@ -278,14 +301,6 @@
X #define DO_SYNC_NEGO BIT13
X #define SRB_UNEXPECT_RESEL BIT14
X
-/*;---ACBFlag */
-#define RESET_DEV BIT0
-#define RESET_DETECT BIT1
-#define RESET_DONE BIT2
-
-/*;---DCBFlag */
-#define ABORT_DEV_ BIT0
-
X /*;---SRBstatus */
X #define SRB_OK BIT0
X #define ABORTION BIT1
@@ -294,6 +309,14 @@
X #define PARITY_ERROR BIT4
X #define SRB_ERROR BIT5
X
+/*;---ACBFlag */
+#define RESET_DEV BIT0
+#define RESET_DETECT BIT1
+#define RESET_DONE BIT2
+
+/*;---DCBFlag */
+#define ABORT_DEV_ BIT0
+
X /*;---SRBFlag */
X #define DATAOUT BIT7
X #define DATAIN BIT6
@@ -316,7 +339,7 @@
X #define H_BAD_CCB_OR_SG 0x1A
X #define H_ABORT 0x0FF
X
-/*; SCSI Status byte codes*/
+/*; SCSI Status byte codes*/ /* Twice the values defined in scsi/scsi.h */
X #define SCSI_STAT_GOOD 0x0 /*; Good status */
X #define SCSI_STAT_CHECKCOND 0x02 /*; SCSI Check Condition */
X #define SCSI_STAT_CONDMET 0x04 /*; Condition Met */
@@ -335,9 +358,9 @@
X #define SYNC_DISABLE 0
X #define SYNC_ENABLE BIT0
X #define SYNC_NEGO_DONE BIT1
-#define WIDE_ENABLE BIT2
-#define WIDE_NEGO_DONE BIT3
-#define EN_TAG_QUEUING BIT4
+#define WIDE_ENABLE BIT2 /* Not used ;-) */
+#define WIDE_NEGO_DONE BIT3 /* Not used ;-) */
+#define EN_TAG_QUEUEING BIT4
X #define EN_ATN_STOP BIT5
X
X #define SYNC_NEGO_OFFSET 15
@@ -352,7 +375,7 @@
X #define SCSI_MSG_OUT 6
X #define SCSI_MSG_IN 7
X
-/*;----SCSI MSG BYTE*/
+/*;----SCSI MSG BYTE*/ /* see scsi/scsi.h */
X #define MSG_COMPLETE 0x00
X #define MSG_EXTENDED 0x01
X #define MSG_SAVE_PTR 0x02
@@ -373,13 +396,6 @@
X #define MSG_IDENTIFY 0x80
X #define MSG_HOST_ID 0x0C0
X
-/*;----SCSI STATUS BYTE*/
-#define STATUS_GOOD 0x00
-#define CHECK_CONDITION_ 0x02
-#define STATUS_BUSY 0x08
-#define STATUS_INTERMEDIATE 0x10
-#define RESERVE_CONFLICT 0x18
-
X /* cmd->result */
X #define STATUS_MASK_ 0xFF
X #define MSG_MASK 0xFF00
@@ -389,7 +405,7 @@
X ** Inquiry Data format
X */
X
-typedef struct _SCSIInqData { /* INQ */
+typedef struct _SCSIInqData { /* INQUIRY */
X
X UCHAR DevType; /* Periph Qualifier & Periph Dev Type*/
X UCHAR RMB_TypeMod; /* rem media bit & Dev Type Modifier */
@@ -412,6 +428,7 @@
X
X #define SCSI_DEVTYPE 0x1F /* Peripheral Device Type */
X #define SCSI_PERIPHQUAL 0xE0 /* Peripheral Qualifier */
+#define TYPE_NODEV SCSI_DEVTYPE /* Unknown or no device type */
X
X
X /* Inquiry byte 1 mask */
@@ -420,18 +437,10 @@
X
X
X /* Peripheral Device Type definitions */
+/* see include/scsi/scsi.h for the rest */
X
-#define SCSI_DASD 0x00 /* Direct-access Device */
-#define SCSI_SEQACESS 0x01 /* Sequential-access device */
-#define SCSI_PRINTER 0x02 /* Printer device */
-#define SCSI_PROCESSOR 0x03 /* Processor device */
-#define SCSI_WRITEONCE 0x04 /* Write-once device */
-#define SCSI_CDROM 0x05 /* CD-ROM device */
-#define SCSI_SCANNER 0x06 /* Scanner device */
-#define SCSI_OPTICAL 0x07 /* Optical memory device */
-#define SCSI_MEDCHGR 0x08 /* Medium changer device */
-#define SCSI_COMM 0x09 /* Communications device */
-#define SCSI_NODEV 0x1F /* Unknown or no device type */
+#define TYPE_PRINTER 0x02 /* Printer device */
+#define TYPE_COMM 0x09 /* Communications device */
X
X /*
X ** Inquiry flag definitions (Inq data byte 7)
@@ -459,17 +468,24 @@
X UCHAR xx2;
X } EEprom, *PEEprom;
X
-#define EE_ADAPT_SCSI_ID 64
-#define EE_MODE2 65
-#define EE_DELAY 66
-#define EE_TAG_CMD_NUM 67
+#define REAL_EE_ADAPT_SCSI_ID 64
+#define REAL_EE_MODE2 65
+#define REAL_EE_DELAY 66
+#define REAL_EE_TAG_CMD_NUM 67
+
+#define EE_ADAPT_SCSI_ID 32
+#define EE_MODE2 33
+#define EE_DELAY 34
+#define EE_TAG_CMD_NUM 35
+
+#define EE_LEN 40
X
X /*; EE_MODE1 bits definition*/
X #define PARITY_CHK_ BIT0
X #define SYNC_NEGO_ BIT1
X #define EN_DISCONNECT_ BIT2
X #define SEND_START_ BIT3
-#define TAG_QUEUING_ BIT4
+#define TAG_QUEUEING_ BIT4
X
X /*; EE_MODE2 bits definition*/
X #define MORE2_DRV BIT0
@@ -494,34 +510,42 @@
X ;====================
X */
X
-/*; Command Reg.(+0CH) */
+/*; Command Reg.(+0CH) (rw) */
X #define DMA_COMMAND BIT7
X #define NOP_CMD 0
X #define CLEAR_FIFO_CMD 1
X #define RST_DEVICE_CMD 2
X #define RST_SCSI_BUS_CMD 3
+
X #define INFO_XFER_CMD 0x10
X #define INITIATOR_CMD_CMPLTE 0x11
X #define MSG_ACCEPTED_CMD 0x12
X #define XFER_PAD_BYTE 0x18
X #define SET_ATN_CMD 0x1A
X #define RESET_ATN_CMD 0x1B
-#define SELECT_W_ATN 0x42
+
+#define SEL_WO_ATN 0x41 /* currently not used */
+#define SEL_W_ATN 0x42
X #define SEL_W_ATN_STOP 0x43
+#define SEL_W_ATN3 0x46
X #define EN_SEL_RESEL 0x44
-#define SEL_W_ATN2 0x46
+#define DIS_SEL_RESEL 0x45 /* currently not used */
+#define RESEL 0x40 /* " */
+#define RESEL_ATN3 0x47 /* " */
+
X #define DATA_XFER_CMD INFO_XFER_CMD
X
X
-/*; SCSI Status Reg.(+10H) */
+/*; SCSI Status Reg.(+10H) (r) */
X #define INTERRUPT BIT7
X #define ILLEGAL_OP_ERR BIT6
X #define PARITY_ERR BIT5
X #define COUNT_2_ZERO BIT4
X #define GROUP_CODE_VALID BIT3
-#define SCSI_PHASE_MASK (BIT2+BIT1+BIT0)
+#define SCSI_PHASE_MASK (BIT2+BIT1+BIT0)
+/* BIT2: MSG phase; BIT1: C/D physe; BIT0: I/O phase */
X
-/*; Interrupt Status Reg.(+14H) */
+/*; Interrupt Status Reg.(+14H) (r) */
X #define SCSI_RESET BIT7
X #define INVALID_CMD BIT6
X #define DISCONNECTED BIT5
@@ -531,11 +555,12 @@
X #define SEL_ATTENTION BIT1
X #define SELECTED BIT0
X
-/*; Internal State Reg.(+18H) */
+/*; Internal State Reg.(+18H) (r) */
X #define SYNC_OFFSET_FLAG BIT3
X #define INTRN_STATE_MASK (BIT2+BIT1+BIT0)
+/* 0x04: Sel. successful (w/o stop), 0x01: Sel. successful (w/ stop) */
X
-/*; Clock Factor Reg.(+24H) */
+/*; Clock Factor Reg.(+24H) (w) */
X #define CLK_FREQ_40MHZ 0
X #define CLK_FREQ_35MHZ (BIT2+BIT1+BIT0)
X #define CLK_FREQ_30MHZ (BIT2+BIT1)
@@ -544,47 +569,54 @@
X #define CLK_FREQ_15MHZ (BIT1+BIT0)
X #define CLK_FREQ_10MHZ BIT1
X
-/*; Control Reg. 1(+20H) */
+/*; Control Reg. 1(+20H) (rw) */
X #define EXTENDED_TIMING BIT7
X #define DIS_INT_ON_SCSI_RST BIT6
X #define PARITY_ERR_REPO BIT4
-#define SCSI_ID_ON_BUS (BIT2+BIT1+BIT0)
+#define SCSI_ID_ON_BUS (BIT2+BIT1+BIT0) /* host adapter ID */
X
-/*; Control Reg. 2(+2CH) */
+/*; Control Reg. 2(+2CH) (rw) */
X #define EN_FEATURE BIT6
X #define EN_SCSI2_CMD BIT3
X
-/*; Control Reg. 3(+30H) */
+/*; Control Reg. 3(+30H) (rw) */
X #define ID_MSG_CHECK BIT7
X #define EN_QTAG_MSG BIT6
X #define EN_GRP2_CMD BIT5
X #define FAST_SCSI BIT4 /* ;10MB/SEC */
X #define FAST_CLK BIT3 /* ;25 - 40 MHZ */
X
-/*; Control Reg. 4(+34H) */
+/*; Control Reg. 4(+34H) (rw) */
X #define EATER_12NS 0
X #define EATER_25NS BIT7
X #define EATER_35NS BIT6
X #define EATER_0NS (BIT7+BIT6)
+#define REDUCED_POWER BIT5
+#define CTRL4_RESERVED BIT4 /* must be 1 acc. to AM53C974.c */
X #define NEGATE_REQACKDATA BIT2
X #define NEGATE_REQACK BIT3
+
+#define GLITCH_TO_NS(x) (((~x>>6 & 2) >> 1) | ((x>>6 & 1) << 1 ^ (x>>6 & 2)))
+#define NS_TO_GLITCH(y) (((~y<<7) | ~((y<<6) ^ ((y<<5 & 1<<6) | ~0x40))) & 0xc0)
+
X /*
X ;====================
X ; DMA Register
X ;====================
X */
-/*; DMA Command Reg.(+40H) */
+/*; DMA Command Reg.(+40H) (rw) */
X #define READ_DIRECTION BIT7
X #define WRITE_DIRECTION 0
X #define EN_DMA_INT BIT6
-#define MAP_TO_MDL BIT5
-#define DIAGNOSTIC BIT4
+#define EN_PAGE_INT BIT5 /* page transfer interrupt enable */
+#define MAP_TO_MDL BIT4
+#define DIAGNOSTIC BIT2
X #define DMA_IDLE_CMD 0
X #define DMA_BLAST_CMD BIT0
X #define DMA_ABORT_CMD BIT1
X #define DMA_START_CMD (BIT1+BIT0)
X
-/*; DMA Status Reg.(+54H) */
+/*; DMA Status Reg.(+54H) (r) */
X #define PCI_MS_ABORT BIT6
X #define BLAST_COMPLETE BIT5
X #define SCSI_INTERRUPT BIT4
@@ -593,88 +625,77 @@
X #define DMA_XFER_ERROR BIT1
X #define POWER_DOWN BIT0
X
-/*
-; DMA SCSI Bus and Ctrl.(+70H)
-;EN_INT_ON_PCI_ABORT
-*/
+/*; DMA SCSI Bus and Ctrl.(+70H) */
+#define EN_INT_ON_PCI_ABORT BIT25
+#define WRT_ERASE_DMA_STAT BIT24
+#define PW_DOWN_CTRL BIT21
+#define SCSI_BUSY BIT20
+#define SCLK BIT19
+#define SCAM BIT18
+#define SCSI_LINES 0x0003ffff
X
X /*
X ;==========================================================
X ; SCSI Chip register address offset
X ;==========================================================
+;Registers are rw unless declared otherwise
X */
-#define CtcReg_Low 0x00
-#define CtcReg_Mid 0x04
+#define CtcReg_Low 0x00 /* r curr. transfer count */
+#define CtcReg_Mid 0x04 /* r */
+#define CtcReg_High 0x38 /* r */
X #define ScsiFifo 0x08
X #define ScsiCmd 0x0C
-#define Scsi_Status 0x10
-#define INT_Status 0x14
-#define Sync_Period 0x18
-#define Sync_Offset 0x1C
-#define CtrlReg1 0x20
-#define Clk_Factor 0x24
+#define Scsi_Status 0x10 /* r */
+#define INT_Status 0x14 /* r */
+#define Sync_Period 0x18 /* w */
+#define Sync_Offset 0x1C /* w */
+#define Clk_Factor 0x24 /* w */
+#define CtrlReg1 0x20
X #define CtrlReg2 0x2C
X #define CtrlReg3 0x30
X #define CtrlReg4 0x34
-#define CtcReg_High 0x38
X #define DMA_Cmd 0x40
-#define DMA_XferCnt 0x44
-#define DMA_XferAddr 0x48
-#define DMA_Wk_ByteCntr 0x4C
-#define DMA_Wk_AddrCntr 0x50
-#define DMA_Status 0x54
-#define DMA_MDL_Addr 0x58
-#define DMA_Wk_MDL_Cntr 0x5C
-#define DMA_ScsiBusCtrl 0x70
-
-#define StcReg_Low CtcReg_Low
-#define StcReg_Mid CtcReg_Mid
-#define Scsi_Dest_ID Scsi_Status
-#define Scsi_TimeOut INT_Status
-#define Intern_State Sync_Period
-#define Current_Fifo Sync_Offset
-#define StcReg_High CtcReg_High
-
-#define am_target Scsi_Status
-#define am_timeout INT_Status
-#define am_seq_step Sync_Period
-#define am_fifo_count Sync_Offset
-
-
-#define DC390_read8(address) \
- inb(DC390_ioport + (address)))
-
-#define DC390_read16(address) \
- inw(DC390_ioport + (address)))
-
-#define DC390_read32(address) \
- inl(DC390_ioport + (address)))
-
-#define DC390_write8(address,value) \
- outb((value), DC390_ioport + (address)))
-
-#define DC390_write16(address,value) \
- outw((value), DC390_ioport + (address)))
-
-#define DC390_write32(address,value) \
- outl((value), DC390_ioport + (address)))
-
-
-/* Configuration method #1 */
-#define PCI_CFG1_ADDRESS_REG 0xcf8
-#define PCI_CFG1_DATA_REG 0xcfc
-#define PCI_CFG1_ENABLE 0x80000000
-#define PCI_CFG1_TUPPLE(bus, device, function, register) \
- (PCI_CFG1_ENABLE | (((bus) << 16) & 0xff0000) | \
- (((device) << 11) & 0xf800) | (((function) << 8) & 0x700)| \
- (((register) << 2) & 0xfc))
-
-/* Configuration method #2 */
-#define PCI_CFG2_ENABLE_REG 0xcf8
-#define PCI_CFG2_FORWARD_REG 0xcfa
-#define PCI_CFG2_ENABLE 0x0f0
-#define PCI_CFG2_TUPPLE(function) \
- (PCI_CFG2_ENABLE | (((function) << 1) & 0xe))
+#define DMA_XferCnt 0x44 /* rw starting transfer count (32 bit) */
+#define DMA_XferAddr 0x48 /* rw starting physical address (32 bit) */
+#define DMA_Wk_ByteCntr 0x4C /* r working byte counter */
+#define DMA_Wk_AddrCntr 0x50 /* r working address counter */
+#define DMA_Status 0x54 /* r */
+#define DMA_MDL_Addr 0x58 /* rw starting MDL address */
+#define DMA_Wk_MDL_Cntr 0x5C /* r working MDL counter */
+#define DMA_ScsiBusCtrl 0x70 /* rw SCSI Bus, PCI/DMA Ctrl */
+
+#define StcReg_Low CtcReg_Low /* w start transfer count */
+#define StcReg_Mid CtcReg_Mid /* w */
+#define StcReg_High CtcReg_High /* w */
+#define Scsi_Dest_ID Scsi_Status /* w */
+#define Scsi_TimeOut INT_Status /* w */
+#define Intern_State Sync_Period /* r */
+#define Current_Fifo Sync_Offset /* r Curr. FIFO / int. state */
+
+
+#define DC390_read8(address) \
+ (inb (pACB->IOPortBase + (address)))
+
+#define DC390_read8_(address, base) \
+ (inb ((USHORT)(base) + (address)))
+
+#define DC390_read16(address) \
+ (inw (pACB->IOPortBase + (address)))
+
+#define DC390_read32(address) \
+ (inl (pACB->IOPortBase + (address)))
+
+#define DC390_write8(address,value) \
+ outb ((value), pACB->IOPortBase + (address))
+
+#define DC390_write8_(address,value,base) \
+ outb ((value), (USHORT)(base) + (address))
+
+#define DC390_write16(address,value) \
+ outw ((value), pACB->IOPortBase + (address))
+
+#define DC390_write32(address,value) \
+ outl ((value), pACB->IOPortBase + (address))
X
X
-#endif /* TMSCSIM_H */
+#endif /* _TMSCSIM_H */
diff -u --recursive --new-file v2.0.36/linux/drivers/scsi/tripace.c linux/drivers/scsi/tripace.c
--- v2.0.36/linux/drivers/scsi/tripace.c Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/tripace.c Sun Jun 13 10:21:03 1999
@@ -0,0 +1,1562 @@
+/* tc2550.c -- Tripace TC-2550x based PCI SCSI Adapter SCSI driver
+ * Created:D.Ravi jun 8 1998 at chennai lab of Tripace
+ * Copyright 1998 Tripace Europe BV
+ *
+ * Driver version 1.00.000 (904)
+


+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+

+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ **************************************************************************
+
+ DESCRIPTION:
+
+
+
+
+ REFERENCES USED:
+
+ 1.0 Design Kit for the Tripace TC-2550x based PCI SCSI Adapter
+
+ 2.0 Tripace IOLAYER document.
+
+ 3.0 LINUX driver sources in /usr/linux/drivers/scsi directory.
+
+
+ ALPHA TESTERS:
+
+ 1.0 so far no external testers,only developer testing has been done.
+
+ 2.0 Testing with IBMHDD,Quantum HDD,zip drive and sony CDROM has been
+ done.
+
+
+ NOTES ON USER DEFINABLE OPTIONS:
+
+ 1.0 The following are the command line options that are possible for the
+ TRIPACE TC-2550 PCI SCSI controller without BIOS.
+
+ tripace=fast clock,discon,sync,tag
+
+
+ The values for these four options can be either 0 or 1.
+ If fast clock is set to 1 ,then the chip uses a 60mhz clock.If ultra
+ scsi devices are used this should be set and the controller should have a
+ 60mhz crystal.
+
+ if disconnect is 1 ,then disconnect/reconnect is allowed for all scsi
+ devices connected to the controller.if it is 0 ,it is off.
+
+ sync = 1 means that synchronous negotiation will be done with scsi
+ devices.currently,though the flag is set ,the function is not implemented.
+
+ Tag = 1 means that tagged queue commands can be sent to the scsi devices.
+ This is not implemnted as yet in the driver.
+
+ The default values are 0,1,1,1
+
+ **************************************************************************/


+
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+

+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <linux/mm.h>
+#include <linux/head.h>
+#include <linux/sched.h>
+#include <linux/types.h>


+#include <asm/io.h>
+#include <linux/blk.h>
+#include "scsi.h"
+#include "hosts.h"

+#include "tripace.h"
+#include <asm/system.h>
+#include <asm/dma.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/proc_fs.h>
+#include <linux/bios32.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include "tripace_mcode.h"
+
+#define VERSION "$Revision: 1.00 $"
+
+/* #define DEBUG */
+
+
+#define MAXTARGET 8
+#define MAXSRBS 16
+
+#define RISC_ENTRY1 0
+
+#define DEV_PARAM_REG_BASE CFG_BASE+0x20
+
+#define SCSI_DMA_POINTER CFG_BASE+0x40
+#define SCSI_DMA_COUNTER CFG_BASE+0x44
+#define HOST_DMA_POINTER CFG_BASE+0x48
+#define HOST_DMA_COUNTER CFG_BASE+0x4c
+#define MBX_IN_BASE CFG_BASE+0x50
+#define MBX_OUT_BASE CFG_BASE+0x54
+#define DEV_HDR_BASE CFG_BASE+0x58
+#define TASK_Q_BASE CFG_BASE+0x5c
+#define CURRENT_DEV_PTR CFG_BASE+0x60
+#define CURRENT_TASK_PTR CFG_BASE+0x64
+#define SG_LIST_PTR CFG_BASE+0x68
+#define ACC CFG_BASE+0x6c
+#define SCRATCHB CFG_BASE+0x70
+#define CURRENT_INST CFG_BASE+0x74
+#define FLAG CFG_BASE+0x78
+#define SCRATCHC CFG_BASE+0x7a
+#define MBX_IN_INDEX CFG_BASE+0x7b
+#define PC CFG_BASE+0x7c
+#define MBX_OUT_INDEX CFG_BASE+0x7f
+#define PROGRAM_DATA_REG CFG_BASE+0x80
+#define CONTROL_REG CFG_BASE+0x84
+#define STATUS_INT_REG CFG_BASE+0x86
+#define SCSI_DATA CFG_BASE+0x88
+#define SCSI_CONTROL CFG_BASE+0x8A
+#define SCSI_ID_REG CFG_BASE+0x8b
+
+#define INFO_BASE 0x780
+#define SIG_BASE 0x7D4
+
+#define Q_FILE_SIZE 8192
+#define DEVHDR_SIZE 512
+#define MBOX_SIZE 48
+#define BIOS_SIGNATURE 0x55AAC731
+
+#define PCI_1 1
+#define PCI_2 2
+#define MAX 28
+
+#define PCI_BUS 1
+#define PCI_INDEX_PORT 0xCF8
+#define PCI_INDEX 0xF0
+#define PCI_CONFIG 0xC000 /* this needs to include slot number */
+
+#define FAIL -1
+/* #define GOOD 0 */
+#define ERR 1
+#define DONE 2
+#define INT_HALT 0xfe000000 /* interrupt code */
+
+#define SRB_DONE 0
+#define SRB_ACTIVE 2
+#define SRB_READY 1
+#define SRB_CLEAN 4
+#define SRB_ASSIGNED 8
+#define SRB_STOP 2
+
+#define STOP_RISC 2
+#define FIRST_CMD 1
+#define SPECIAL_CMD 1
+#define MAX_OFFSET 30
+/* #define MAX_PERIOD 12 */
+#define MAX_PERIOD 12
+#define W_MAX_OFFSET 14
+
+/* msg */
+#define CMD_ABORT 0x6
+#define DEVICE_RESET 0xC
+
+
+#define CHECK_SYNC 0xA
+#define CHECK_WIDE 0xD
+#define SYNC_NORESPONSE 0x8
+#define SYNC_REJECTED 0x9
+#define SEL_TIME_OUT 0x11
+#define ERR_OVERRUN 0x12
+#define ERR_BUSFREE 0x13
+#define ERR_PHASE 0x14
+#define CHECK_COND 0x04
+#define ERR_PARITY 0x05
+#define ERR_MESSAGE 0x07
+#define WIDE_NORESPONSE 0x0b
+#define WIDE_REJECTED 0x0c
+
+
+#define DO_WIDE_NEGO 0x02
+#define DO_SYNC_NEGO 0x04
+#define FIRST_COMMAND 0x01
+
+#define ENABLE_WIDE_BUS 0x100
+#define ENABLE_TAG_MSG 0x200
+
+/*---------------------------------------------------------*
+** parameter in register definitions *
+** *
+**---------------------------------------------------------*/
+/*
+ status register (read only)
+ */
+#define INTR_PENDING 0x01
+#define INTR_DIS 0x02
+#define SCAM_INTR_DIS 0x04
+#define POWER_SAVE_ON 0x08
+#define SCSI_RESET_OUT 0x10
+#define SCAM_INTR 0x20
+#define RISC_HALT 0x40
+#define SELECTION_TIMEOUT 0x80
+#define SCSI_PARITY_ERR 0x100
+#define SCSI_RESET_LAT 0x200
+#define STS_SCSI_RESET 0x400
+#define EEPROM_IN 0x800
+#define SCAM_ARB_WIN 0x1000
+#define EN_DMA 0x2000
+#define EN_ARB_SEL 0x4000
+/*
+ ** interrupt control register (write only)
+ */
+#define RESET_INTR_LATCH 0x01
+#define DIS_INTR 0x02
+#define DIS_SCAM_INTR 0x04
+#define POWER_SAVE 0x08
+#define RESET_SCSI_BUS 0x10
+/*ravi 10/3/98 changed for term power disable/enable in command line */
+/*#define EN_TERM_PWR 0x20 */
+#define TERM_PWR_EN 0x20
+/*
+ ** control register ( read/write )
+ */
+#define RISC_CHIP_RESET 0x01
+#define RISC_SINGLE_SETP 0x02
+#define HALT_RISC 0x04
+#define EN_SCSI_SCAM 0x08
+#define DIS_SCSI_PARITY 0x10
+#define EN_TARGET_MODE 0x20
+#define FAST_CLOCK 0x40
+#define EN_MEMORY_WRITE 0x80
+#define DIS_PCI_BURST 0x100
+#define DIS_PCI_CACHE_LINE 0x200
+#define DIS_MUL_CACHE_LINE 0x400
+#define EEPROM_CLOCK 0x800
+#define EEPROM_DATA_OUT 0x1000
+#define EEPROM_CHIP_SEL 0x2000
+#define FAST_SELECTION 0x4000
+#define EN_SCAM_ARB 0x8000
+
+#define TASK_DONE 0x80
+
+
+/***************************************************************************
+** filename: newtypes.h
+** usage : type definition
+****************************************************************************/
+
+
+/***************************************************************************
+** filename: newtypes.h
+** usage : type definition
+****************************************************************************/
+
+#define MAX_Adapter 4 /* maximu adapters allow */
+
+/*
+ ** command related structure (7 bytes)
+ */
+typedef struct _task_cmd
+{
+ u8 CmdInProcess;
+ u8 * REQ_Header;
+ void (*complete) (void);
+}
+TaskCmd, *PTaskCmd;
+
+/*
+ ** total 128 bytes
+ */
+typedef struct _HIM
+{
+ u8 status; /* device status, 0xFF not installed */
+ u8 Target_ID; /* target ID */
+ u8 type; /* target type mapped to device name */
+ u16 attrib; /* lo 4bit: 1-Wide, 2-Sync, 4-Tag, */
+ /* 8-removable, */
+ /* hi 4bit: 10h do wide, 20h do sync, */
+ /* 40h do tag, 0x80h - disc */
+ /* bit 15: under BIOS, bit 8: > 1GB */
+ u8 op_param; /* bit 7-5:period, bit4-0:offset */
+ u8 drv_num; /* current ID --> 8x for BIOS used only */
+ u8 sect_per_track; /* sector per track */
+ u8 head_per_cyl; /* sector per track */
+ u8 byte_per_sect; /* byte per sector (BIOS is 512) */
+ u8 link_count; /* SRB link count: */
+ u8 * ASPICMDLink; /* SRB link starting pointer */
+ TaskCmd task[16]; /* array structure for each task */
+
+}
+DEVStruct;
+
+/*
+ ** total (4K+ 36) bytes for each adapter
+ */
+typedef struct _Adapter
+{
+ u16 IoPort; /* I/O Port address, 0 notsupport */
+ u8 AdapterID; /* Adapter scsi ID, default = 7 */
+ u8 first_disk_num; /* first disk number under BIOS (82->2) */
+ u8 last_disk_num; /* last disk number under BIOS */
+ u8 time_factor; /* used for device scam */
+
+ u8 IntrNum; /* -1 NotSupport, otherwise IRQ */
+ u16 hw_attr; /* see eeprom def */
+ u16 sw_attr; /* see eeprom def */
+ DEVStruct dev[16]; /* target device structure */
+ u16 mbx_out_ptr; /* mail box out pointer */
+ u8 HAParam[16]; /* host adapter parameters */
+ u8 bios_install; /* adapter has BIOS installed */
+ u16 scam_type; /* scam use */
+ u8 scam_assigned; /* scam use */
+ u8 * Signature; /* BIOS signature & new manager address */
+ u32 mbx_in_base; /* mbx in base logical address */
+ u32 mbx_out_base; /* mbx out base logical address */
+ u32 devhdr_base; /* devhdr base logical address */
+ u32 taskq_base; /* taskq base logical address */
+ u32 ptaskq_base; /* taskq base physical address */
+ u32 pdev_base; /* taskq base physical address */
+ u32 pmbi_base; /* taskq base physical address */
+ u32 pmbo_base; /* taskq base physical address */
+}
+Adapter, *PAdapter;
+
+/*
+ ** adapter information structure reserved for BIOS usage
+ */
+
+typedef struct _dev_parm
+{
+ u8 header; /* header */
+ u8 sect_per_track; /* sector per tarck */
+}
+target_parm, *ptarget_parm;
+/*
+ ** This structure is for BIOS used and read by driver
+ */
+typedef struct _Ada_data
+{
+ u8 drv_start; /* first drive */
+ u8 drv_end; /* last drive */
+ u16 timfact; /* timing factor */
+ u32 old_int13; /* old int13 addr */
+ u8 drive_id[8]; /* index= (8x-drv_start) */
+ u8 drive_num[16]; /* device number */
+ target_parm dev[16]; /* device parameters */
+ u8 allow_discon[16]; /* disconnect record */
+ u16 scam_type; /* scam use */
+ u8 scam_assigned; /* scam use */
+ u8 adapter_id; /* scam use */
+ u32 signature; /* BIOS signature */
+}
+HA_data, *PHA_data;
+
+
+typedef struct _ScatGath
+{
+ u32 sg_address; /* must be physical address */
+ u32 sg_length; /* sg length */
+}
+ScatGath, *PScatGath;
+
+/* length must be 32 bytes */
+typedef struct _risc_srb
+{
+ u8 Tag_info; /* Tag information */
+ u8 SRB_flag; /* SRB flag */
+ u8 DEV_Status; /* SRB status */
+ u8 ScsiStatus; /* scsi command status */
+ u32 CDB; /* SCSI Command Block */
+ u32 CDBLength; /* SCSI Command Length */
+ u32 SenseDataPtr; /* auto sense pointer */
+ u32 Sense_Cmd_Ptr; /* auto sense pointer */
+ u32 SG_ListPtr; /* SG list */
+ u8 SGNum; /* S/G number */
+ u8 Identify; /* Identify message */
+ u8 Sense_LUN; /* lun */
+ u8 Sense_len; /* sense len */
+ u32 Cmd_sg_addr; /* cmr sg ptr point to cmd */
+}
+RISC_SRB, *PRISC_SRB;
+
+
+typedef struct _SRB
+{ /* for SCSI */
+ RISC_SRB *risc_srb; /* structure of SRB in RISC */
+ PAdapter AdapterPtr; /* a pointer to adapter structure */
+ u8 LUN; /* lun number */
+ u8 Tag_type; /* tag type */
+ u8 Request_type; /* request type */
+}
+SRB, *PSRB;
+
+typedef struct _sync_tbl
+{
+ int period; /* parameter setting */
+ int f_factor; /* fast clock factor */
+ int s_factor; /* slow clock factor */
+}
+sync_tbl;
+
+/*
+ ** total 12 bytes of sg header
+ */
+typedef struct _dma_hrd
+{
+ u32 size; /* region size */
+ u32 offset; /* offste */
+ u16 segment; /* segment */
+ u16 revsed; /* reserved */
+ u16 num_avail; /* number available */
+ u16 num_used; /* number used */
+}
+DMA_HDR;
+
+/*
+ ** total 60 bytes (for each task in windows)
+ */
+typedef struct _dma_desc
+{
+ DMA_HDR dma_hdr;
+ ScatGath sg_list[6];
+}
+dma_desc, *Pdma_desc;
+
+/* Flags */
+#define SRB_TOHOST 8
+#define SRB_TOTARGET 0x10
+#define SRB_NEEDSDT 0x20
+#define SRB_SENSE 0x40 /* only for OSD */
+#define SIZE_OF_SG 0x3C /* size of sg table (60 bytes) */
+
+/* 2. Target Error == SCSI Status */
+
+/* ============ function definiton ============
+ ** 1. INPUT: PSRB
+ ** Start a scsi command.
+ * */
+static void StartScsiCmd(PRISC_SRB);
+
+#define CMD_INPROGRESS 0x01
+#define CMD_DISCONCTED 0x02
+#define CMD_DATAXFERED 0x04
+
+#define TAR_TRUESG 0x01
+#define NEEDSDTN 0x10
+
+#define MSG_ABORT 0x06
+#define MSG_RESET 0x0C
+#define MSG_ALLOWDISC 0x40
+#define MSG_IDENTIFY 0x80
+#define MSG_EXTENDED 0x01
+#define MSG_NOMSG 0x08
+#define MSG_CMDCOMP 0x00
+#define MSG_DISC 0x04
+#define MSG_IGNWR 0x23
+#define MSG_RESTPTR 0x03
+#define MSG_SAVEPTR 0x02
+#define MSG_REJECTED 0x07
+#define MSG_INITRECVY 0x0f
+#define MSG_LNKCMD 0x0a
+#define MSG_LNKCMDTAG 0x0b
+#define MSG_SIMPLEQUE 0x20
+#define MSG_MDFDATPTR 0x00
+#define MSG_SDTREQ 0x01
+#define MSG_WDTREQ 0x03
+
+#define SECOND 18 //ticks per second
+#define DEV_EMPTY 0xFF
+
+typedef struct _DEVHDR
+{
+ u32 Updatedmap; /* updated bitmap */
+ u32 Startedmap; /* start bitmap */
+ u32 Currentmap; /* current bitmap */
+ u8 Task_Index; /* current task index */
+ u8 Request_type; /* request type */
+ u8 SpCmddone; /* special commad done */
+ u8 Srb_loc; /* location */
+ u8 TagCmdCnt; /* Pending task count */
+ u8 ScsiID; /* scsi ID */
+ u8 DeviceNum; /* device number */
+ u8 WideMsg; /* wide bus message */
+ u8 SyncPeriod; /* sync period */
+ u8 SyncOffset; /* sync offset */
+ u8 RtnWideMsg; /* return wide bus msg */
+ u8 RtnSyncPeriod; /* Rtn sync period */
+ u8 RtnSyncOffset; /* rtn sync offset */
+ u8 ChkSenseTask; /* check sense task */
+ u8 SenseCmd[6]; /* sense command */
+}
+DevHdr, *PDevHdr;
+
+typedef struct _E2Prom
+{
+ u16 hw_parm;
+ u16 sw_parm;
+ u16 dev_parm[16];
+}
+E2prom, *PE2prom;
+
+/* parameter setting for parameter */
+#define HW_ADAPTER_ID 0x0f
+#define HW_PARITY_DISABLE 0x10
+#define HW_TERMPWR_ENABLE 0x20
+#define HW_FAST_CLOCK 0x40
+#define HW_DIAG_ENABLE 0x80
+#define HW_BURST_DISABLE 0x100
+#define HW_CACHE_LINE_DISABLE 0x200
+#define HW_MULTI_CACHE_DISABLE 0x400
+#define HW_SCAM_ENABLE 0x800
+#define HW_CACHE_LINE_SIZE_4 0x1000
+#define HW_CACHE_LINE_SIZE_8 0x2000
+#define HW_CACHE_LINE_SIZE_16 0x3000
+#define HW_FAST_SELECTION 0x4000
+#define HW_BIOS_DISABLE 0x8000
+
+
+/* software setting */
+#define SW_REMOVABLE_SUPPORT 0x1
+#define SW_OVER_1GB 0x2
+#define SW_8_DRIVE_SUPPORT 0x4
+#define SW_MAX_ID 0x8
+#define SW_DEVICE_CHANGED 0x10
+
+/* parameter setting */
+#define PM_UNDER_BIOS 0x8000
+#define PM_BIOSSCAN_DISABLE 0x2000
+#define PM_NEED_STARTCMD 0x1000
+#define PM_DISCON_ENABLE 0x800
+#define PM_SYNC_ENABLE 0x400
+#define PM_TAG_ENABLE 0x200
+#define PM_WIDEBUS_ENABLE 0x100
+#define PM_TRANSFER_RATE 0xE0
+#define PM_TRANSFER_OFFSET 0x1F
+
+/* ScsiFunc */
+#define SUPPORT_MORETHAN16M 0x40
+#define SUPPORT_RESELECT 0x20
+#define SUPPORT_SYNC 0x10
+#define SUPPORT_LINKED 0x08
+#define SUPPORT_CMDQUEUE 0x02
+#define SUPPORT_SFTRE 0x01
+#define SUPPORT_WIDEHOST 0x04


SHAR_EOF
true || echo 'restore of patch-2.0.37 failed'
fi

echo 'End of part 40'
echo 'File patch-2.0.37 is continued in part 41'
echo 41 > _shar_seq_.tmp
exit 0

Thomas...@ciw.uni-karlsruhe.de

unread,
Jun 16, 1999, 3:00:00 AM6/16/99
to
Archive-name: v2.0/patch-2.0.37/part39

#!/bin/sh
# this is part 39 of a 45 - part archive


# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.0.37 continued
if test ! -r _shar_seq_.tmp; then
echo 'Please unpack part 1 first!'
exit 1
fi
(read Scheck

if test "$Scheck" != 39; then


echo Please unpack part "$Scheck" next!
exit 1
else
exit 0
fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.0.37'
else
echo 'x - continuing with patch-2.0.37'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.0.37' &&

+ udelay(160);
+}
+
+#ifndef CONFIG_SCSI_DC390T_NOGENSUPP
+static void __init dc390_EEpromDefaults (UCHAR index)
+{
+ PUCHAR ptr;
+ UCHAR id;
+ ptr = (PUCHAR) dc390_eepromBuf[index];
+
+ /* Adapter Settings */
+ ptr[EE_ADAPT_SCSI_ID] = (UCHAR)tmscsim[0]; /* Adapter ID */
+ ptr[EE_MODE2] = (UCHAR)tmscsim[3];
+ ptr[EE_DELAY] = 0; /* ?? */
+ ptr[EE_TAG_CMD_NUM] = (UCHAR)tmscsim[4]; /* Tagged Comds */
+
+ /* Device Settings */
+ for (id = 0; id < MAX_SCSI_ID; id++)
+ {
+ ptr[id<<2] = (UCHAR)tmscsim[2]; /* EE_MODE1 */
+ ptr[(id<<2) + 1] = (UCHAR)tmscsim[1]; /* EE_Speed */
+ };
+ dc390_adapname = "AM53C974";
+}
+
+static void __init dc390_checkparams (void)
+{
+ PARSEDEBUG(printk(KERN_INFO "DC390: setup %08x %08x %08x %08x %08x\n", tmscsim[0],\
+ tmscsim[1], tmscsim[2], tmscsim[3], tmscsim[4]);)
+ if (tmscsim[0] < 0 || tmscsim[0] > 7) /* modules-2.0.0 passes -1 as string */
+ {
+ tmscsim[0] = 7; tmscsim[1] = 4;
+ tmscsim[2] = 9; tmscsim[3] = 15;
+ tmscsim[4] = 2;
+ printk (KERN_INFO "DC390: Using safe settings.\n");
+ }
+ else
+ {
+ /* if (tmscsim[0] < 0 || tmscsim[0] > 7) tmscsim[0] = 7; */
+ if (tmscsim[1] < 0 || tmscsim[1] > 7) tmscsim[1] = 4;
+ if (tmscsim[4] < 0 || tmscsim[4] > 5) tmscsim[4] = 4;
+ };
+};
+/* Override defaults on cmdline:
+ * tmscsim: AdaptID, MaxSpeed (Index), DevMode (Bitmapped), AdaptMode (Bitmapped)
+ */
+void __init dc390_setup (char *str, int *ints)
+{
+ int i;
+ for (i = 0; i < ints[0]; i++)
+ tmscsim[i] = ints[i+1];
+ if (ints[0] > 5)
+ printk (KERN_NOTICE "DC390: ignore extra params!\n");
+ /* dc390_checkparams (); */
+};
+#endif /* CONFIG_SCSI_DC390T_NOGENSUPP */
+
+
+static void __init dc390_EEpromOutDI( PDEVDECL, PUCHAR regval, UCHAR Carry )
+{
+ UCHAR bval;


+
+ bval = 0;

+ if(Carry)
+ {
+ bval = 0x40;
+ *regval = 0x80;
+ PCI_WRITE_CONFIG_BYTE(PDEV, *regval, bval);
+ }
+ udelay(160);
+ bval |= 0x80;
+ PCI_WRITE_CONFIG_BYTE(PDEV, *regval, bval);
+ udelay(160);
+ bval = 0;
+ PCI_WRITE_CONFIG_BYTE(PDEV, *regval, bval);
+ udelay(160);
+}
+
+
+static UCHAR __init dc390_EEpromInDO( PDEVDECL )
+{
+ UCHAR bval;
+
+ PCI_WRITE_CONFIG_BYTE(PDEV, 0x80, 0x80);
+ udelay(160);
+ PCI_WRITE_CONFIG_BYTE(PDEV, 0x80, 0x40);
+ udelay(160);
+ PCI_READ_CONFIG_BYTE(PDEV, 0x00, &bval);
+ if(bval == 0x22)
+ return(1);
+ else
+ return(0);
+}
+
+
+static USHORT __init dc390_EEpromGetData1( PDEVDECL )
+{
+ UCHAR i;
+ UCHAR carryFlag;
+ USHORT wval;
+
+ wval = 0;
+ for(i=0; i<16; i++)
+ {
+ wval <<= 1;
+ carryFlag = dc390_EEpromInDO(PDEV);
+ wval |= carryFlag;
+ }
+ return(wval);
+}
+
+
+static void __init dc390_Prepare( PDEVDECL, PUCHAR regval, UCHAR EEpromCmd )
+{
+ UCHAR i,j;
+ UCHAR carryFlag;
+
+ carryFlag = 1;
+ j = 0x80;
+ for(i=0; i<9; i++)
+ {
+ dc390_EEpromOutDI(PDEV,regval,carryFlag);
+ carryFlag = (EEpromCmd & j) ? 1 : 0;
+ j >>= 1;
+ }
+}
+
+
+static void __init dc390_ReadEEprom( PDEVDECL, PUSHORT ptr)
+{
+ UCHAR regval,cmd;
+ UCHAR i;
+
+ cmd = EEPROM_READ;
+ for(i=0; i<0x40; i++)
+ {
+ dc390_EnDisableCE(ENABLE_CE, PDEV, &regval);
+ dc390_Prepare(PDEV, &regval, cmd++);
+ *ptr++ = dc390_EEpromGetData1(PDEV);
+ dc390_EnDisableCE(DISABLE_CE, PDEV, &regval);
+ }
+}
+
+
+static UCHAR __init dc390_CheckEEpromCheckSum( PDEVDECL, UCHAR index )
+{
+ UCHAR i;
+ char EEbuf[128];
+ USHORT wval, *ptr = (PUSHORT)EEbuf;
+
+ dc390_ReadEEprom( PDEV, ptr );
+ memcpy (dc390_eepromBuf[index], EEbuf, EE_ADAPT_SCSI_ID);
+ memcpy (&dc390_eepromBuf[index][EE_ADAPT_SCSI_ID],
+ &EEbuf[REAL_EE_ADAPT_SCSI_ID], EE_LEN - EE_ADAPT_SCSI_ID);
+ wval = 0;
+ for(i=0; i<0x40; i++, ptr++)
+ wval += *ptr;
+ return (wval == 0x1234 ? 0 : 1);
+}
+
+
+/***********************************************************************
+ * Functions for the management of the internal structures
+ * (DCBs, SRBs, Queueing)
X *
X **********************************************************************/
-static void
-QLinkcmd( PSCSICMD cmd, PDCB pDCB )
+static PDCB __inline__ dc390_findDCB ( PACB pACB, Scsi_Cmnd *cmd)
X {
- ULONG flags;
- PSCSICMD pcmd;
+ PDCB pDCB = pACB->pLinkDCB; if (!pDCB) return 0;
+ while (pDCB->UnitSCSIID != cmd->target || pDCB->UnitSCSILUN != cmd->lun)
+ {


+ pDCB = pDCB->pNextDCB;

+ if (pDCB == pACB->pLinkDCB)
+ {
+ printk (KERN_WARNING "DC390: DCB not found (DCB=%08x, DCBmap[%2x]=%2x)\n",
+ (int)pDCB, cmd->target, pACB->DCBmap[cmd->target]);
+ return 0;
+ }
+ };
+ DCBDEBUG1( printk (KERN_DEBUG "DCB %08x (%02x,%02x) found.\n", \
+ (int)pDCB, pDCB->UnitSCSIID, pDCB->UnitSCSILUN);)
+ return pDCB;
+};
X
- save_flags(flags);
- cli();
+static void dc390_QLinkcmd( PSCSICMD cmd, PDCB pDCB )
+{
+ PSCSICMD pcmd;
X
X if( !pDCB->QIORBCnt )
X {
@@ -194,83 +711,61 @@
X cmd->next = NULL;
X }
X

- restore_flags(flags);
X }
X
X

-static PSCSICMD
-Getcmd( PDCB pDCB )
+static __inline__ PSCSICMD dc390_Getcmd( PDCB pDCB )
X {
- ULONG flags;
X PSCSICMD pcmd;
X
- save_flags(flags);
- cli();
-
X pcmd = pDCB->pQIORBhead;
X pDCB->pQIORBhead = pcmd->next;
X pcmd->next = NULL;
X pDCB->QIORBCnt--;
X
- restore_flags(flags);
X return( pcmd );
X }
X
X
-static PSRB
-GetSRB( PACB pACB )
+static __inline__ PSRB dc390_GetSRB( PACB pACB )
X {
- ULONG flags;
X PSRB pSRB;
X
- save_flags(flags);
- cli();
-
X pSRB = pACB->pFreeSRB;
X if( pSRB )
X {
X pACB->pFreeSRB = pSRB->pNextSRB;
X pSRB->pNextSRB = NULL;
X }
- restore_flags(flags);
+
X return( pSRB );
X }
X
X
-static void
-RewaitSRB0( PDCB pDCB, PSRB pSRB )
+static __inline__ void dc390_RewaitSRB0( PDCB pDCB, PSRB pSRB )
X {
X PSRB psrb1;
- ULONG flags;


-
- save_flags(flags);
- cli();

X
X if( (psrb1 = pDCB->pWaitingSRB) )
X {
X pSRB->pNextSRB = psrb1;
- pDCB->pWaitingSRB = pSRB;
X }
X else
X {
X pSRB->pNextSRB = NULL;
- pDCB->pWaitingSRB = pSRB;
X pDCB->pWaitLast = pSRB;
X }
- restore_flags(flags);
+ pDCB->pWaitingSRB = pSRB;
X }
X
X
-static void
-RewaitSRB( PDCB pDCB, PSRB pSRB )
+static void dc390_RewaitSRB( PDCB pDCB, PSRB pSRB )
X {
X PSRB psrb1;
- ULONG flags;
X UCHAR bval;
X
- save_flags(flags);
- cli();
- pDCB->GoingSRBCnt--;
+ pDCB->GoingSRBCnt--; pDCB->pDCBACB->SelLost++;
+ DEBUG0(printk(KERN_INFO "DC390: RewaitSRB (%p, %p) pid = %li\n", pDCB, pSRB, pSRB->pcmd->pid);)
X psrb1 = pDCB->pGoingSRB;
X if( pSRB == psrb1 )
X {
@@ -298,20 +793,14 @@
X
X bval = pSRB->TagNumber;
X pDCB->TagMask &= (~(1 << bval)); /* Free TAG number */


- restore_flags(flags);
X }
X
X

-static void
-DoWaitingSRB( PACB pACB )
+static void dc390_DoWaitingSRB( PACB pACB )
X {
- ULONG flags;
X PDCB ptr, ptr1;
X PSRB pSRB;
X
- save_flags(flags);
- cli();
-
X if( !(pACB->pActiveDCB) && !(pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV) ) )
X {
X ptr = pACB->pDCBRunRobin;
@@ -333,7 +822,7 @@
X }
X else
X {
- if( !DC390_StartSCSI(pACB, ptr1, pSRB) )
+ if( !dc390_StartSCSI(pACB, ptr1, pSRB) )
X {
X ptr1->GoingSRBCnt++;
X if( ptr1->pWaitLast == pSRB )
@@ -357,55 +846,54 @@
X }
X }
X }
- restore_flags(flags);


X return;
X }
X
X

-static void
-SRBwaiting( PDCB pDCB, PSRB pSRB)
+static __inline__ void dc390_SRBwaiting( PDCB pDCB, PSRB pSRB)
X {
X if( pDCB->pWaitingSRB )
X {
X pDCB->pWaitLast->pNextSRB = pSRB;
- pDCB->pWaitLast = pSRB;
X pSRB->pNextSRB = NULL;
X }
X else
X {
X pDCB->pWaitingSRB = pSRB;
- pDCB->pWaitLast = pSRB;
X }
+ pDCB->pWaitLast = pSRB;
X }
X
X
-static void
-SendSRB( PSCSICMD pcmd, PACB pACB, PSRB pSRB )
+/***********************************************************************
+ * Function: static void dc390_SendSRB (PACB pACB, PSRB pSRB)
+ *
+ * Purpose: Send SCSI Request Block (pSRB) to adapter (pACB)
+ *
+ ***********************************************************************/
+
+static void dc390_SendSRB( PACB pACB, PSRB pSRB )
X {
- ULONG flags;
X PDCB pDCB;
X
- save_flags(flags);
- cli();
-
X pDCB = pSRB->pSRBDCB;
X if( !(pDCB->MaxCommand > pDCB->GoingSRBCnt) || (pACB->pActiveDCB) ||
X (pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV)) )
X {
- SRBwaiting(pDCB, pSRB);
+ dc390_SRBwaiting(pDCB, pSRB);
X goto SND_EXIT;
X }
X
X if( pDCB->pWaitingSRB )
X {
- SRBwaiting(pDCB, pSRB);
-/* pSRB = GetWaitingSRB(pDCB); */
+ dc390_SRBwaiting(pDCB, pSRB);
+/* pSRB = GetWaitingSRB(pDCB); */ /* non-existent */
X pSRB = pDCB->pWaitingSRB;
X pDCB->pWaitingSRB = pSRB->pNextSRB;
X pSRB->pNextSRB = NULL;
X }
X
- if( !DC390_StartSCSI(pACB, pDCB, pSRB) )
+ if( !dc390_StartSCSI(pACB, pDCB, pSRB) )
X {
X pDCB->GoingSRBCnt++;
X if( pDCB->pGoingSRB )
@@ -420,13 +908,60 @@
X }
X }
X else
- RewaitSRB0( pDCB, pSRB );
+ dc390_RewaitSRB0( pDCB, pSRB );
X
X SND_EXIT:
- restore_flags(flags);
X return;
X }
X
+/***********************************************************************
+ * Function: static void dc390_BuildSRB (Scsi_Cmd *pcmd, PDCB pDCB,
+ * PSRB pSRB)
+ *
+ * Purpose: Prepare SRB for being sent to Device DCB w/ command *pcmd
+ *
+ ***********************************************************************/
+
+static void dc390_BuildSRB (Scsi_Cmnd* pcmd, PDCB pDCB, PSRB pSRB)
+{
+ pSRB->pSRBDCB = pDCB;
+ pSRB->pcmd = pcmd;
+ pSRB->ScsiCmdLen = pcmd->cmd_len;
+ memcpy (pSRB->CmdBlock, pcmd->cmnd, pcmd->cmd_len);
+
+ if( pcmd->use_sg )
+ {
+ pSRB->SGcount = (UCHAR) pcmd->use_sg;
+ pSRB->pSegmentList = (PSGL) pcmd->request_buffer;
+ }
+ else if( pcmd->request_buffer )
+ {
+ pSRB->SGcount = 1;
+ pSRB->pSegmentList = (PSGL) &pSRB->Segmentx;
+ pSRB->Segmentx.address = (PUCHAR) pcmd->request_buffer;
+ pSRB->Segmentx.length = pcmd->request_bufflen;
+ }
+ else
+ pSRB->SGcount = 0;
+
+ pSRB->SGIndex = 0;
+ pSRB->AdaptStatus = 0;
+ pSRB->TargetStatus = 0;
+ pSRB->MsgCnt = 0;
+ if( pDCB->DevType != TYPE_TAPE )
+ pSRB->RetryCnt = 1;
+ else
+ pSRB->RetryCnt = 0;
+ pSRB->SRBStatus = 0;
+ pSRB->SRBFlag = 0;
+ pSRB->SRBState = 0;
+ pSRB->TotalXferredLen = 0;
+ pSRB->SGBusAddr = 0;
+ pSRB->SGToBeXferLen = 0;
+ pSRB->ScsiPhase = 0;
+ pSRB->EndMessage = 0;
+};
+
X
X /***********************************************************************
X * Function : static int DC390_queue_command (Scsi_Cmnd *cmd,
@@ -434,276 +969,307 @@
X *
X * Purpose : enqueues a SCSI command
X *
- * Inputs : cmd - SCSI command, done - function called on completion, with
- * a pointer to the command descriptor.
+ * Inputs : cmd - SCSI command, done - callback function called on
+ * completion, with a pointer to the command descriptor.
X *
- * Returns : 0
+ * Returns : (depending on kernel version)
+ * 2.0.x: always return 0
+ * 2.1.x: old model: (use_new_eh_code == 0): like 2.0.x
+ * TO BE DONE:
+ * new model: return 0 if successful
+ * return 1 if command cannot be queued (queue full)
+ * command will be inserted in midlevel queue then ...
X *
X ***********************************************************************/
X
-int
-DC390_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *))
+int DC390_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *))
X {
- USHORT ioport, i;
X Scsi_Cmnd *pcmd;
- struct Scsi_Host *psh;
- PACB pACB;
X PDCB pDCB;
X PSRB pSRB;
- ULONG flags;
- PUCHAR ptr,ptr1;
+ DC390_AFLAGS
+ PACB pACB = (PACB) cmd->host->hostdata;
X
- psh = cmd->host;
- pACB = (PACB ) psh->hostdata;


- ioport = pACB->IOPortBase;

X
-#ifdef DC390_DEBUG0
-/* if(pACB->scan_devices) */
- printk("Cmd=%2x,ID=%d,LUN=%d,",cmd->cmnd[0],cmd->target,cmd->lun);
-#endif
+ DEBUG0(/* if(pACB->scan_devices) */ \
+ printk(KERN_INFO "DC390: Queue Cmd=%02x,ID=%d,LUN=%d (pid=%li)\n",\
+ cmd->cmnd[0],cmd->target,cmd->lun,cmd->pid);)
+
+ DC390_LOCK_ACB;
+
+ /* Assume BAD_TARGET; will be cleared later */
+ cmd->result = DID_BAD_TARGET << 16;
+
+ /* TODO: Change the policy: Alway accept TEST_UNIT_READY or INQUIRY
+ * commands and alloc a DCB for the device if not yet there. DCB will
+ * be removed in dc390_SRBdone if SEL_TIMEOUT */
X
X if( (pACB->scan_devices == END_SCAN) && (cmd->cmnd[0] != INQUIRY) )
- {
X pACB->scan_devices = 0;
- pPrevDCB->pNextDCB = pACB->pLinkDCB;
- }
- else if( (pACB->scan_devices) && (cmd->cmnd[0] == 8) )
- {
+
+ else if( (pACB->scan_devices) && (cmd->cmnd[0] == READ_6) )
X pACB->scan_devices = 0;
- pPrevDCB->pNextDCB = pACB->pLinkDCB;
- }
X
- if ( ( cmd->target > pACB->max_id ) || (cmd->lun > pACB->max_lun) )
+ if ( ( cmd->target >= pACB->pScsiHost->max_id ) ||
+ (cmd->lun >= pACB->pScsiHost->max_lun) )
X {
X /* printk("DC390: Ignore target %d lun %d\n",
X cmd->target, cmd->lun); */
- cmd->result = (DID_BAD_TARGET << 16);
+ DC390_UNLOCK_ACB;
X done(cmd);


X return( 0 );
X }
X

- if( (pACB->scan_devices) && !(pACB->DCBmap[cmd->target] & (1 << cmd->lun)) )
+ if( (pACB->scan_devices || cmd->cmnd[0] == TEST_UNIT_READY) && !(pACB->DCBmap[cmd->target] & (1 << cmd->lun)) )
X {
- if( pACB->DeviceCnt < MAX_DEVICES )
- {
- pACB->DCBmap[cmd->target] |= (1 << cmd->lun);
- pDCB = pACB->pDCB_free;
-#ifdef DC390_DEBUG0
- printk("pDCB=%8x,ID=%2x,", (UINT) pDCB, cmd->target);
-#endif
- DC390_initDCB( pACB, pDCB, cmd );
- }
- else /* ???? */
- {
-/* printk("DC390: Ignore target %d lun %d\n",
- cmd->target, cmd->lun); */
- cmd->result = (DID_BAD_TARGET << 16);
+ pACB->DCBmap[cmd->target] |= (1 << cmd->lun);
+ pACB->scan_devices = 1;
+
+ dc390_initDCB( pACB, &pDCB, cmd );
+ if (!pDCB)
+ {
+ printk (KERN_ERR "DC390: kmalloc for DCB failed, ID=%2x\n", cmd->target);
+ DC390_UNLOCK_ACB;
X done(cmd);
X return(0);
- }
+ };
+
X }
X else if( !(pACB->scan_devices) && !(pACB->DCBmap[cmd->target] & (1 << cmd->lun)) )
X {
-/* printk("DC390: Ignore target %d lun %d\n",
- cmd->target, cmd->lun); */
- cmd->result = (DID_BAD_TARGET << 16);
+ printk(KERN_INFO "DC390: Ignore target %02x lun %02x\n",
+ cmd->target, cmd->lun);
+ DC390_UNLOCK_ACB;
X done(cmd);
X return(0);
X }
X else
X {
- pDCB = pACB->pLinkDCB;
- while( (pDCB->UnitSCSIID != cmd->target) ||
- (pDCB->UnitSCSILUN != cmd->lun) )
- {
- pDCB = pDCB->pNextDCB;
- }
-#ifdef DC390_DEBUG0
- printk("pDCB=%8x,ID=%2x,", (UINT) pDCB, cmd->target);
-#endif
+ pDCB = dc390_findDCB (pACB, cmd);
+ if (!pDCB)
+ { /* should never happen */
+ DC390_UNLOCK_ACB;
+ done(cmd);
+ return(0);
+ };
X }
X
+ pACB->Cmds++;
X cmd->scsi_done = done;
X cmd->result = 0;
X
- save_flags(flags);
- cli();
-
- if( pDCB->QIORBCnt )
+ if( pDCB->QIORBCnt ) /* Unsent commands ? */
X {
- QLinkcmd( cmd, pDCB );
- pcmd = Getcmd( pDCB );
+ dc390_QLinkcmd( cmd, pDCB );
+ pcmd = dc390_Getcmd( pDCB ); /* Get first command */
+ pACB->CmdInQ++;
X }
X else
X pcmd = cmd;
X
- pSRB = GetSRB( pACB );
+ pSRB = dc390_GetSRB( pACB );
X
X if( !pSRB )
X {
- QLinkcmd( pcmd, pDCB );
- restore_flags(flags);
+ dc390_QLinkcmd( pcmd, pDCB ); /* Queue command at the end */
+ pACB->CmdOutOfSRB++;
+ DC390_UNLOCK_ACB;
X return(0);
X }
X
-/* BuildSRB(pSRB); */
+ dc390_BuildSRB (pcmd, pDCB, pSRB);
+ dc390_SendSRB( pACB, pSRB );
X
- pSRB->pSRBDCB = pDCB;
- pSRB->pcmd = pcmd;


- ptr = (PUCHAR) pSRB->CmdBlock;

- ptr1 = (PUCHAR) pcmd->cmnd;
- pSRB->ScsiCmdLen = pcmd->cmd_len;
- for(i=0; i< pcmd->cmd_len; i++)
+ DC390_UNLOCK_ACB;
+ DEBUG1(printk (KERN_DEBUG " ... command (%02x) queued successfully.\n", pcmd->cmnd[0]);)
+ return(0);
+}
+
+
+static void dc390_DoNextCmd( PACB pACB, PDCB pDCB )
+{
+ Scsi_Cmnd *pcmd;
+ PSRB pSRB;
+
+ if( pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV) )
+ return;
+
+ pcmd = dc390_Getcmd( pDCB );
+ pSRB = dc390_GetSRB( pACB );
+ if( !pSRB )
+ dc390_QLinkcmd( pcmd, pDCB );
+ else
+ {
+ dc390_BuildSRB (pcmd, pDCB, pSRB);
+ dc390_SendSRB( pACB, pSRB );
+ };
+}
+
+/* We ignore mapping problems, as we expect everybody to respect
+ * valid partition tables. Waiting for complaints ;-) */
+
+#ifdef CONFIG_SCSI_DC390T_TRADMAP
+/*
+ * The next function, partsize(), is copied from scsicam.c.
+ *
+ * This is ugly code duplication, but I didn't find another way to solve it:
+ * We want to respect the partition table and if it fails, we apply the
+ * DC390 BIOS heuristic. Too bad, just calling scsicam_bios_param() doesn't do
+ * the job, because we don't know, whether the values returned are from
+ * the part. table or determined by setsize(). Unfortunately the setsize()
+ * values differ from the ones chosen by the DC390 BIOS.
+ *
+ * Looking forward to seeing suggestions for a better solution! KG, 98/10/14
+ */
+#include <asm/unaligned.h>
+
+/*
+ * Function : static int partsize(struct buffer_head *bh, unsigned long
+ * capacity,unsigned int *cyls, unsigned int *hds, unsigned int *secs);
+ *
+ * Purpose : to determine the BIOS mapping used to create the partition
+ * table, storing the results in *cyls, *hds, and *secs
+ *
+ * Returns : -1 on failure, 0 on success.


+ *
+ */
+

+static int partsize(struct buffer_head *bh, unsigned long capacity,
+ unsigned int *cyls, unsigned int *hds, unsigned int *secs) {
+ struct partition *p, *largest = NULL;
+ int i, largest_cyl;
+ int cyl, ext_cyl, end_head, end_cyl, end_sector;
+ unsigned int logical_end, physical_end, ext_physical_end;
+
+
+ if (*(unsigned short *) (bh->b_data+510) == 0xAA55) {
+ for (largest_cyl = -1, p = (struct partition *)
+ (0x1BE + bh->b_data), i = 0; i < 4; ++i, ++p) {
+ if (!p->sys_ind)
+ continue;
+ cyl = p->cyl + ((p->sector & 0xc0) << 2);
+ if (cyl > largest_cyl) {
+ largest_cyl = cyl;
+ largest = p;
+ }
+ }
+ }
+
+ if (largest) {
+ end_cyl = largest->end_cyl + ((largest->end_sector & 0xc0) << 2);
+ end_head = largest->end_head;
+ end_sector = largest->end_sector & 0x3f;
+
+ physical_end = end_cyl * (end_head + 1) * end_sector +
+ end_head * end_sector + end_sector;
+
+ /* This is the actual _sector_ number at the end */
+ logical_end = get_unaligned(&largest->start_sect)
+ + get_unaligned(&largest->nr_sects);
+
+ /* This is for >1023 cylinders */
+ ext_cyl= (logical_end-(end_head * end_sector + end_sector))
+ /(end_head + 1) / end_sector;
+ ext_physical_end = ext_cyl * (end_head + 1) * end_sector +
+ end_head * end_sector + end_sector;
+
+ if ((logical_end == physical_end) ||
+ (end_cyl==1023 && ext_physical_end==logical_end)) {
+ *secs = end_sector;
+ *hds = end_head + 1;
+ *cyls = capacity / ((end_head + 1) * end_sector);


+ return 0;
+ }
+ }

+ return -1;
+}
+

+/***********************************************************************
+ * Function:
+ * DC390_bios_param


+ *
+ * Description:

+ * Return the disk geometry for the given SCSI device.
+ * Respect the partition table, otherwise try own heuristic


+ *
+ * Note:

+ * In contrary to other externally callable funcs (DC390_), we don't lock
+ ***********************************************************************/
+int DC390_bios_param (Disk *disk, kdev_t devno, int geom[])
+{
+ int heads, sectors, cylinders;
+ PACB pACB = (PACB) disk->device->host->hostdata;
+ struct buffer_head *bh;
+ int ret_code = -1;
+ int size = disk->capacity;
+
+ if ((bh = bread(MKDEV(MAJOR(devno), MINOR(devno)&~0xf), 0, 1024)))
X {
- *ptr = *ptr1;
- ptr++;
- ptr1++;
+ /* try to infer mapping from partition table */
+ ret_code = partsize (bh, (unsigned long) size, (unsigned int *) geom + 2,
+ (unsigned int *) geom + 0, (unsigned int *) geom + 1);
+ brelse (bh);
X }
- if( pcmd->use_sg )
+ if (ret_code == -1)
X {
- pSRB->SGcount = (UCHAR) pcmd->use_sg;
- pSRB->pSegmentList = (PSGL) pcmd->request_buffer;
- }
- else if( pcmd->request_buffer )
- {
- pSRB->SGcount = 1;
- pSRB->pSegmentList = (PSGL) &pSRB->Segmentx;
- pSRB->Segmentx.address = (PUCHAR) pcmd->request_buffer;
- pSRB->Segmentx.length = pcmd->request_bufflen;
- }
- else
- pSRB->SGcount = 0;
-
- pSRB->SGIndex = 0;
- pSRB->AdaptStatus = 0;
- pSRB->TargetStatus = 0;
- pSRB->MsgCnt = 0;
- if( pDCB->DevType != TYPE_TAPE )
- pSRB->RetryCnt = 1;
- else
- pSRB->RetryCnt = 0;
- pSRB->SRBStatus = 0;
- pSRB->SRBFlag = 0;
- pSRB->SRBState = 0;
- pSRB->TotalXferredLen = 0;
- pSRB->SGPhysAddr = 0;
- pSRB->SGToBeXferLen = 0;
- pSRB->ScsiPhase = 0;
- pSRB->EndMessage = 0;
- SendSRB( pcmd, pACB, pSRB );
-
- restore_flags(flags);
- return(0);
-}


+ heads = 64;
+ sectors = 32;

+ cylinders = size / (heads * sectors);
X
+ if ( (pACB->Gmode2 & GREATER_1G) && (cylinders > 1024) )
+ {


+ heads = 255;
+ sectors = 63;

+ cylinders = size / (heads * sectors);
+ }
X
-static void
-DoNextCmd( PACB pACB, PDCB pDCB )
-{
- Scsi_Cmnd *pcmd;
- PSRB pSRB;
- ULONG flags;
- PUCHAR ptr,ptr1;
- USHORT i;
-
-
- if( pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV) )
- return;
- save_flags(flags);
- cli();
-
- pcmd = Getcmd( pDCB );
- pSRB = GetSRB( pACB );
- if( !pSRB )
- {
- QLinkcmd( pcmd, pDCB );
- restore_flags(flags);
- return;
- }
-
- pSRB->pSRBDCB = pDCB;
- pSRB->pcmd = pcmd;


- ptr = (PUCHAR) pSRB->CmdBlock;

- ptr1 = (PUCHAR) pcmd->cmnd;
- pSRB->ScsiCmdLen = pcmd->cmd_len;
- for(i=0; i< pcmd->cmd_len; i++)
- {
- *ptr = *ptr1;
- ptr++;
- ptr1++;
- }
- if( pcmd->use_sg )
- {
- pSRB->SGcount = (UCHAR) pcmd->use_sg;
- pSRB->pSegmentList = (PSGL) pcmd->request_buffer;
- }
- else if( pcmd->request_buffer )
- {
- pSRB->SGcount = 1;
- pSRB->pSegmentList = (PSGL) &pSRB->Segmentx;
- pSRB->Segmentx.address = (PUCHAR) pcmd->request_buffer;
- pSRB->Segmentx.length = pcmd->request_bufflen;
+ geom[0] = heads;
+ geom[1] = sectors;
+ geom[2] = cylinders;
X }
- else
- pSRB->SGcount = 0;
X
- pSRB->SGIndex = 0;
- pSRB->AdaptStatus = 0;
- pSRB->TargetStatus = 0;
- pSRB->MsgCnt = 0;
- if( pDCB->DevType != TYPE_TAPE )
- pSRB->RetryCnt = 1;
- else
- pSRB->RetryCnt = 0;
- pSRB->SRBStatus = 0;
- pSRB->SRBFlag = 0;
- pSRB->SRBState = 0;
- pSRB->TotalXferredLen = 0;
- pSRB->SGPhysAddr = 0;
- pSRB->SGToBeXferLen = 0;
- pSRB->ScsiPhase = 0;
- pSRB->EndMessage = 0;
- SendSRB( pcmd, pACB, pSRB );
-
- restore_flags(flags);
- return;
+ return (0);
X }
-
-
-/***********************************************************************
- * Function:
- * DC390_bios_param
- *
- * Description:
- * Return the disk geometry for the given SCSI device.
- ***********************************************************************/
-#ifdef VERSION_ELF_1_2_13
-int DC390_bios_param(Disk *disk, int devno, int geom[])
X #else
-int DC390_bios_param(Disk *disk, kdev_t devno, int geom[])
-#endif
+int DC390_bios_param (Disk *disk, kdev_t devno, int geom[])


X {
- int heads, sectors, cylinders;

- PACB pACB;
-
- pACB = (PACB) disk->device->host->hostdata;


- heads = 64;
- sectors = 32;

- cylinders = disk->capacity / (heads * sectors);
-
- if ( (pACB->Gmode2 & GREATER_1G) && (cylinders > 1024) )
- {


- heads = 255;
- sectors = 63;

- cylinders = disk->capacity / (heads * sectors);
- }
+ return scsicam_bios_param (disk, devno, geom);
+};
+#endif
X
- geom[0] = heads;
- geom[1] = sectors;
- geom[2] = cylinders;
X
- return (0);
-}
+void dc390_dumpinfo (PACB pACB, PDCB pDCB, PSRB pSRB)
+{
+ USHORT pstat; PDEVDECL1;
+
+ if (pSRB)
+ {
+ printk ("DC390: SRB: Xferred %08lx, Remain %08lx, State %08lx, Phase %02x\n",
+ pSRB->TotalXferredLen, pSRB->SGToBeXferLen, pSRB->SRBState,
+ pSRB->ScsiPhase);
+ printk ("DC390: AdpaterStatus: %02x, SRB Status %02x\n", pSRB->AdaptStatus, pSRB->SRBStatus);
+ };
+ printk ("DC390: Status of last IRQ (DMA/SC/Int/IRQ): %08lx\n", dc390_laststatus);
+ printk ("DC390: Register dump: SCSI block:\n");
+ printk ("DC390: XferCnt Cmd Stat IntS IRQS FFIS Ctl1 Ctl2 Ctl3 Ctl4\n");
+ printk ("DC390: %06x %02x %02x %02x",
+ DC390_read8(CtcReg_Low) + (DC390_read8(CtcReg_Mid) << 8) + (DC390_read8(CtcReg_High) << 16),
+ DC390_read8(ScsiCmd), DC390_read8(Scsi_Status), DC390_read8(Intern_State));
+ printk (" %02x %02x %02x %02x %02x %02x\n",
+ DC390_read8(INT_Status), DC390_read8(Current_Fifo), DC390_read8(CtrlReg1),
+ DC390_read8(CtrlReg2), DC390_read8(CtrlReg3), DC390_read8(CtrlReg4));
+ DC390_write32 (DMA_ScsiBusCtrl, WRT_ERASE_DMA_STAT | EN_INT_ON_PCI_ABORT);
+ printk ("DC390: Register dump: DMA engine:\n");
+ printk ("DC390: Cmd STrCnt SBusA WrkBC WrkAC Stat SBusCtrl\n");
+ printk ("DC390: %02x %08x %08x %08x %08x %02x %08x\n",
+ DC390_read8(DMA_Cmd), DC390_read32(DMA_XferCnt), DC390_read32(DMA_XferAddr),
+ DC390_read32(DMA_Wk_ByteCntr), DC390_read32(DMA_Wk_AddrCntr),
+ DC390_read8(DMA_Status), DC390_read32(DMA_ScsiBusCtrl));
+ DC390_write32 (DMA_ScsiBusCtrl, EN_INT_ON_PCI_ABORT);
+ PDEVSET1; PCI_READ_CONFIG_WORD(PDEV, PCI_STATUS, &pstat);
+ printk ("DC390: Register dump: PCI Status: %04x\n", pstat);
+ printk ("DC390: In case of driver trouble read linux/drivers/scsi/README.tmscsim\n");
+};
X
X
X /***********************************************************************
@@ -714,37 +1280,32 @@
X * Inputs : cmd - command to abort
X *
X * Returns : 0 on success, -1 on failure.
+ *
+ * Status: Buggy !
X ***********************************************************************/
X
-int
-DC390_abort (Scsi_Cmnd *cmd)
+int DC390_abort (Scsi_Cmnd *cmd)
X {
- ULONG flags;
- PACB pACB;
- PDCB pDCB, pdcb;
+ PDCB pDCB;
X PSRB pSRB, psrb;
- USHORT count, i;
+ ULONG count, i;
X PSCSICMD pcmd, pcmd1;
X int status;
+ ULONG sbac;
+ DC390_AFLAGS
+ PACB pACB = (PACB) cmd->host->hostdata;
+
+ DC390_LOCK_ACB;
+
+ pDCB = dc390_findDCB (pACB, cmd);
+ /* abort() is too buggy at the moment. If it's called we are in trouble anyway.
+ * so let's dump some info into the syslog at least. (KG, 98/08/20) */
+ if (pDCB) pSRB = pDCB->pActiveSRB; else pSRB = 0;
+ printk ("DC390: Abort command (pid %li, DCB %p, SRB %p)\n",
+ cmd->pid, pDCB, pSRB);
+ dc390_dumpinfo (pACB, pDCB, pSRB);
X
-
-#ifdef DC390_DEBUG0
- printk("DC390 : Abort Cmd.");
-#endif


-
- save_flags(flags);
- cli();

-
- pACB = (PACB) cmd->host->hostdata;
- pDCB = pACB->pLinkDCB;
- pdcb = pDCB;
- while( (pDCB->UnitSCSIID != cmd->target) ||
- (pDCB->UnitSCSILUN != cmd->lun) )
- {
- pDCB = pDCB->pNextDCB;
- if( pDCB == pdcb )
- goto NOT_RUN;
- }
+ if( !pDCB ) goto NOT_RUN;
X
X if( pDCB->QIORBCnt )
X {
@@ -774,7 +1335,12 @@
X }
X }
X }
-
+
+ /* Added 98/07/02 KG */
+ pSRB = pDCB->pActiveSRB;
+ if (pSRB && pSRB->pcmd == cmd )
+ goto ON_GOING;
+
X pSRB = pDCB->pWaitingSRB;
X if( !pSRB )
X goto ON_GOING;
@@ -791,7 +1357,7 @@
X while( psrb->pNextSRB->pcmd != cmd )
X {
X psrb = psrb->pNextSRB;
- if( !(psrb->pNextSRB) )
+ if( !(psrb->pNextSRB) || psrb == pSRB)
X goto ON_GOING;
X }
X pSRB = psrb->pNextSRB;
@@ -808,6 +1374,8 @@
X
X ON_GOING:
X pSRB = pDCB->pGoingSRB;
+ pDCB->DCBFlag |= ABORT_DEV_;
+ /* Now for the hard part: The command is currently processed */
X for( count = pDCB->GoingSRBCnt, i=0; i<count; i++)
X {
X if( pSRB->pcmd != cmd )
@@ -817,6 +1385,8 @@
X if( (pACB->pActiveDCB == pDCB) && (pDCB->pActiveSRB == pSRB) )
X {
X status = SCSI_ABORT_BUSY;
+ printk ("DC390: Abort current command (pid %li, SRB %p)\n",
+ cmd->pid, pSRB);
X goto ABO_X;
X }
X else
@@ -832,20 +1402,51 @@
X
X ABO_X:
X cmd->result = DID_ABORT << 16;
+ printk(KERN_INFO "DC390: Aborted pid %li with status %i\n", cmd->pid, status);
+ if (cmd->pid == dc390_lastabortedpid) /* repeated failure ? */
+ {
+ /* Let's do something to help the bus getting clean again */
+ DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
+ DC390_write8 (ScsiCmd, DMA_COMMAND);
+ //DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
+ //DC390_write8 (ScsiCmd, RESET_ATN_CMD);
+ DC390_write8 (ScsiCmd, NOP_CMD);
+ //udelay (10000);
+ //DC390_read8 (INT_Status);
+ //DC390_write8 (ScsiCmd, EN_SEL_RESEL);
+ };
+ sbac = DC390_read32 (DMA_ScsiBusCtrl);
+ if (sbac & SCSI_BUSY)
+ { /* clear BSY, SEL and ATN */
+ printk (KERN_WARNING "DC390: Reset SCSI device: ");
+ //DC390_write32 (DMA_ScsiBusCtrl, (sbac | SCAM) & ~SCSI_LINES);
+ //udelay (250);
+ //sbac = DC390_read32 (DMA_ScsiBusCtrl);
+ //printk ("%08lx ", sbac);
+ //DC390_write32 (DMA_ScsiBusCtrl, sbac & ~(SCSI_LINES | SCAM));
+ //udelay (100);
+ //sbac = DC390_read32 (DMA_ScsiBusCtrl);
+ //printk ("%08lx ", sbac);
+ DC390_write8 (ScsiCmd, RST_DEVICE_CMD);
+ udelay (250);
+ DC390_write8 (ScsiCmd, NOP_CMD);
+ sbac = DC390_read32 (DMA_ScsiBusCtrl);
+ printk ("%08lx\n", sbac);
+ };
+ dc390_lastabortedpid = cmd->pid;
+ DC390_UNLOCK_ACB;
+ //do_DC390_Interrupt (pACB->IRQLevel, 0, 0);
X cmd->scsi_done(cmd);
- restore_flags(flags);
X return( status );
X }
X
X
-static void
-ResetDevParam( PACB pACB )
+static void dc390_ResetDevParam( PACB pACB )
X {
X PDCB pDCB, pdcb;
X
X pDCB = pACB->pLinkDCB;
- if( pDCB == NULL )
- return;
+ if (! pDCB) return;
X pdcb = pDCB;
X do
X {
@@ -853,24 +1454,22 @@
X pDCB->SyncPeriod = 0;
X pDCB->SyncOffset = 0;
X pDCB->CtrlR3 = FAST_CLK;
- pDCB->CtrlR4 &= NEGATE_REQACKDATA;
- pDCB->CtrlR4 |= EATER_25NS;
+ pDCB->CtrlR4 &= NEGATE_REQACKDATA | CTRL4_RESERVED | NEGATE_REQACK;
+ pDCB->CtrlR4 |= pACB->glitch_cfg;
X pDCB = pDCB->pNextDCB;
X }
X while( pdcb != pDCB );
X }
X
X
-static void
-RecoverSRB( PACB pACB )
+static void dc390_RecoverSRB( PACB pACB )
X {
X PDCB pDCB, pdcb;
X PSRB psrb, psrb2;
- USHORT cnt, i;
+ ULONG cnt, i;
X
X pDCB = pACB->pLinkDCB;
- if( pDCB == NULL )
- return;
+ if( !pDCB ) return;
X pdcb = pDCB;
X do
X {
@@ -880,7 +1479,7 @@
X {
X psrb2 = psrb;
X psrb = psrb->pNextSRB;
-/* RewaitSRB( pDCB, psrb ); */
+/* dc390_RewaitSRB( pDCB, psrb ); */
X if( pdcb->pWaitingSRB )
X {
X psrb2->pNextSRB = pdcb->pWaitingSRB;
@@ -897,8 +1496,7 @@
X pdcb->pGoingSRB = NULL;
X pdcb->TagMask = 0;
X pdcb = pdcb->pNextDCB;
- }
- while( pdcb != pDCB );
+ } while( pdcb != pDCB );
X }
X
X
@@ -912,83 +1510,82 @@
X * Returns : 0 on success.
X ***********************************************************************/
X
-#ifdef VERSION_2_0_0
X int DC390_reset(Scsi_Cmnd *cmd, unsigned int resetFlags)
-#else
-int DC390_reset (Scsi_Cmnd *cmd)
-#endif
X {


- USHORT ioport;
- unsigned long flags;

- PACB pACB;
- UCHAR bval;
- USHORT i;
+ UCHAR bval;
+ ULONG i;
+ DC390_AFLAGS
+ PACB pACB = (PACB) cmd->host->hostdata;
X
+ printk(KERN_INFO "DC390: RESET ... ");
X
-#ifdef DC390_DEBUG1
- printk("DC390: RESET,");
-#endif
-
- pACB = (PACB ) cmd->host->hostdata;


- ioport = pACB->IOPortBase;

- save_flags(flags);
- cli();
- bval = inb(ioport+CtrlReg1);
+ DC390_LOCK_ACB;


+ bval = DC390_read8 (CtrlReg1);
X bval |= DIS_INT_ON_SCSI_RST;
- outb(bval,ioport+CtrlReg1); /* disable interrupt */
- DC390_ResetSCSIBus( pACB );

- for( i=0; i<500; i++ )


+ DC390_write8 (CtrlReg1, bval); /* disable interrupt */
+

+ dc390_ResetSCSIBus( pACB );
+ /* Unlock ? */
+ for( i=0; i<600; i++ )
X udelay(1000);
- bval = inb(ioport+CtrlReg1);
- bval &= ~DIS_INT_ON_SCSI_RST;
- outb(bval,ioport+CtrlReg1); /* re-enable interrupt */
X
- bval = DMA_IDLE_CMD;
- outb(bval,ioport+DMA_Cmd);
- bval = CLEAR_FIFO_CMD;
- outb(bval,ioport+ScsiCmd);
+ DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
+ DC390_read8 (INT_Status); /* Reset Pending INT */
X
- ResetDevParam( pACB );
- DoingSRB_Done( pACB );
+ dc390_ResetDevParam( pACB );
+ dc390_DoingSRB_Done( pACB );
+ /* dc390_RecoverSRB (pACB); */
X pACB->pActiveDCB = NULL;
X
X pACB->ACBFlag = 0;
- DoWaitingSRB( pACB );


+ bval = DC390_read8 (CtrlReg1);

+ bval &= ~DIS_INT_ON_SCSI_RST;
+ DC390_write8 (CtrlReg1, bval); /* re-enable interrupt */
X
- restore_flags(flags);
-#ifdef DC390_DEBUG1
- printk("DC390: RESET1,");
-#endif
+ dc390_DoWaitingSRB( pACB );
+
+ DC390_UNLOCK_ACB;
+ printk("done\n");
X return( SCSI_RESET_SUCCESS );
X }
X
-
X #include "scsiiom.c"
X
X
X /***********************************************************************
- * Function : static void DC390_initDCB
+ * Function : static void dc390_initDCB()
X *
X * Purpose : initialize the internal structures for a given DCB
X *
X * Inputs : cmd - pointer to this scsi cmd request block structure
- *
X ***********************************************************************/
-void DC390_initDCB( PACB pACB, PDCB pDCB, PSCSICMD cmd )
+
+void dc390_initDCB( PACB pACB, PDCB *ppDCB, PSCSICMD cmd )
X {
X PEEprom prom;
- UCHAR bval;
- USHORT index;
+ UCHAR index;
+ PDCB pDCB;
X
- if( pACB->DeviceCnt == 0 )
+ pDCB = kmalloc (sizeof(DC390_DCB), GFP_ATOMIC);
+ DCBDEBUG(printk (KERN_INFO "DC390: alloc mem for DCB (ID %i, LUN %i): 0x%08x\n", \
+ cmd->target, cmd->lun, (int)pDCB);)
+
+ *ppDCB = pDCB;
+ if (!pDCB) return;
+ if( pACB->DCBCnt == 0 )
X {
X pACB->pLinkDCB = pDCB;
X pACB->pDCBRunRobin = pDCB;
- pDCB->pNextDCB = pDCB;
- pPrevDCB = pDCB;
X }
X else
- pPrevDCB->pNextDCB = pDCB;
+ {
+ pACB->pLastDCB->pNextDCB = pDCB;
+ };
+
+ pACB->DCBCnt++;
+
+ pACB->pLastDCB = pDCB;
+ pDCB->pNextDCB = pACB->pLinkDCB;
X
X pDCB->pDCBACB = pACB;
X pDCB->QIORBCnt = 0;
@@ -1000,128 +1597,144 @@
X pDCB->pActiveSRB = NULL;
X pDCB->TagMask = 0;
X pDCB->MaxCommand = 1;
- pDCB->AdaptIndex = pACB->AdapterIndex;
X index = pACB->AdapterIndex;
X pDCB->DCBFlag = 0;
X
- prom = (PEEprom) &eepromBuf[index][cmd->target << 2];
+ prom = (PEEprom) &dc390_eepromBuf[index][cmd->target << 2];
X pDCB->DevMode = prom->EE_MODE1;
- pDCB->AdpMode = eepromBuf[index][EE_MODE2];
-
- if( pDCB->DevMode & EN_DISCONNECT_ )
- bval = 0xC0;
- else
- bval = 0x80;
- bval |= cmd->lun;
- pDCB->IdentifyMsg = bval;
X
X pDCB->SyncMode = 0;
- if( pDCB->DevMode & SYNC_NEGO_ )
- {
- if( !(cmd->lun) || CurrSyncOffset )
- pDCB->SyncMode = SYNC_ENABLE;
- }
+ dc390_updateDCB(pACB, pDCB);
X
X pDCB->SyncPeriod = 0;
X pDCB->SyncOffset = 0;
- pDCB->NegoPeriod = (clock_period1[prom->EE_SPEED] * 25) >> 2;
-
- pDCB->CtrlR1 = pACB->AdaptSCSIID;
- if( pDCB->DevMode & PARITY_CHK_ )
- pDCB->CtrlR1 |= PARITY_ERR_REPO;
+ pDCB->NegoPeriod = (dc390_clock_period1[prom->EE_SPEED] * 25) >> 2;
X
X pDCB->CtrlR3 = FAST_CLK;
X
- pDCB->CtrlR4 = EATER_25NS;
- if( pDCB->AdpMode & ACTIVE_NEGATION)
- pDCB->CtrlR4 |= NEGATE_REQACKDATA;
+ pDCB->CtrlR4 = pACB->glitch_cfg | CTRL4_RESERVED;
+ if( dc390_eepromBuf[index][EE_MODE2] & ACTIVE_NEGATION)
+ pDCB->CtrlR4 |= NEGATE_REQACKDATA | NEGATE_REQACK;
X }
X
+/***********************************************************************
+ * Function : static void dc390_updateDCB()
+ *
+ * Purpose : Set the configuration dependent DCB parameters
+ ***********************************************************************/
+
+void dc390_updateDCB (PACB pACB, PDCB pDCB)
+{
+ pDCB->IdentifyMsg = IDENTIFY (pDCB->DevMode & EN_DISCONNECT_, pDCB->UnitSCSILUN);
+
+ if (pDCB->DevMode & TAG_QUEUEING_) pDCB->SyncMode &= EN_TAG_QUEUEING | SYNC_NEGO_DONE | EN_ATN_STOP;
+ else pDCB->SyncMode &= SYNC_NEGO_DONE | EN_ATN_STOP;
+
+ if( pDCB->DevMode & SYNC_NEGO_ && (!(pDCB->UnitSCSILUN) || dc390_CurrSyncOffset) )
+ pDCB->SyncMode |= SYNC_ENABLE;
+ else
+ {
+ pDCB->SyncMode &= ~(SYNC_NEGO_DONE | SYNC_ENABLE);
+ pDCB->SyncOffset &= ~0x0f;
+ };
+
+ if (! (pDCB->DevMode & EN_DISCONNECT_)) pDCB->SyncMode &= ~EN_ATN_STOP;
+
+ pDCB->CtrlR1 = pACB->pScsiHost->this_id;
+ if( pDCB->DevMode & PARITY_CHK_ )
+ pDCB->CtrlR1 |= PARITY_ERR_REPO;
+};
+
+
+/***********************************************************************
+ * Function : static void dc390_updateDCBs ()
+ *
+ * Purpose : Set the configuration dependent DCB params for all DCBs
+ ***********************************************************************/
+
+static void dc390_updateDCBs (PACB pACB)
+{
+ int i;


+ PDCB pDCB = pACB->pLinkDCB;

+ for (i = 0; i < pACB->DeviceCnt; i++)


+ {
+ dc390_updateDCB (pACB, pDCB);

+ pDCB = pDCB->pNextDCB;
+ };
+};
+
X
X /***********************************************************************
- * Function : static void DC390_initSRB
+ * Function : static void dc390_initSRB()
X *
X * Purpose : initialize the internal structures for a given SRB
X *
X * Inputs : psrb - pointer to this scsi request block structure
- *
X ***********************************************************************/
-void DC390_initSRB( PSRB psrb )
+
+static void __inline__ dc390_initSRB( PSRB psrb )
X {
-#ifndef VERSION_ELF_1_2_13
-#ifdef DC390_DEBUG0
- printk("DC390 init: %08lx %08lx,",(ULONG)psrb,(ULONG)virt_to_bus(psrb));
-#endif
- psrb->PhysSRB = virt_to_bus( psrb );
-#else
- psrb->PhysSRB = (ULONG) psrb;
-#endif
+ /* psrb->PhysSRB = virt_to_phys( psrb ); */
X }
X
X
-void DC390_linkSRB( PACB pACB )
+void dc390_linkSRB( PACB pACB )
X {
- USHORT count, i;
- PSRB psrb;
+ ULONG count, i;
X
X count = pACB->SRBCount;
-
X for( i=0; i< count; i++)
X {
X if( i != count - 1)
X pACB->SRB_array[i].pNextSRB = &pACB->SRB_array[i+1];
X else
X pACB->SRB_array[i].pNextSRB = NULL;
- psrb = (PSRB) &pACB->SRB_array[i];
- DC390_initSRB( psrb );
+ dc390_initSRB( &pACB->SRB_array[i] );
X }
X }
X
X
X /***********************************************************************
- * Function : static void DC390_initACB
+ * Function : static void dc390_initACB ()
X *
X * Purpose : initialize the internal structures for a given SCSI host
X *
X * Inputs : psh - pointer to this host adapter's structure
- *
+ * io_port, Irq, index: Resources and adapter index
X ***********************************************************************/
-void DC390_initACB( PSH psh, ULONG io_port, UCHAR Irq, USHORT index )
+
+void __init dc390_initACB (PSH psh, ULONG io_port, UCHAR Irq, UCHAR index)
X {
X PACB pACB;
- USHORT i;
+ UCHAR i;
+ DC390_AFLAGS
X
X psh->can_queue = MAX_CMD_QUEUE;
X psh->cmd_per_lun = MAX_CMD_PER_LUN;
- psh->this_id = (int) eepromBuf[index][EE_ADAPT_SCSI_ID];
+ psh->this_id = (int) dc390_eepromBuf[index][EE_ADAPT_SCSI_ID];
X psh->io_port = io_port;
X psh->n_io_port = 0x80;
X psh->irq = Irq;
X
X pACB = (PACB) psh->hostdata;
+ DC390_LOCKA_INIT;
+ DC390_LOCK_ACB;
+
+ pACB->pScsiHost = psh;
+ pACB->IOPortBase = (USHORT) io_port;
+ pACB->IRQLevel = Irq;
X
-#ifndef VERSION_ELF_1_2_13
+ DEBUG0(printk (KERN_INFO "DC390: Adapter index %i, ID %i, IO 0x%08x, IRQ 0x%02x\n", \
+ index, psh->this_id, (int)io_port, Irq);)
+
X psh->max_id = 8;
-#ifdef CONFIG_SCSI_MULTI_LUN
- if( eepromBuf[index][EE_MODE2] & LUN_CHECK )
- psh->max_lun = 8;
- else
-#endif
- psh->max_lun = 1;
-#endif
X
- pACB->max_id = 7;
- if( pACB->max_id == eepromBuf[index][EE_ADAPT_SCSI_ID] )
- pACB->max_id--;
-#ifdef CONFIG_SCSI_MULTI_LUN
- if( eepromBuf[index][EE_MODE2] & LUN_CHECK )
- pACB->max_lun = 7;
- else
-#endif
- pACB->max_lun = 0;
+ if( psh->max_id - 1 == dc390_eepromBuf[index][EE_ADAPT_SCSI_ID] )
+ psh->max_id--;
+ psh->max_lun = 1;
+ if( dc390_eepromBuf[index][EE_MODE2] & LUN_CHECK )
+ psh->max_lun = 8;
X
- pACB->pScsiHost = psh;
- pACB->IOPortBase = (USHORT) io_port;
X pACB->pLinkDCB = NULL;
X pACB->pDCBRunRobin = NULL;
X pACB->pActiveDCB = NULL;
@@ -1129,475 +1742,204 @@
X pACB->SRBCount = MAX_SRB_CNT;
X pACB->AdapterIndex = index;
X pACB->status = 0;
- pACB->AdaptSCSIID = eepromBuf[index][EE_ADAPT_SCSI_ID];
- pACB->HostID_Bit = (1 << pACB->AdaptSCSIID);
- pACB->AdaptSCSILUN = 0;
+ psh->this_id = dc390_eepromBuf[index][EE_ADAPT_SCSI_ID];
X pACB->DeviceCnt = 0;
- pACB->IRQLevel = Irq;
- pACB->TagMaxNum = eepromBuf[index][EE_TAG_CMD_NUM] << 2;
+ pACB->DCBCnt = 0;
+ pACB->TagMaxNum = 2 << dc390_eepromBuf[index][EE_TAG_CMD_NUM];
X pACB->ACBFlag = 0;
X pACB->scan_devices = 1;
- pACB->Gmode2 = eepromBuf[index][EE_MODE2];
- if( eepromBuf[index][EE_MODE2] & LUN_CHECK )
- pACB->LUNchk = 1;
- pACB->pDCB_free = &pACB->DCB_array[0];
- DC390_linkSRB( pACB );
+ pACB->MsgLen = 0;
+ pACB->Ignore_IRQ = 0;
+ pACB->Gmode2 = dc390_eepromBuf[index][EE_MODE2];
+ dc390_linkSRB( pACB );
X pACB->pTmpSRB = &pACB->TmpSRB;
- DC390_initSRB( pACB->pTmpSRB );
+ dc390_initSRB( pACB->pTmpSRB );
X for(i=0; i<MAX_SCSI_ID; i++)
X pACB->DCBmap[i] = 0;
+ pACB->sel_timeout = SEL_TIMEOUT;
+ pACB->glitch_cfg = EATER_25NS;
+ pACB->Cmds = pACB->CmdInQ = pACB->CmdOutOfSRB = pACB->SelLost = 0;
X }
X
X
X /***********************************************************************
- * Function : static int DC390_initAdapter
+ * Function : static int dc390_initAdapter ()
X *
X * Purpose : initialize the SCSI chip ctrl registers
X *
X * Inputs : psh - pointer to this host adapter's structure
+ * io_port, Irq, index: Resources
X *
+ * Outputs: 0 on success, -1 on error
X ***********************************************************************/
-int DC390_initAdapter( PSH psh, ULONG io_port, UCHAR Irq, USHORT index )
-{
- USHORT ioport;
- UCHAR bval;
- PACB pACB, pacb;
- USHORT used_irq = 0;
X
- pacb = pACB_start;
- if( pacb != NULL )
- {
- for ( ; (pacb != (PACB) -1) ; )
- {
- if( pacb->IRQLevel == Irq )
- {
- used_irq = 1;


- break;
- }
- else

- pacb = pacb->pNextACB;
- }
- }
+int __init dc390_initAdapter (PSH psh, ULONG io_port, UCHAR Irq, UCHAR index)
+{
+ PACB pACB, pACB2;
+ UCHAR used_irq = 0, dstate;
+ int i;
+
+ pACB = (PACB) psh->hostdata;
+
+ for ( pACB2 = dc390_pACB_start; pACB2 ; )
+ {
+ if( pACB2->IRQLevel == Irq )
+ {
+ used_irq = 1;


+ break;
+ }
+ else

+ pACB2 = pACB2->pNextACB;
+ }
X
- if( !used_irq )
- {
-#ifdef VERSION_ELF_1_2_13
- if( request_irq(Irq, DC390_Interrupt, SA_INTERRUPT, "tmscsim"))
-#else
- if( request_irq(Irq, DC390_Interrupt, SA_INTERRUPT | SA_SHIRQ, "tmscsim", NULL))
-#endif
+ if (check_region (io_port, psh->n_io_port))
X {
- printk("DC390: register IRQ error!\n");
+ printk(KERN_ERR "DC390: register IO ports error!\n");
X return( -1 );
X }
- }
-
- request_region(io_port,psh->n_io_port,"tmscsim");
-
- ioport = (USHORT) io_port;
-
- pACB = (PACB) psh->hostdata;
- bval = SEL_TIMEOUT; /* 250ms selection timeout */
- outb(bval,ioport+Scsi_TimeOut);
-
- bval = CLK_FREQ_40MHZ; /* Conversion factor = 0 , 40MHz clock */
- outb(bval,ioport+Clk_Factor);
-
- bval = NOP_CMD; /* NOP cmd - clear command register */
- outb(bval,ioport+ScsiCmd);
-
- bval = EN_FEATURE+EN_SCSI2_CMD; /* Enable Feature and SCSI-2 */
- outb(bval,ioport+CtrlReg2);
-
- bval = FAST_CLK; /* fast clock */
- outb(bval,ioport+CtrlReg3);
-
- bval = EATER_25NS;
- if( eepromBuf[index][EE_MODE2] & ACTIVE_NEGATION )
- bval |= NEGATE_REQACKDATA;
- outb(bval,ioport+CtrlReg4);
-
- bval = DIS_INT_ON_SCSI_RST; /* Disable SCSI bus reset interrupt */
- outb(bval,ioport+CtrlReg1);
-
- return(0);
-}
-
-
-void
-DC390_EnableCfg( USHORT mechnum, UCHAR regval )
-{
- ULONG wlval;
-
- if(mechnum == 2)
- {
- outb(mech2bus, PCI_CFG2_FORWARD_REG);
- outb(mech2CfgSPenR, PCI_CFG2_ENABLE_REG);
- }
- else
- {
- regval &= 0xFC;
- wlval = mech1addr;
- wlval |= (((ULONG)regval) & 0xff);
- outl(wlval, PCI_CFG1_ADDRESS_REG);
- }
-}
-
-
-void
-DC390_DisableCfg( USHORT mechnum )
-{
-
- if(mechnum == 2)
- outb(0, PCI_CFG2_ENABLE_REG);
- else
- outl(0, PCI_CFG1_ADDRESS_REG);
-}
-
-
-UCHAR
-DC390_inByte( USHORT mechnum, UCHAR regval )
-{
- UCHAR bval;
- ULONG wval;
- ULONG flags;


-
- save_flags(flags);
- cli();

- DC390_EnableCfg( mechnum, regval );
- if(mechnum == 2)
- {
- wval = mech2Agent;
- wval <<= 8;
- wval |= ((USHORT) regval) & 0xff;
- bval = inb(wval);
- }
- else
- {
- regval &= 3;
- bval = inb(PCI_CFG1_DATA_REG | regval);
- }
- DC390_DisableCfg(mechnum);
- restore_flags(flags);
- return(bval);
-}
-
-
-USHORT
-DC390_inWord( USHORT mechnum, UCHAR regval )
-{
- USHORT wval;
- ULONG flags;


-
- save_flags(flags);
- cli();

- DC390_EnableCfg(mechnum,regval);
- if(mechnum == 2)
- {
- wval = mech2Agent;
- wval <<= 8;
- wval |= regval;
- wval = inw(wval);
- }
- else
- {
- regval &= 3;
- wval = inw(PCI_CFG1_DATA_REG | regval);
- }
- DC390_DisableCfg(mechnum);
- restore_flags(flags);
- return(wval);
-}
-
-
-ULONG
-DC390_inDword(USHORT mechnum, UCHAR regval )
-{
- ULONG wlval;
- ULONG flags;
- USHORT wval;


-
- save_flags(flags);
- cli();

- DC390_EnableCfg(mechnum,regval);
- if(mechnum == 2)
- {
- wval = mech2Agent;
- wval <<= 8;
- wval |= regval;
- wlval = inl(wval);
- }
- else
- {
- wlval = inl(PCI_CFG1_DATA_REG);
- }
- DC390_DisableCfg(mechnum);
- restore_flags(flags);
- return(wlval);
-}
-
-
-void
-DC390_OutB(USHORT mechnum, UCHAR regval, UCHAR bval )
-{
-
- USHORT wval;
- ULONG flags;


-
- save_flags(flags);
- cli();

- DC390_EnableCfg(mechnum,regval);
- if(mechnum == 2)
- {
- wval = mech2Agent;
- wval <<= 8;
- wval |= regval;
- outb(bval, wval);
- }
- else
- {
- regval &= 3;
- outb(bval, PCI_CFG1_DATA_REG | regval);
- }
- DC390_DisableCfg(mechnum);
- restore_flags(flags);
-}
-
-
-void
-DC390_EnDisableCE( UCHAR mode, USHORT mechnum, PUCHAR regval )
-{
-
- UCHAR bval;
-
- bval = 0;
- if(mode == ENABLE_CE)
- *regval = 0xc0;
- else
- *regval = 0x80;
- DC390_OutB(mechnum,*regval,bval);
- if(mode == DISABLE_CE)
- DC390_OutB(mechnum,*regval,bval);
- udelay(160);
-}
-
-
-void
-DC390_EEpromOutDI( USHORT mechnum, PUCHAR regval, USHORT Carry )
-{
- UCHAR bval;
-
- bval = 0;
- if(Carry)
- {
- bval = 0x40;
- *regval = 0x80;
- DC390_OutB(mechnum,*regval,bval);
- }
- udelay(160);
- bval |= 0x80;
- DC390_OutB(mechnum,*regval,bval);
- udelay(160);
- bval = 0;
- DC390_OutB(mechnum,*regval,bval);
- udelay(160);
-}
-
-
-UCHAR
-DC390_EEpromInDO( USHORT mechnum )
-{
- UCHAR bval,regval;
-
- regval = 0x80;
- bval = 0x80;
- DC390_OutB(mechnum,regval,bval);
- udelay(160);
- bval = 0x40;
- DC390_OutB(mechnum,regval,bval);
- udelay(160);
- regval = 0x0;
- bval = DC390_inByte(mechnum,regval);
- if(bval == 0x22)
- return(1);
X else
- return(0);
-}
-
-
-USHORT
-EEpromGetData1( USHORT mechnum )
-{
- UCHAR i;
- UCHAR carryFlag;
- USHORT wval;
-
- wval = 0;
- for(i=0; i<16; i++)
- {
- wval <<= 1;
- carryFlag = DC390_EEpromInDO(mechnum);
- wval |= carryFlag;
- }
- return(wval);
-}
-
-
-void
-DC390_Prepare( USHORT mechnum, PUCHAR regval, UCHAR EEpromCmd )
-{
- UCHAR i,j;
- USHORT carryFlag;
-
- carryFlag = 1;
- j = 0x80;
- for(i=0; i<9; i++)
- {
- DC390_EEpromOutDI(mechnum,regval,carryFlag);
- carryFlag = (EEpromCmd & j) ? 1 : 0;
- j >>= 1;
- }
-}
-
+ request_region (io_port, psh->n_io_port, "tmscsim");
X
-void
-DC390_ReadEEprom( USHORT mechnum, USHORT index )
-{
- UCHAR regval,cmd;
- PUSHORT ptr;
- USHORT i;
+ DC390_read8_ (INT_Status, io_port); /* Reset Pending INT */
X
- ptr = (PUSHORT) &eepromBuf[index][0];
- cmd = EEPROM_READ;
- for(i=0; i<0x40; i++)
+ if( !used_irq )
X {
- DC390_EnDisableCE(ENABLE_CE, mechnum, &regval);
- DC390_Prepare(mechnum, &regval, cmd);
- *ptr = EEpromGetData1(mechnum);
- ptr++;
- cmd++;
- DC390_EnDisableCE(DISABLE_CE,mechnum,&regval);
+ if( (i = request_irq(Irq, do_DC390_Interrupt, DC390_IRQ, "tmscsim", NULL) ))
+ {
+ printk(KERN_ERR "DC390: register IRQ error!\n");


+ return( -1 );
+ }

X }
-}
X
-
-USHORT
-DC390_CheckEEpromCheckSum( USHORT MechNum, USHORT index )
-{
- USHORT wval, rc, *ptr;
- UCHAR i;
-
- DC390_ReadEEprom( MechNum, index );
- wval = 0;
- ptr = (PUSHORT) &eepromBuf[index][0];
- for(i=0; i<128 ;i+=2, ptr++)
- wval += *ptr;
- if( wval == 0x1234 )
- rc = 0;
+ if( !dc390_pACB_start )
+ {
+ pACB2 = NULL;
+ dc390_pACB_start = pACB;
+ dc390_pACB_current = pACB;
+ pACB->pNextACB = NULL;
+ }
X else
- rc = -1;
- return( rc );
-}
-
-
-USHORT
-DC390_ToMech( USHORT Mechnum, USHORT BusDevFunNum )
-{
- USHORT devnum;
-
- devnum = BusDevFunNum;
+ {
+ pACB2 = dc390_pACB_current;
+ dc390_pACB_current->pNextACB = pACB;
+ dc390_pACB_current = pACB;
+ pACB->pNextACB = NULL;
+ };
+
+ DC390_write8 (CtrlReg1, DIS_INT_ON_SCSI_RST | psh->this_id); /* Disable SCSI bus reset interrupt */
+


+ if (pACB->Gmode2 & RST_SCSI_BUS)

+ {
+ dc390_ResetSCSIBus( pACB );
+ /* Unlock before ? */
+ for( i=0; i<600; i++ )
+ udelay(1000);
+ };
+ pACB->ACBFlag = 0;
+ DC390_read8 (INT_Status); /* Reset Pending INT */
+
+ DC390_write8 (Scsi_TimeOut, SEL_TIMEOUT); /* 250ms selection timeout */
+ DC390_write8 (Clk_Factor, CLK_FREQ_40MHZ); /* Conversion factor = 0 , 40MHz clock */
+ DC390_write8 (ScsiCmd, NOP_CMD); /* NOP cmd - clear command register */
+ DC390_write8 (CtrlReg2, EN_FEATURE+EN_SCSI2_CMD); /* Enable Feature and SCSI-2 */
+ DC390_write8 (CtrlReg3, FAST_CLK); /* fast clock */
+ DC390_write8 (CtrlReg4, pACB->glitch_cfg | /* glitch eater */
+ (dc390_eepromBuf[index][EE_MODE2] & ACTIVE_NEGATION) ? NEGATE_REQACKDATA : 0); /* Negation */
+ DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
+ DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
+ DC390_write32 (DMA_ScsiBusCtrl, EN_INT_ON_PCI_ABORT);
+ dstate = DC390_read8 (DMA_Status);
+ DC390_write8 (DMA_Status, dstate); /* clear */
X
- if(Mechnum == 2)
- {
- if(devnum & 0x80)
- return(-1);
- mech2bus = (UCHAR)((devnum & 0xff00) >> 8); /* Bus num */
- mech2Agent = ((UCHAR)(devnum & 0xff)) >> 3; /* Dev num */
- mech2Agent |= 0xc0;
- mech2CfgSPenR = ((UCHAR)(devnum & 0xff)) & 0x07; /* Fun num */
- mech2CfgSPenR = (mech2CfgSPenR << 1) | 0x20;
- }
- else /* use mech #1 method */
- {
- mech1addr = 0x80000000 | ((ULONG)devnum << 8);
- }
X return(0);
X }
X
+
X /***********************************************************************
- * Function : static int DC390_init (struct Scsi_Host *host)
+ * Function : static int DC390_init (struct Scsi_Host *host, ...)
X *
X * Purpose : initialize the internal structures for a given SCSI host
X *
- * Inputs : host - pointer to this host adapter's structure/
+ * Inputs : host - pointer to this host adapter's structure
+ * io_port - IO ports mapped to this adapter
+ * Irq - IRQ assigned to this adpater
+ * PDEVDECL - PCI access handle
+ * index - Adapter index
X *
- * Preconditions : when this function is called, the chip_type
- * field of the pACB structure MUST have been set.
+ * Outputs: 0 on success, -1 on error
+ *
+ * Note: written in capitals, because the locking is only done here,
+ * not in DC390_detect, called from outside
X ***********************************************************************/
X
-static int
-DC390_init (PSHT psht, ULONG io_port, UCHAR Irq, USHORT index, USHORT MechNum)
+static int __init DC390_init (PSHT psht, ULONG io_port, UCHAR Irq, PDEVDECL, UCHAR index)
X {
X PSH psh;
X PACB pACB;
-
- if( !DC390_CheckEEpromCheckSum( MechNum, index) )
+ DC390_AFLAGS
+
+ if (dc390_CheckEEpromCheckSum (PDEV, index))
X {
- psh = scsi_register( psht, sizeof(DC390_ACB) );
- if( !psh )
- return( -1 );
- if( !pSH_start )
- {
- pSH_start = psh;
- pSH_current = psh;
- }
- else
- {
- pSH_current->next = psh;
- pSH_current = psh;
- }
+#ifdef CONFIG_SCSI_DC390T_NOGENSUPP
+ printk (KERN_ERR "DC390_init: No EEPROM found!\n");
+ return( -1 );
+#else
+ int period;
+ printk (KERN_INFO "DC390_init: No EEPROM found!\n");
+ printk (KERN_INFO "DC390_init: Trying default EEPROM settings:\n");
+ dc390_checkparams ();
+ period = dc390_clock_period1[tmscsim[1]];
+ printk (KERN_INFO "DC390: Used defaults: AdaptID=%i, SpeedIdx=%i (%i.%i MHz),"
+ " DevMode=0x%02x, AdaptMode=0x%02x, TaggedCmnds=%i (%i)\n", tmscsim[0], tmscsim[1],
+ 40 / period, ((40%period)*10 + period/2) / period,
+ (UCHAR)tmscsim[2], (UCHAR)tmscsim[3], tmscsim[4], 2 << (tmscsim[4]));
+ dc390_EEpromDefaults (index);
+#endif
+ };
+
+ psh = scsi_register( psht, sizeof(DC390_ACB) );
+ if( !psh ) return( -1 );
+
+ pACB = (PACB) psh->hostdata;
+ DC390_LOCKA_INIT;
+ DC390_LOCK_ACB;
X
-#ifdef DC390_DEBUG0
- printk("DC390: pSH = %8x,", (UINT) psh);
- printk("DC390: Index %02i,", index);
+#if 0
+ if( !dc390_pSH_start )
+ {
+ dc390_pSH_start = psh;
+ dc390_pSH_current = psh;
+ }
+ else
+ {
+ dc390_pSH_current->next = psh;
+ dc390_pSH_current = psh;
+ }
X #endif
X
- DC390_initACB( psh, io_port, Irq, index );
- if( !DC390_initAdapter( psh, io_port, Irq, index ) )
- {
- pACB = (PACB) psh->hostdata;
- if( !pACB_start )
- {
- pACB_start = pACB;
- pACB_current = pACB;
- pACB->pNextACB = (PACB) -1;
- }
- else
- {
- pACB_current->pNextACB = pACB;
- pACB_current = pACB;
- pACB->pNextACB = (PACB) -1;
- }
+ DEBUG0(printk(KERN_INFO "DC390: pSH = %8x,", (UINT) psh);)
+ DEBUG0(printk(" Index %02i,", index);)
X
-#ifdef DC390_DEBUG0
- printk("DC390: pACB = %8x, pDCB_array = %8x, pSRB_array = %8x\n",
- (UINT) pACB, (UINT) pACB->DCB_array, (UINT) pACB->SRB_array);
- printk("DC390: ACB size= %4x, DCB size= %4x, SRB size= %4x\n",
- sizeof(DC390_ACB), sizeof(DC390_DCB), sizeof(DC390_SRB) );
-#endif
+ dc390_initACB( psh, io_port, Irq, index );
+ pACB = (PACB) psh->hostdata;
+
+ PDEVSET;
X
- }
- else
- {
- pSH_start = NULL;
- scsi_unregister( psh );
- return( -1 );
- }
- return( 0 );
+ if( !dc390_initAdapter( psh, io_port, Irq, index ) )
+ {
+ DEBUG0(printk("\nDC390: pACB = %8x, pDCBmap = %8x, pSRB_array = %8x\n",\
+ (UINT) pACB, (UINT) pACB->DCBmap, (UINT) pACB->SRB_array);)
+ DEBUG0(printk("DC390: ACB size= %4x, DCB size= %4x, SRB size= %4x\n",\
+ sizeof(DC390_ACB), sizeof(DC390_DCB), sizeof(DC390_SRB) );)
+
+ DC390_UNLOCK_ACB;
+ return (0);
X }
X else
X {
- printk("DC390_init: EEPROM reading error!\n");
+ //dc390_pSH_start = NULL;
+ scsi_unregister( psh );
+ DC390_UNLOCK_ACB;
X return( -1 );
X }
X }
@@ -1616,136 +1958,443 @@
X *
X ***********************************************************************/
X
-int
-DC390_detect(Scsi_Host_Template *psht)
-{
-#ifdef FOR_PCI_OK
- UCHAR pci_bus, pci_device_fn;
- int error = 0;
- USHORT chipType = 0;
- USHORT i;
-#endif
+#ifndef NEW_PCI
+/* Acc. to PCI 2.1 spec it's up to the driver to enable Bus mastering:
+ * We use pci_set_master () for 2.1.x and this func for 2.0.x: */
+static void __init dc390_set_master (PDEVDECL)
+{
+ USHORT cmd;
+ UCHAR lat;
+
+ PCI_READ_CONFIG_WORD (PDEV, PCI_COMMAND, &cmd);
+
+ if (! (cmd & PCI_COMMAND_MASTER)) {
+ printk("PCI: Enabling bus mastering for device %02x:%02x\n",
+ PCI_BUS_DEV);
+ cmd |= PCI_COMMAND_MASTER;
+ PCI_WRITE_CONFIG_WORD(PDEV, PCI_COMMAND, cmd);
+ }
+ PCI_READ_CONFIG_BYTE (PDEV, PCI_LATENCY_TIMER, &lat);
+ if (lat < 16 /* || lat == 255 */) {
+ printk("PCI: Setting latency timer of device %02x:%02x from %i to 64\n",
+ PCI_BUS_DEV, lat);
+ PCI_WRITE_CONFIG_BYTE(PDEV, PCI_LATENCY_TIMER, 64);
+ }
+
+};
+#endif /* ! NEW_PCI */
+
+static void __init dc390_set_pci_cfg (PDEVDECL)
+{
+ USHORT cmd;
+ PCI_READ_CONFIG_WORD (PDEV, PCI_COMMAND, &cmd);
+ cmd |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY | PCI_COMMAND_IO;
+ PCI_WRITE_CONFIG_WORD (PDEV, PCI_COMMAND, cmd);
+ PCI_WRITE_CONFIG_WORD (PDEV, PCI_STATUS, (PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY));
+};
+
X
+int __init DC390_detect (Scsi_Host_Template *psht)
+{
+ PDEVDECL0;
X UCHAR irq;
- UCHAR istatus;
-#ifndef VERSION_ELF_1_2_13
X UINT io_port;
-#else
- ULONG io_port;
-#endif
- USHORT adaptCnt = 0; /* Number of boards detected */
- USHORT pci_index = 0; /* Device index to PCI BIOS calls */
- USHORT MechNum, BusDevFunNum;
- ULONG wlval;
-
-#ifndef VERSION_ELF_1_2_13
- psht->proc_dir = &proc_scsi_tmscsim;
-#endif
+ DC390_IFLAGS DC390_DFLAGS
X
- InitialTime = 1;
- pSHT_start = psht;
- pACB_start = NULL;
+ DC390_LOCK_DRV;
+ //dc390_pSHT_start = psht;
+ dc390_pACB_start = NULL;
X
- MechNum = 1;
- for( ; (MechNum < 3) && (!adaptCnt); MechNum++)
- {
- BusDevFunNum = 0;
- for (; adaptCnt < MAX_ADAPTER_NUM ;)
+ if ( PCI_PRESENT )
+ while (PCI_FIND_DEVICE (PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD53C974))
X {
- if( !DC390_ToMech( MechNum, BusDevFunNum) )
- {
- wlval = DC390_inDword( MechNum, PCI_VENDOR_ID);
- if(wlval == ( (PCI_DEVICE_ID_AMD53C974 << 16)+
- PCI_VENDOR_ID_AMD) )


SHAR_EOF
true || echo 'restore of patch-2.0.37 failed'
fi

echo 'End of part 39'
echo 'File patch-2.0.37 is continued in part 40'
echo 40 > _shar_seq_.tmp

Thomas...@ciw.uni-karlsruhe.de

unread,
Jun 16, 1999, 3:00:00 AM6/16/99
to
Archive-name: v2.0/patch-2.0.37/part41

#!/bin/sh
# this is part 41 of a 45 - part archive


# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.0.37 continued
if test ! -r _shar_seq_.tmp; then
echo 'Please unpack part 1 first!'
exit 1
fi
(read Scheck

if test "$Scheck" != 41; then


echo Please unpack part "$Scheck" next!
exit 1
else
exit 0
fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.0.37'
else
echo 'x - continuing with patch-2.0.37'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.0.37' &&

+#define SUPPORT_PARCHK 0x80
+
+
+static unsigned int port_base = 0;
+static unsigned int CFG_BASE = 0;
+static unsigned int interrupt_level = 0;
+
+/* period table
+
+ static sync_tbl period_tbl[8]= {
+ { 0, 12, 12,},
+ { 1, 16, 18,},
+ { 2, 20, 25,},
+ { 3, 25, 31,},
+ { 4, 29, 37,},
+ { 5, 33, 43,},
+ { 6, 50, 50,},
+ { 7, 58, 75,},
+ };
+ */
+
+/* pointer to scsi host struc for each HA */
+/* needs change for multiple HA support */
+
+static struct Scsi_Host *tripace_host;
+
+/* Tc2550 mailbox data structures */
+static unsigned char tcmbdata[Q_FILE_SIZE + DEVHDR_SIZE + MBOX_SIZE + 64];
+/* static alloc of sg table for all tasks */
+/* dynamic memory is giving problems */
+static unsigned char table[8 * MAXSGENT * MAXSRBS * MAXTARGET + 4];
+
+
+/* global variables */
+/* logical addresses of mailbox in/out,dev header base,task que base */
+
+static unsigned char *startsgptr;
+static unsigned long pstartsgptr;
+
+
+static u32 mbx_in_base, mbx_out_base, devhdr_base, taskq_base;
+static u8 TargetID;
+
+
+/* hostadapter structure-as of now we have a single adapter */
+Adapter HostAdapter[1];
+unsigned char ReqType, targetID, HANumber, Index, HostID;
+
+/* variable for term power in case of /T option */
+static unsigned short int EN_TERM_PWR = TERM_PWR_EN;
+static unsigned short fast_clk = 0;
+static unsigned short par_off = 0;
+static unsigned short discon = 1;
+static unsigned short syncflag = 1;
+static unsigned short tagflag = 0;
+
+
+static int makecode(unsigned, unsigned);
+static void Init_struc(int);
+static int download_RISC_code(void);
+static void init_chip_reg(void);
+
+static PRISC_SRB search(PAdapter);
+u32 insert_bit(u32, short int);
+static void Get_Base(Adapter *);
+
+void tc2550_intr(int, void *, struct pt_regs *);
+
+static void internal_done(Scsi_Cmnd *);
+
+int tc2550_command(Scsi_Cmnd *);
+
+static int tc2550_pci_bios_detect(int *irq, int *iobase)
+{
+ int error;
+ unsigned char pci_bus, pci_dev_fn; /* PCI bus & device function */
+ unsigned char pci_irq; /* PCI interrupt line */
+ unsigned int pci_base; /* PCI I/O base address */
+ unsigned short pci_vendor, pci_device; /* PCI vendor & device IDs */
+
+
+ /* We will have to change this if more than 1 PCI bus is present and the
+ tripace scsi host is not on the first bus (i.e., a PCI to PCI bridge,
+ which is not supported by bios32 right now anyway). */
+
+ pci_bus = 0;
+
+ for (pci_dev_fn = 0x0; pci_dev_fn < 0xff; pci_dev_fn++)
+ {
+ pcibios_read_config_word(pci_bus,
+ pci_dev_fn,
+ PCI_VENDOR_ID,
+ &pci_vendor);
+
+ if (pci_vendor == 0x1190)
+ {
+ pcibios_read_config_word(pci_bus,
+ pci_dev_fn,
+ PCI_DEVICE_ID,
+ &pci_device);
+
+ if (pci_device == 0xc731)
+ {
+ /* Break out once we have the correct device. If othertrip
+ PCI devices are added to this driver we will need to add
+ an or of the other PCI_DEVICE_ID here. */
+ printk(KERN_INFO "Tripace TC-2550x based PCI SCSI Adapter detected\n");
+ break;
+ } else
+ {
+ /* If we can't finl an tripace scsi card we give up. */


+ return 0;
+ }
+ }
+ }

+
+/* vendor id not found */
+
+ if (pci_device != 0xc731)
+ {
+ printk(KERN_INFO "Tripace TC-2550x - No Host Adapter Detected \n");
+ return (0);
+ }
+ /* We now have the appropriate device function for the tripace board so we
+ just read the PCI config info from the registers. */
+
+ if ((error = pcibios_read_config_dword(pci_bus,
+ pci_dev_fn,
+ PCI_BASE_ADDRESS_0,
+ &pci_base))
+ || (error = pcibios_read_config_byte(pci_bus,
+ pci_dev_fn,
+ PCI_INTERRUPT_LINE,
+ &pci_irq)))
+ {
+ printk(KERN_ERR "Tripace TC-2550x not initializing"
+ " due to error reading configuration space\n");
+ return 0;
+ } else
+ {
+ printk(KERN_INFO "TC-2550x PCI: IRQ = %u, I/O base = %X\n",
+ pci_irq, pci_base);
+
+ /* Now we have the I/O base address and interrupt from the PCI
+ configuration registers.
+ */
+
+ *irq = pci_irq;
+ *iobase = (pci_base & 0xfff8);
+ CFG_BASE = *iobase;
+
+ printk(KERN_INFO "TC-2550x Driver version 1.00.000 (904)\n");
+ printk(KERN_INFO "TC-2550x: IRQ = %d, I/O base = 0x%X\n", *irq, *iobase);
+ return 1;


+ }
+ return 0;
+}
+

+static void init_chip_reg(void)
+{
+ int i, val, base;
+ unsigned long tick;
+
+ outw(HALT_RISC, CONTROL_REG);
+ base = CFG_BASE + 0x20;
+ for (i = 0; i < 16; i++)
+ outw(0, base + i * 2);
+ outw(EN_TERM_PWR, STATUS_INT_REG);
+ outw(RESET_SCSI_BUS, STATUS_INT_REG);
+
+ udelay(50); /*wait for 50 micro secs */
+
+ outw(EN_TERM_PWR, STATUS_INT_REG);
+ val = (HALT_RISC | RISC_CHIP_RESET);
+ outw(val, CONTROL_REG);
+ outw(HALT_RISC, CONTROL_REG);
+ val = inw(STATUS_INT_REG);
+ tick = 0;
+ while ((val & 0x40) == 0 && tick < 0x3fff)
+ {
+ val = inw(STATUS_INT_REG);
+ tick += 1;
+ };
+ if (tick == 0x3fff)
+ printk(KERN_DEBUG "val= %x \n\r", val);
+ outw(EN_TERM_PWR, STATUS_INT_REG);
+ outw(0, SCSI_CONTROL);
+
+/* delay for 50 micro secs */
+ udelay(50);
+}
+
+static int download_RISC_code(void)
+{
+ unsigned short i, j, fast = 0;
+ unsigned short hi, low, base;
+ long tmp;
+ unsigned long start_time;
+
+ i = inw(CONTROL_REG);
+ if (i & 0x40)
+ fast = 1;
+ outw(HALT_RISC, CONTROL_REG);
+
+/* Ravi modified for sanity check dec 17 1998 */
+ start_time = jiffies;
+
+ do
+ {
+ if ((jiffies - start_time) > 5 * HZ)
+ {
+ printk(KERN_ERR "tc2550: Download failure.\n");
+ return 1;
+ }
+ i = inw(STATUS_INT_REG);
+ }
+ while ((i & 0x40) == 0);
+
+ outw(HALT_RISC + EN_MEMORY_WRITE, CONTROL_REG);
+ outw(EN_TERM_PWR + DIS_INTR, STATUS_INT_REG);
+
+ /* download load RISC code
+ */
+ outw(0, PC);
+ for (i = 0; i < ucode_size; i++)
+ outl(ucode_instruction[i], CURRENT_INST);
+ /*
+ // checksum checking (word)
+ */
+ base = 0;
+ for (i = 0; i < ucode_size; i++)
+ {
+ outw(i * 4, PC);
+ tmp = inl(PROGRAM_DATA_REG);
+ hi = tmp >> 16;
+ low = (tmp & 0xffff);
+ base = base + (hi + low);
+ }
+ outw(HALT_RISC + RISC_CHIP_RESET, CONTROL_REG);
+ outw(HALT_RISC, CONTROL_REG);
+ if (fast_clk)
+ outw((HALT_RISC | FAST_CLOCK), CONTROL_REG);
+ if (par_off)
+ {
+ i = inw(CONTROL_REG);
+ outw((i | DIS_SCSI_PARITY), CONTROL_REG);
+ }
+ outw(EN_TERM_PWR, STATUS_INT_REG);
+ /*ravi
+ */
+ if ((unsigned short) (ucode_checksum + base) != 0)
+ {
+ printk(KERN_ERR "tc2550: Checksum Error During Code Download\n");


+ return (1);
+ };
+ /*

+ load vector table
+ */
+ j = 0;
+ base = CFG_BASE;
+ for (i = 0, j = 0; i < 15; i++, j = j + 2)
+ outw(ucode_vector[i], (base + j));
+ outw(0, SCSI_CONTROL);


+ return (0);
+}
+

+int tc2550_detect(Scsi_Host_Template * tpnt)
+{
+ int flag = 0;
+ int retcode;
+ struct Scsi_Host *shpnt;
+ unsigned long flags;
+ unsigned int mod4;
+
+
+ flag = tc2550_pci_bios_detect(&interrupt_level, &port_base);
+ if (!flag)
+ return (0);
+
+ init_chip_reg(); /* chip Tc-2550 initialize */
+ flag = download_RISC_code();
+ if (flag == 0)
+ {
+ printk(KERN_INFO "tc2550: Successful F/W download on TC-2550x\n");
+ }
+/* now do a scsi register and get scsi host ptr */
+
+ shpnt = scsi_register(tpnt, 0);


+
+ save_flags(flags);
+ cli();

+ retcode = request_irq(interrupt_level,
+ tc2550_intr, SA_INTERRUPT, "tripace", NULL);
+ if (retcode)
+ {
+ printk(KERN_ERR "tc2550: Unable to allocate IRQ for Tripace TC-2550x based SCSI Host Adapter.\n");
+ goto unregister;
+ }
+ /* For multiple HA we need to change all this */
+
+
+ tripace_host = shpnt;
+ shpnt->io_port = CFG_BASE;
+ shpnt->n_io_port = 0xfc; /* Number of bytes of I/O space used */
+ shpnt->dma_channel = 0;
+ shpnt->irq = interrupt_level;
+
+ restore_flags(flags);
+
+
+ /* log i/o ports with the kernel */
+ request_region(port_base, 0xfc, "tripace");
+
+/* when we support multiple HA ,we need to modify */
+ Init_struc(0); /* init mailboxes for one adapter */
+/* sg table init */
+
+ /* get physical address */
+ startsgptr = (unsigned char *) table;
+ pstartsgptr = virt_to_phys((unsigned char *) table);
+ mod4 = pstartsgptr % 4;
+ if (mod4)
+ {
+ pstartsgptr += (4 - mod4);
+ startsgptr += (4 - mod4);


+ }
+ return (0);
+
+

+unregister:
+ scsi_unregister(shpnt);


+ return (0);
+}
+

+/****************************************************************************
+** Init chip registers and allocate required memory space
+****************************************************************************/
+
+static void Init_struc(int id)
+{
+ u32 pmbx_in_base, pmbx_out_base, pdevhdr_base, ptaskq_base;
+ unsigned long paddr;
+ char *laddr;
+ unsigned short modulo;
+
+/* setup ioport address and irq */
+
+ HostAdapter[id].IoPort = (u16) CFG_BASE;
+ HostAdapter[id].IntrNum = (u8) interrupt_level;
+
+ laddr = tcmbdata;
+ paddr = virt_to_phys(tcmbdata);
+/* adjust phys address to 32 byte boundary */
+ modulo = paddr % 32;
+ if (modulo)
+ {
+ paddr = paddr + 32 - modulo;
+ laddr = laddr + 32 - modulo;
+ }
+ /* logical address */
+ mbx_in_base = (u32) laddr;
+ pmbx_in_base = paddr;
+ HostAdapter[id].mbx_in_base = mbx_in_base;
+
+ laddr += 32;
+ paddr += 32;
+ mbx_out_base = (u32) laddr;
+ pmbx_out_base = paddr;
+ HostAdapter[id].mbx_out_base = mbx_out_base;
+ memset((char *) mbx_in_base, 0, 48);
+
+ laddr += 32;
+ paddr += 32;
+ devhdr_base = (u32) laddr;
+ pdevhdr_base = paddr;
+ HostAdapter[id].devhdr_base = devhdr_base;
+ memset((char *) devhdr_base, 0, 512);
+
+
+ laddr += 512;
+ paddr += 512;
+
+ taskq_base = (u32) laddr;
+ ptaskq_base = paddr;
+ HostAdapter[id].taskq_base = taskq_base;
+ memset((char *) taskq_base, 0, Q_FILE_SIZE);
+
+ HostAdapter[id].ptaskq_base = (u32) ptaskq_base;
+ HostAdapter[id].pdev_base = (u32) pdevhdr_base;
+ HostAdapter[id].pmbi_base = (u32) pmbx_in_base;
+ HostAdapter[id].pmbo_base = (u32) pmbx_out_base;
+
+ outl(pmbx_in_base, MBX_IN_BASE);
+ outl(pmbx_out_base, MBX_OUT_BASE);
+ outl(pdevhdr_base, DEV_HDR_BASE);
+ outl(ptaskq_base, TASK_Q_BASE);
+ outb(0, MBX_IN_INDEX);
+ outb(0, MBX_OUT_INDEX);
+ /* clear mailbox out pointer */
+ HostAdapter[id].mbx_out_ptr = 0;
+}
+
+
+/***************************************************************************
+** adjust bitmap position
+** Input : old bitmap, new bit location
+** Output: return with new bitmap layout
+****************************************************************************/
+
+extern __inline__ u32 insert_bit(u32 bits, short int loc)
+{
+ u32 lo = 0;
+
+ lo = 1;
+ lo <<= loc;
+
+
+ return ((lo | bits));
+}
+
+
+/***************************************************************************
+** Get the base address and structures of current host adapter
+** Input : adapter structure pointer
+** Output : none
+****************************************************************************/
+
+static void Get_Base(Adapter * padapter)
+{
+
+ CFG_BASE = padapter->IoPort;
+ interrupt_level = (u16) padapter->IntrNum;
+ mbx_in_base = padapter->mbx_in_base;
+ mbx_out_base = padapter->mbx_out_base;
+ devhdr_base = padapter->devhdr_base;
+ taskq_base = padapter->taskq_base;


+
+}
+
+
+

+/***************************************************************************
+** name : search()
+** Desc : search an available SRB from taskQ
+** Input : adapter structure pointer
+** Output : 1. a risc structure space pointer or 0 for non available
+** 2. index of task location
+****************************************************************************/
+static PRISC_SRB search(PAdapter pa)
+{
+ PRISC_SRB rsrb;
+ short int i;


+ unsigned long flags;
+

+ Get_Base(pa);
+ rsrb = (PRISC_SRB) (taskq_base + TargetID * 16 * sizeof(RISC_SRB));
+ /* check attrib in case drive doesn't support SYNC xfer */
+
+ if ((pa->dev[TargetID].attrib & DO_SYNC_NEGO) == 0)
+ ReqType = 0;


+ save_flags(flags);
+ cli();
+

+ Index = 0;
+ for (i = 0; i < 16; i++, rsrb++)
+ if (rsrb->SRB_flag == SRB_DONE)
+ break;
+ if (i == 16)
+ {
+ restore_flags(flags);
+ return (0);
+ }
+ Index = i;
+ restore_flags(flags);
+ memset((char *) rsrb, 0, 32);
+ rsrb->SRB_flag = SRB_ASSIGNED; /* mark for use */
+ if ((pa->dev[TargetID].attrib & 0x44) == 0x44)
+ rsrb->Tag_info = 0x20;
+ return (rsrb);
+}
+
+/***************************************************************************
+** Name : StartSCSICmd()
+** func : 1. all commands passed through here are regular
+** 2. fill in device structure bitmap && start RISC
+** Input : risc srb structure, Index, ReqType
+** Output : none
+****************************************************************************/
+static void StartScsiCmd(PRISC_SRB rsrb)
+{
+ DevHdr *dev;
+ u16 status;
+ PAdapter pa;
+ unsigned short val;
+ u8 t, find_id, find_last, ch = 0;
+ char *mptr;
+/* Request sense CDB */
+ char RequestSense[6] =
+ {0x03, 0x00, 0x00, 0x00, 0x0e, 0};
+
+ pa = (PAdapter) & HostAdapter[HANumber];
+ pa->dev[TargetID].task[Index].CmdInProcess = 1; /* command in process */
+ dev = (DevHdr *) (devhdr_base + TargetID * sizeof(DevHdr));
+ dev->Srb_loc = Index;
+ dev->Request_type = ReqType; /* set request type */
+ dev->Updatedmap = insert_bit(dev->Updatedmap, Index);
+ for (val = 0; val < 6; val++)
+ dev->SenseCmd[val] = RequestSense[val];
+ rsrb->Sense_Cmd_Ptr = virt_to_phys(&dev->SenseCmd[0]);
+
+ if (ReqType >= 2)
+ {
+ if (ReqType & 0x2)
+ dev->WideMsg = 0x1;
+ else
+ {
+/* printf("firing sync nego");
+ //ravi 10/3/98 -ultra support in parse
+
+ if(fast_clk)
+ dev->SyncPeriod = period_tbl[(ultra[TargetID])].f_factor;
+ else
+ dev->SyncPeriod = period_tbl[(ultra[TargetID])].s_factor;
+ */
+
+ if (pa->dev[TargetID].attrib & 0x1)
+ dev->SyncOffset = W_MAX_OFFSET;
+ else
+ dev->SyncOffset = MAX_OFFSET;
+ }
+ }
+ mptr = (char *) mbx_in_base;
+ find_id = 0xff;
+ find_last = 0xff;
+ for (t = 0; t < 15; t++)
+ {
+ ch = *mptr++;
+ if ((ch & 0xf) == TargetID)
+ {
+ find_id = t;


+ break;
+ }
+ }
+

+ mptr = (char *) mbx_in_base;
+ for (t = 0; t < 15; t++)
+ {
+ ch = *mptr++;
+ if (ch & 0x80)
+ {
+ find_last = t;
+ break;
+ }
+ }
+ val = inw(STATUS_INT_REG);
+ mptr = (char *) mbx_in_base;
+ if (find_id != 0xff && find_last != 0xff)
+ {
+ if (find_id < find_last)
+ *(char *) (mptr + find_id) |= 0x10;
+ else
+ {
+ *(char *) (mptr + find_last) &= 0x7f;
+ *(char *) (mptr + find_id) |= 0x90;
+ }
+ } else if (find_last != 0xff && find_id == 0xff)
+ {
+ *(char *) (mptr + find_last) &= 0x7f;
+ find_last = find_last + 1;
+ *(char *) (mptr + find_last) = (0x90 | TargetID);
+ } else if (find_last == 0xff)
+ *(char *) mptr = (0x90 | TargetID);
+
+
+ ReqType = 0;
+ /*
+ // restart the RISC if it is halted before
+ */
+
+ rsrb->SRB_flag = SRB_READY;
+
+
+ if (val & RISC_HALT)
+ {
+ outw(ucode_start, PC); /* set pc counter */
+ status = inw(CONTROL_REG); /* clear halt status */
+ outw((status & ~HALT_RISC), CONTROL_REG);
+ }
+#ifdef DEBUG
+ printk(KERN_DEBUG " start scsi issued \n");
+#endif
+
+}
+


+static void internal_done(Scsi_Cmnd * SCpnt)
+{
+ SCpnt->SCp.Status++;
+}
+

+int tc2550_command(Scsi_Cmnd * SCpnt)
+{
+ tc2550_queue(SCpnt, internal_done);


+
+ SCpnt->SCp.Status = 0;
+ while (!SCpnt->SCp.Status)
+ barrier();
+ return SCpnt->result;
+}
+

+int tc2550_queue(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
+{
+
+ PAdapter pa;
+ PRISC_SRB rsrb;
+ int val;
+ struct scatterlist *sgpnt;
+
+
+ ScatGath *riscsgptr;
+
+
+ int i;
+ unsigned int nentries;
+
+ pa = (PAdapter) & HostAdapter[HANumber];
+ Get_Base(pa);
+ val = 0xaa;
+ TargetID = SCpnt->target;
+ HostID = 7;
+ /* the following code is for corel compatibility */
+ if (SCpnt->lun != 0 ||
+ (TargetID == HostID))
+ {
+ SCpnt->result = DID_BAD_TARGET << 16;
+ done(SCpnt);
+ return (0);
+ };
+ /* Error if more than 16 tasks /target if no space is available */
+
+ if ((rsrb = search(pa)) == 0)
+ {
+ SCpnt->result = DID_ERROR << 16;
+ done(SCpnt);


+ return (0);
+ };
+

+/*Ravi -modified for hostid 16/12/98 */
+ outb((u8) ((TargetID << 4) | HostID), SCSI_ID_REG);
+
+
+ rsrb->CDBLength = SCpnt->cmd_len;
+/* get the physical address of CDB */
+ rsrb->CDB = virt_to_phys((unsigned char *) SCpnt->cmnd);
+
+
+ if (discon)
+
+ rsrb->Identify = 0xC0;
+ else
+ rsrb->Identify = 0x80;
+
+/* scatter gather processing */
+
+ nentries = SCpnt->use_sg;
+ if (nentries == 0)
+ nentries = 1;
+ rsrb->SGNum = nentries;
+
+#ifdef DEBUG
+ printk(KERN_DEBUG "sgentries = %d\n", nentries);
+#endif
+
+/*allocate mem for scatter gather table at 32bit boundary */
+ SCpnt->host_scribble = startsgptr + 8 * MAXSGENT * MAXSRBS * TargetID;
+
+ /*(unsigned char *)scsi_malloc(4096); */
+
+ sgpnt = (struct scatterlist *) SCpnt->request_buffer;
+
+ riscsgptr = (PScatGath) (SCpnt->host_scribble);
+ if (riscsgptr == NULL)
+ panic("tripace: unable to allocate DMA memory\n");
+
+
+ /* fill physical address of scatter-gather list */
+ rsrb->SG_ListPtr = virt_to_phys(SCpnt->host_scribble);
+ rsrb->Cmd_sg_addr = virt_to_phys(rsrb + 4);
+
+ if (SCpnt->use_sg)
+ {
+ for (i = 0; i < SCpnt->use_sg; i++)
+ {
+ if (sgpnt[i].length == 0 || SCpnt->use_sg > 255)
+ {
+ unsigned char *ptr;
+ printk(KERN_ERR "tc2550: Bad segment list supplied to Tripace.c (%d, %d)\n", SCpnt->use_sg, i);
+ for (i = 0; i < SCpnt->use_sg; i++)
+ {
+ printk(KERN_ERR "%d: %x %x %d\n", i, (unsigned int) sgpnt[i].address, (unsigned int) sgpnt[i].alt_address,
+ sgpnt[i].length);
+ };
+ printk(KERN_ERR "RISCGPTR %x: ", (unsigned int) riscsgptr);
+ ptr = (unsigned char *) &riscsgptr[i];
+ for (i = 0; i < 18; i++)
+ printk("%02x ", ptr[i]);
+ panic("Tripace tc-2550x driver!");
+ };
+
+ riscsgptr[i].sg_address = (u32) sgpnt[i].address;
+ riscsgptr[i].sg_length = sgpnt[i].length;
+ };
+ } else
+ {
+ riscsgptr[0].sg_address = (u32) SCpnt->request_buffer;
+ riscsgptr[0].sg_length = SCpnt->request_bufflen;
+ };
+
+
+/* fill sense data pointer and len */
+
+ rsrb->Sense_len = sizeof(SCpnt->sense_buffer);
+ rsrb->SenseDataPtr = virt_to_phys(SCpnt->sense_buffer);
+
+/* store scsi command pointer for use in intr routine */
+ pa->dev[TargetID].task[Index].REQ_Header = (u8 *) SCpnt;


+ SCpnt->scsi_done = done;
+

+ /* pa->dev[TargetID].task[Index].complete = CompleteIORequest; */
+ ReqType = 0;
+ StartScsiCmd(rsrb);


+ return 0;
+}
+

+int tc2550_reset(Scsi_Cmnd * SCpnt)


+{
+ return 0;
+
+}
+

+#include "sd.h"
+
+int tc2550_biosparam(Scsi_Disk * disk, int dev, int *info_array)


+{
+ return 0;
+
+}
+

+int tc2550_abort(Scsi_Cmnd * SCpnt)


+{
+
+ return 0;
+}
+
+

+const char *tc2550_info(struct Scsi_Host *ignore)


+{
+
+ return 0;
+}
+

+void tc2550_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+ void (*my_done) (Scsi_Cmnd *) = NULL;
+
+ int val, id, map = 0, tmap, mbx_out_ptr;
+ u8 loc = 0;
+ PRISC_SRB rsrb;
+ DevHdr *dev;
+ char *ptr0;
+ PAdapter padapter;
+/*
+ int i ;
+ unsigned long flags ;
+ */
+ unsigned int memsize;
+ Scsi_Cmnd *SCtmp;
+ unsigned devstat = 0;
+ unsigned scsistat = 0;
+ long start_time;
+
+#ifdef DEBUG
+ printk("interrupt registered \n");
+#endif
+
+/*
+ save_flags(flags);
+ cli();
+ */
+
+ /* multiple HA? not supported now! */
+ HANumber = 0;
+ padapter = (PAdapter) & HostAdapter[HANumber];
+ Get_Base(padapter);
+
+/* disable interrupts */
+ val = inw(STATUS_INT_REG);
+
+ udelay(10);
+
+ val |= 0x20; /* clear interrupt pending */
+ outw(val, STATUS_INT_REG);
+
+ udelay(10);
+
+ val |= 0x22; /* disable interrupt */
+
+ outw(val, STATUS_INT_REG);
+ /*
+ // if RISC is in halt state then find out why ?
+ */
+ tmap = inw(STATUS_INT_REG);
+/* The following code needs to be added when we intro sync /wide nego */
+/*
+ if(tmap & RISC_HALT) {
+ tmap= risc_halt_check();
+ if(tmap) return(0xff);
+ };
+ */
+
+
+ mbx_out_ptr = padapter->mbx_out_ptr;
+
+ val = *(u16 *) (mbx_out_base + mbx_out_ptr);
+
+ while (val & 0x80)
+ {
+ loc = (char) (val & 0x7f);
+ id = val & 0xff00;
+ id >>= 8;
+ TargetID = id;
+ dev = (DevHdr *) (devhdr_base + TargetID * sizeof(DevHdr));
+ /*(u16 *)(mbx_out_base+ mbx_out_ptr)= (val& 0xff7f); */
+ rsrb = (PRISC_SRB) (taskq_base + (id * 16 + loc) * sizeof(RISC_SRB));
+ Index = loc;
+ devstat = rsrb->DEV_Status;
+ scsistat = rsrb->ScsiStatus;
+
+/* (*padapter->dev[TargetID].task[loc].complete)(rsrb); */
+
+ *(u16 *) (mbx_out_base + mbx_out_ptr) = (val & 0xff7f);
+
+ padapter->dev[TargetID].task[loc].CmdInProcess = 0;
+ mbx_out_ptr += 2;
+ if (mbx_out_ptr == 32)
+ mbx_out_ptr = 0;
+ padapter->mbx_out_ptr = mbx_out_ptr;
+ /*
+ * Clear init bimap if no more tasks are waiting
+ */
+ map = 1;
+ dev->Updatedmap = (dev->Updatedmap ^ (map << loc));
+ if ((dev->Updatedmap & 0x0000ffff) == 0)
+ {
+ ptr0 = (char *) mbx_in_base;
+ for (map = 0; map < 16; map++)
+ if ((*ptr0 & 0xf) == (char) id)
+ {
+ *ptr0 = (*ptr0 & 0xef);
+ break;
+ } else
+ ptr0++;
+ }
+ val = *(u16 *) (mbx_out_base + mbx_out_ptr);
+
+ rsrb->SRB_flag = SRB_DONE; /* mark done */
+ }
+
+ /* stop RISC if mailbox is empty */
+
+ ptr0 = (char *) mbx_in_base;
+ for (map = 0; map < 16; map++)
+ if (*ptr0 & 0x10)
+ break;
+ if (map == 16)
+ {
+ tmap = inw(CONTROL_REG);
+ outw((tmap | HALT_RISC), CONTROL_REG);
+
+/*Ravi modified to introduce sanity check&time out dec 16 1998 */
+
+ start_time = jiffies;
+
+ do
+ {
+ if ((start_time - jiffies) > 5 * HZ)
+ {
+ printk(KERN_ERR "tc2550: TC-2550x Controller Failure\n");
+ return;
+ }
+ tmap = inw(STATUS_INT_REG);
+ }
+ while((tmap & RISC_HALT) == 0);
+ }
+ SCtmp = (Scsi_Cmnd *) padapter->dev[TargetID].task[loc].REQ_Header;
+
+ if (!SCtmp || !SCtmp->scsi_done)
+ {
+ printk(KERN_ERR "tc2550: Tripace_Intr_Handle: Unexpected Interrupt\n");
+ return;
+ }
+ memsize = 255 * sizeof(struct _ScatGath) + 4;
+ my_done = SCtmp->scsi_done;
+ /*if (SCtmp->host_scribble)
+ scsi_free(SCtmp->host_scribble,4096); */
+
+
+ padapter->dev[TargetID].task[loc].REQ_Header = NULL;
+ SCtmp->result = makecode(devstat, scsistat);
+/*enable chip interrupt signal */
+ val = inw(STATUS_INT_REG);
+ udelay(25); /* delay for 25 micros */
+
+ val &= 0xfd; /* enable interrupt-bit1=0 in status-int reg */
+ outw(val, STATUS_INT_REG);
+
+ my_done(SCtmp); /* inform mid layer that scsi command is over */
+/*
+ restore_flags(flags);
+ */
+
+}
+
+/* called from init/main.c */
+void tripace_setup(char *str, int *ints)
+{
+ switch (ints[0])
+ {


+
+ case 0:
+

+ printk(KERN_INFO "tc2550: No Arguments In Command Line:Assuming Defaults\n");
+ break;
+
+ case 1:
+ fast_clk = ints[1];
+ break;
+
+ case 2:
+ fast_clk = ints[1];
+ discon = ints[2];
+ break;
+
+ case 3:
+ fast_clk = ints[1];
+ discon = ints[2];
+ syncflag = ints[3];
+ break;
+
+ case 4:
+ fast_clk = ints[1];
+ discon = ints[2];
+ syncflag = ints[3];
+ tagflag = ints[4];
+ }
+
+#ifdef DEBUG
+ printk("fast_clk = %d,discon = %d,syncflag =%d,tagflag=%d\n",
+ fast_clk, discon, syncflag, tagflag);
+ printk("fast_clk = %d,discon = %d,syncflag =%d,tagflag=%d\n",
+ fast_clk, discon, syncflag, tagflag);
+ printk("fast_clk = %d,discon = %d,syncflag =%d,tagflag=%d\n",
+ fast_clk, discon, syncflag, tagflag);
+ printk("fast_clk = %d,discon = %d,syncflag =%d,tagflag=%d\n",
+ fast_clk, discon, syncflag, tagflag);
+#endif
+
+}
+
+static int makecode(unsigned hosterr, unsigned scsierr)
+{
+ switch (hosterr)
+ {
+ case 0x0:
+ hosterr = 0;
+ break;
+
+ case SEL_TIME_OUT: /* Selection time out-The initiator selection or target


+ reselection was not complete within the SCSI Time out period */

+ hosterr = DID_TIME_OUT;
+ break;
+
+ case ERR_PARITY: /* parity error */
+
+ hosterr = DID_PARITY;
+ break;
+
+ case ERR_OVERRUN: /* Data overrun/underrun-The target attempted to transfer more data


+ than was allocated by the Data Length field or the sum of the
+ Scatter / Gather Data Length fields. */
+

+ case ERR_BUSFREE: /* Unexpected bus free-The target dropped the SCSI BSY at an unexpected time. */
+
+
+ case ERR_PHASE: /* Target bus phase sequence failure-An invalid bus phase or bus
+ phase sequence was requested by the target. */
+
+ hosterr = DID_ERROR; /* Couldn't find any better */


+ break;
+
+ default:

+ hosterr = DID_ERROR;
+ printk(KERN_ERR "tc2550: Makecode: Unknown Hoststatus %x\n", hosterr);
+ break;
+ }
+ return scsierr | (hosterr << 16);
+}
diff -u --recursive --new-file v2.0.36/linux/drivers/scsi/tripace.h linux/drivers/scsi/tripace.h
--- v2.0.36/linux/drivers/scsi/tripace.h Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/tripace.h Sun Jun 13 10:21:03 1999
@@ -0,0 +1,57 @@
+/* tc2550.h -- Header for tripace TC-2550x PCI-SCSI HA
+ * Created: Tue June 9 by chennai team of Tripace Ravi
+ * Author: Ravi rav...@md2.vsnl.net.in
+ * Copyright 1998 Tripace B.V
+ *


+
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+

+ */
+#define MAXSGENT 16
+
+#ifndef _TRIPACE_H
+#define _TRIPACE_H
+
+int tc2550_detect( Scsi_Host_Template * );
+int tc2550_command( Scsi_Cmnd * );
+int tc2550_abort( Scsi_Cmnd * );
+const char *tc2550_info( struct Scsi_Host * );
+int tc2550_reset( Scsi_Cmnd * );
+int tc2550_queue( Scsi_Cmnd *, void (*done)(Scsi_Cmnd *) );
+int tc2550_biosparam(Disk *,int,int *) ;
+
+#define TC2550 { NULL, \
+ NULL, \
+ NULL, \
+ "tripace", \
+ PROC_SCSI_TRIPACE, \
+ NULL, \
+ tc2550_detect, \
+ NULL, \
+ tc2550_info, \
+ tc2550_command, \
+ tc2550_queue, \
+ tc2550_abort, \
+ tc2550_reset, \
+ NULL, \
+ tc2550_biosparam, \
+ 1, \
+ 7, \
+ MAXSGENT, \


+ 1, \
+ 0, \
+ 0, \
+ DISABLE_CLUSTERING }

+#endif
diff -u --recursive --new-file v2.0.36/linux/drivers/scsi/tripace_mcode.h linux/drivers/scsi/tripace_mcode.h
--- v2.0.36/linux/drivers/scsi/tripace_mcode.h Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/tripace_mcode.h Sun Jun 13 10:21:03 1999
@@ -0,0 +1,483 @@
+u16 ucode_vector[] = {
+ 0x1e0, /* vector 0 */
+ 0x0, /* vector 1 */
+ 0x1d8, /* vector 2 */
+ 0x500, /* vector 3 */
+ 0x2f0, /* vector 4 */
+ 0x2e4, /* vector 5 */
+ 0x604, /* vector 6 */
+ 0x258, /* vector 7 */
+ 0x30c, /* vector 8 */
+ 0x45c, /* vector 9 */
+ 0x368, /* vector 10 */
+ 0x4a4, /* vector 11 */
+ 0x514, /* vector 12 */
+ 0x520, /* vector 13 */
+ 0x70c, /* vector 14 */
+ 0x728 /* vector 15 */
+ };
+unsigned short ucode_start = 0x0; /* starting point (9 bit only) */
+
+unsigned short ucode_size = 0x1cb; /* total number of instructions */
+unsigned short ucode_checksum = 0x87d0; /* checksum */
+u32 ucode_instruction[] = {
+ 0x1c0e0078, /* line 1 --- addr 0 */
+ 0x45800000, /* line 2 --- addr 4 */
+ 0x08070004, /* line 3 --- addr 8 */
+ 0x7d040000, /* line 4 --- addr c */
+ 0x08040000, /* line 5 --- addr 10 */
+ 0x9c000f00, /* line 6 --- addr 14 */
+ 0x59500000, /* line 7 --- addr 18 */
+ 0x100e0010, /* line 8 --- addr 1c */
+ 0xcc000000, /* line 9 --- addr 20 */
+ 0x1c0e0078, /* line 10 --- addr 24 */
+ 0x6500000d, /* line 11 --- addr 28 */
+ 0x0c070041, /* line 12 --- addr 2c */
+ 0x08030016, /* line 13 --- addr 30 */
+ 0x9c007700, /* line 14 --- addr 34 */
+ 0x6100000d, /* line 15 --- addr 38 */
+ 0x78000004, /* line 16 --- addr 3c */
+ 0x7c000000, /* line 17 --- addr 40 */
+ 0xdc000100, /* line 18 --- addr 44 */
+ 0x60000008, /* line 19 --- addr 48 */
+ 0x6500000f, /* line 20 --- addr 4c */
+ 0x59700000, /* line 21 --- addr 50 */
+ 0x3000002a, /* line 22 --- addr 54 */
+ 0x9c000700, /* line 23 --- addr 58 */
+ 0x3c00001a, /* line 24 --- addr 5c */
+ 0xa000000e, /* line 25 --- addr 60 */
+ 0x38000148, /* line 26 --- addr 64 */
+ 0x18070021, /* line 27 --- addr 68 */
+ 0x65000019, /* line 28 --- addr 6c */
+ 0x9c000f00, /* line 29 --- addr 70 */
+ 0x59700000, /* line 30 --- addr 74 */
+ 0x1c0e0078, /* line 31 --- addr 78 */
+ 0xc8000000, /* line 32 --- addr 7c */
+ 0x30000145, /* line 33 --- addr 80 */
+ 0x6500000c, /* line 34 --- addr 84 */
+ 0x59700000, /* line 35 --- addr 88 */
+ 0x38000030, /* line 36 --- addr 8c */
+ 0x64000004, /* line 37 --- addr 90 */
+ 0x94000000, /* line 38 --- addr 94 */
+ 0xa0000000, /* line 39 --- addr 98 */
+ 0x3c008043, /* line 40 --- addr 9c */
+ 0x60000008, /* line 41 --- addr a0 */
+ 0x78000004, /* line 42 --- addr a4 */
+ 0x64000008, /* line 43 --- addr a8 */
+ 0x3c008041, /* line 44 --- addr ac */
+ 0x0800003d, /* line 45 --- addr b0 */
+ 0xf8000000, /* line 46 --- addr b4 */
+ 0x60000008, /* line 47 --- addr b8 */
+ 0x6170000c, /* line 48 --- addr bc */
+ 0x6500000d, /* line 49 --- addr c0 */
+ 0x0c070041, /* line 50 --- addr c4 */
+ 0x9c000700, /* line 51 --- addr c8 */
+ 0x38000148, /* line 52 --- addr cc */
+ 0x59070000, /* line 53 --- addr d0 */
+ 0x1c0e0078, /* line 54 --- addr d4 */
+ 0xc8000000, /* line 55 --- addr d8 */
+ 0x1c0e0078, /* line 56 --- addr dc */
+ 0x6d000001, /* line 57 --- addr e0 */
+ 0x0800003f, /* line 58 --- addr e4 */
+ 0x6c200004, /* line 59 --- addr e8 */
+ 0x6c300008, /* line 60 --- addr ec */
+ 0x30000067, /* line 61 --- addr f0 */
+ 0xf8000000, /* line 62 --- addr f4 */
+ 0x60000008, /* line 63 --- addr f8 */
+ 0xdc700100, /* line 64 --- addr fc */
+ 0x3000002a, /* line 65 --- addr 100 */
+ 0x7c000000, /* line 66 --- addr 104 */
+ 0x6100000c, /* line 67 --- addr 108 */
+ 0x78000004, /* line 68 --- addr 10c */
+ 0x30000000, /* line 69 --- addr 110 */
+ 0xc0000000, /* line 70 --- addr 114 */
+ 0xc0000000, /* line 71 --- addr 118 */
+ 0xc0000000, /* line 72 --- addr 11c */
+ 0xc0000000, /* line 73 --- addr 120 */
+ 0xc0000000, /* line 74 --- addr 124 */
+ 0xc0000000, /* line 75 --- addr 128 */
+ 0xc0000000, /* line 76 --- addr 12c */
+ 0x1c060183, /* line 77 --- addr 130 */
+ 0x4d000000, /* line 78 --- addr 134 */
+ 0x0c07004d, /* line 79 --- addr 138 */
+ 0x59070000, /* line 80 --- addr 13c */
+ 0x8c008000, /* line 81 --- addr 140 */
+ 0x49800000, /* line 82 --- addr 144 */
+ 0x6d000001, /* line 83 --- addr 148 */
+ 0x59700000, /* line 84 --- addr 14c */
+ 0x71000401, /* line 85 --- addr 150 */
+ 0x59050000, /* line 86 --- addr 154 */
+ 0x49800000, /* line 87 --- addr 158 */
+ 0xb0000000, /* line 88 --- addr 15c */
+ 0xb0050000, /* line 89 --- addr 160 */
+ 0x1801005d, /* line 90 --- addr 164 */
+ 0x65000010, /* line 91 --- addr 168 */
+ 0xc0000000, /* line 92 --- addr 16c */
+ 0x61000010, /* line 93 --- addr 170 */
+ 0x59070000, /* line 94 --- addr 174 */
+ 0x61000012, /* line 95 --- addr 178 */
+ 0x0c010064, /* line 96 --- addr 17c */
+ 0xfb000000, /* line 97 --- addr 180 */
+ 0xfa000000, /* line 98 --- addr 184 */
+ 0x6570000c, /* line 99 --- addr 188 */
+ 0x30000030, /* line 100 --- addr 18c */
+ 0xfb000000, /* line 101 --- addr 190 */
+ 0xfe000000, /* line 102 --- addr 194 */
+ 0x30000000, /* line 103 --- addr 198 */
+ 0xb0000000, /* line 104 --- addr 19c */
+ 0xfb000000, /* line 105 --- addr 1a0 */
+ 0xf9000002, /* line 106 --- addr 1a4 */
+ 0xd1001018, /* line 107 --- addr 1a8 */
+ 0x65000012, /* line 108 --- addr 1ac */
+ 0xdc000100, /* line 109 --- addr 1b0 */
+ 0x9c000f00, /* line 110 --- addr 1b4 */
+ 0x80000018, /* line 111 --- addr 1b8 */
+ 0x61000012, /* line 112 --- addr 1bc */
+ 0xd1001018, /* line 113 --- addr 1c0 */
+ 0x18010140, /* line 114 --- addr 1c4 */
+ 0xd1000110, /* line 115 --- addr 1c8 */
+ 0x380f0140, /* line 116 --- addr 1cc */
+ 0xb4000000, /* line 117 --- addr 1d0 */
+ 0x30000140, /* line 118 --- addr 1d4 */
+ 0x71001102, /* line 119 --- addr 1d8 */
+ 0x3000004c, /* line 120 --- addr 1dc */
+ 0xb0020000, /* line 121 --- addr 1e0 */
+ 0x2c00707a, /* line 122 --- addr 1e4 */
+ 0x59040080, /* line 123 --- addr 1e8 */
+ 0xcc000000, /* line 124 --- addr 1ec */
+ 0x2c00707f, /* line 125 --- addr 1f0 */
+ 0x6500000c, /* line 126 --- addr 1f4 */
+ 0x3000008b, /* line 127 --- addr 1f8 */
+ 0x59040080, /* line 128 --- addr 1fc */
+ 0x3c200089, /* line 129 --- addr 200 */
+ 0x3c200089, /* line 130 --- addr 204 */
+ 0x3c200089, /* line 131 --- addr 208 */
+ 0x3c200089, /* line 132 --- addr 20c */
+ 0x3c200089, /* line 133 --- addr 210 */
+ 0x3c200089, /* line 134 --- addr 214 */
+ 0x3c210089, /* line 135 --- addr 218 */
+ 0x3c220089, /* line 136 --- addr 21c */
+ 0x3000007c, /* line 137 --- addr 220 */
+ 0x2c00708a, /* line 138 --- addr 224 */
+ 0x59040080, /* line 139 --- addr 228 */
+ 0x59700000, /* line 140 --- addr 22c */
+ 0xc8000000, /* line 141 --- addr 230 */
+ 0x6c100014, /* line 142 --- addr 234 */
+ 0x2c002091, /* line 143 --- addr 238 */
+ 0xb0080000, /* line 144 --- addr 23c */
+ 0xb0080000, /* line 145 --- addr 240 */
+ 0x54000000, /* line 146 --- addr 244 */
+ 0x30000140, /* line 147 --- addr 248 */
+ 0x54000000, /* line 148 --- addr 24c */
+ 0x6c100014, /* line 149 --- addr 250 */
+ 0x30000140, /* line 150 --- addr 254 */
+ 0x65000015, /* line 151 --- addr 258 */
+ 0xdc000100, /* line 152 --- addr 25c */
+ 0x9c000f00, /* line 153 --- addr 260 */
+ 0x80000018, /* line 154 --- addr 264 */
+ 0x61000015, /* line 155 --- addr 268 */
+ 0xd1001018, /* line 156 --- addr 26c */
+ 0xf0000345, /* line 157 --- addr 270 */
+ 0x6d000018, /* line 158 --- addr 274 */
+ 0xc0000000, /* line 159 --- addr 278 */
+ 0x3c0000a4, /* line 160 --- addr 27c */
+ 0x69000018, /* line 161 --- addr 280 */
+ 0x6810001c, /* line 162 --- addr 284 */
+ 0x54000000, /* line 163 --- addr 288 */
+ 0x30000096, /* line 164 --- addr 28c */
+ 0x180500a4, /* line 165 --- addr 290 */
+ 0x2c006129, /* line 166 --- addr 294 */
+ 0x2c0070da, /* line 167 --- addr 298 */
+ 0x180b00ac, /* line 168 --- addr 29c */
+ 0x280000ac, /* line 169 --- addr 2a0 */
+ 0x1c0900ac, /* line 170 --- addr 2a4 */
+ 0xf1000645, /* line 171 --- addr 2a8 */
+ 0x28000140, /* line 172 --- addr 2ac */
+ 0x280020b2, /* line 173 --- addr 2b0 */
+ 0x7c000000, /* line 174 --- addr 2b4 */
+ 0x59040080, /* line 175 --- addr 2b8 */
+ 0x2c0020ae, /* line 176 --- addr 2bc */
+ 0x2c0020ae, /* line 177 --- addr 2c0 */
+ 0x300000a4, /* line 178 --- addr 2c4 */
+ 0x280000b8, /* line 179 --- addr 2c8 */
+ 0x7c000000, /* line 180 --- addr 2cc */
+ 0x59400080, /* line 181 --- addr 2d0 */
+ 0x2c0000b4, /* line 182 --- addr 2d4 */
+ 0x2c0000b4, /* line 183 --- addr 2d8 */
+ 0x300000a4, /* line 184 --- addr 2dc */
+ 0x30000140, /* line 185 --- addr 2e0 */
+ 0x1c0200c1, /* line 186 --- addr 2e4 */
+ 0x1c0c00bc, /* line 187 --- addr 2e8 */
+ 0x30000181, /* line 188 --- addr 2ec */
+ 0xb4030000, /* line 189 --- addr 2f0 */
+ 0x71000502, /* line 190 --- addr 2f4 */
+ 0x280050be, /* line 191 --- addr 2f8 */
+ 0x74400680, /* line 192 --- addr 2fc */
+ 0x3000004c, /* line 193 --- addr 300 */
+ 0x71001302, /* line 194 --- addr 304 */
+ 0x3000004c, /* line 195 --- addr 308 */
+ 0x65000014, /* line 196 --- addr 30c */
+ 0xdc000100, /* line 197 --- addr 310 */
+ 0x9c000f00, /* line 198 --- addr 314 */
+ 0x80000018, /* line 199 --- addr 318 */
+ 0x61000014, /* line 200 --- addr 31c */
+ 0xd1001018, /* line 201 --- addr 320 */
+ 0xf0000545, /* line 202 --- addr 324 */
+ 0x2c0040ca, /* line 203 --- addr 328 */
+ 0x180700cf, /* line 204 --- addr 32c */
+ 0x6c20000c, /* line 205 --- addr 330 */
+ 0x6c30001b, /* line 206 --- addr 334 */
+ 0x30000140, /* line 207 --- addr 338 */
+ 0x6d000001, /* line 208 --- addr 33c */
+ 0x9c00fe00, /* line 209 --- addr 340 */
+ 0x69000001, /* line 210 --- addr 344 */
+ 0x7c000000, /* line 211 --- addr 348 */
+ 0xb8000000, /* line 212 --- addr 34c */
+ 0x80000004, /* line 213 --- addr 350 */
+ 0x60000004, /* line 214 --- addr 354 */
+ 0x6c100014, /* line 215 --- addr 358 */
+ 0x6810001c, /* line 216 --- addr 35c */
+ 0x54000000, /* line 217 --- addr 360 */
+ 0x28007140, /* line 218 --- addr 364 */
+ 0x65000017, /* line 219 --- addr 368 */
+ 0xdc000100, /* line 220 --- addr 36c */
+ 0x9c000f00, /* line 221 --- addr 370 */
+ 0x80000018, /* line 222 --- addr 374 */
+ 0x61000017, /* line 223 --- addr 378 */
+ 0xd1001018, /* line 224 --- addr 37c */
+ 0x59040000, /* line 225 --- addr 380 */
+ 0x3c000114, /* line 226 --- addr 384 */
+ 0x3c040104, /* line 227 --- addr 388 */
+ 0x3c0200ed, /* line 228 --- addr 38c */
+ 0x3c0700e8, /* line 229 --- addr 390 */
+ 0x3c0100f6, /* line 230 --- addr 394 */
+ 0x3c2300ef, /* line 231 --- addr 398 */
+ 0x3c0800ed, /* line 232 --- addr 39c */
+ 0xb4030000, /* line 233 --- addr 3a0 */
+ 0xb0050000, /* line 234 --- addr 3a4 */
+ 0x2c0070ea, /* line 235 --- addr 3a8 */
+ 0x28005181, /* line 236 --- addr 3ac */
+ 0x30000140, /* line 237 --- addr 3b0 */
+ 0xb0050000, /* line 238 --- addr 3b4 */
+ 0x30000140, /* line 239 --- addr 3b8 */
+ 0xb0050000, /* line 240 --- addr 3bc */
+ 0x28007181, /* line 241 --- addr 3c0 */
+ 0x59040080, /* line 242 --- addr 3c4 */
+ 0xb4060000, /* line 243 --- addr 3c8 */
+ 0x28006140, /* line 244 --- addr 3cc */
+ 0xb0060000, /* line 245 --- addr 3d0 */
+ 0x30000140, /* line 246 --- addr 3d4 */
+ 0xb0050000, /* line 247 --- addr 3d8 */
+ 0x2c0070f8, /* line 248 --- addr 3dc */
+ 0x59040080, /* line 249 --- addr 3e0 */
+ 0x3c0200ff, /* line 250 --- addr 3e4 */
+ 0x3c0300fd, /* line 251 --- addr 3e8 */
+ 0x2c0070fc, /* line 252 --- addr 3ec */
+ 0x59040080, /* line 253 --- addr 3f0 */
+ 0x2c0070fe, /* line 254 --- addr 3f4 */
+ 0x59040080, /* line 255 --- addr 3f8 */
+ 0x2c007100, /* line 256 --- addr 3fc */
+ 0x59040080, /* line 257 --- addr 400 */
+ 0x2c007102, /* line 258 --- addr 404 */
+ 0x59040040, /* line 259 --- addr 408 */
+ 0x300000e8, /* line 260 --- addr 40c */
+ 0x180a010a, /* line 261 --- addr 410 */
+ 0x18060108, /* line 262 --- addr 414 */
+ 0xb0060000, /* line 263 --- addr 418 */
+ 0x3000010a, /* line 264 --- addr 41c */
+ 0x1c0b010a, /* line 265 --- addr 420 */
+ 0xb0080000, /* line 266 --- addr 424 */
+ 0x1c01010c, /* line 267 --- addr 428 */
+ 0xb4000000, /* line 268 --- addr 42c */
+ 0xb0050000, /* line 269 --- addr 430 */
+ 0x6c10001c, /* line 270 --- addr 434 */
+ 0x68100014, /* line 271 --- addr 438 */
+ 0x50000000, /* line 272 --- addr 43c */
+ 0x6570000c, /* line 273 --- addr 440 */
+ 0xfb000000, /* line 274 --- addr 444 */
+ 0x1c010030, /* line 275 --- addr 448 */
+ 0x30000000, /* line 276 --- addr 44c */
+ 0x1807004c, /* line 277 --- addr 450 */
+ 0xb0050000, /* line 278 --- addr 454 */
+ 0x30000145, /* line 279 --- addr 458 */
+ 0x65000013, /* line 280 --- addr 45c */
+ 0xdc000100, /* line 281 --- addr 460 */
+ 0x9c000f00, /* line 282 --- addr 464 */
+ 0x80000018, /* line 283 --- addr 468 */
+ 0x61000013, /* line 284 --- addr 46c */
+ 0xd1001018, /* line 285 --- addr 470 */
+ 0x6d000099, /* line 286 --- addr 474 */
+ 0x18070120, /* line 287 --- addr 478 */
+ 0x9c00bf00, /* line 288 --- addr 47c */
+ 0x1c010123, /* line 289 --- addr 480 */
+ 0x59400080, /* line 290 --- addr 484 */
+ 0x30000140, /* line 291 --- addr 488 */
+ 0x594000c0, /* line 292 --- addr 48c */
+ 0x2c005125, /* line 293 --- addr 490 */
+ 0x6d4000c0, /* line 294 --- addr 494 */
+ 0x2c005127, /* line 295 --- addr 498 */
+ 0x59470080, /* line 296 --- addr 49c */
+ 0x30000140, /* line 297 --- addr 4a0 */
+ 0x65000016, /* line 298 --- addr 4a4 */
+ 0xdc000100, /* line 299 --- addr 4a8 */
+ 0x9c000f00, /* line 300 --- addr 4ac */
+ 0x80000018, /* line 301 --- addr 4b0 */
+ 0x61000016, /* line 302 --- addr 4b4 */
+ 0xd1001018, /* line 303 --- addr 4b8 */
+ 0x59040080, /* line 304 --- addr 4bc */
+ 0x1c07013e, /* line 305 --- addr 4c0 */
+ 0x69000003, /* line 306 --- addr 4c4 */
+ 0x3802013e, /* line 307 --- addr 4c8 */
+ 0xb4070000, /* line 308 --- addr 4cc */
+ 0x71000402, /* line 309 --- addr 4d0 */
+ 0x61700019, /* line 310 --- addr 4d4 */
+ 0x6d00001a, /* line 311 --- addr 4d8 */
+ 0x6100001b, /* line 312 --- addr 4dc */
+ 0x6d00001b, /* line 313 --- addr 4e0 */
+ 0x6100001e, /* line 314 --- addr 4e4 */
+ 0x38000140, /* line 315 --- addr 4e8 */
+ 0x6500000d, /* line 316 --- addr 4ec */
+ 0x8c008000, /* line 317 --- addr 4f0 */
+ 0x6100000d, /* line 318 --- addr 4f4 */
+ 0xb0070000, /* line 319 --- addr 4f8 */
+ 0x2c00613f, /* line 320 --- addr 4fc */
+ 0x20204778, /* line 321 --- addr 500 */
+ 0x18050141, /* line 322 --- addr 504 */
+ 0x205769ab, /* line 323 --- addr 508 */
+ 0x107e00c0, /* line 324 --- addr 50c */
+ 0x30000140, /* line 325 --- addr 510 */
+ 0x6c200010, /* line 326 --- addr 514 */
+ 0x74300600, /* line 327 --- addr 518 */
+ 0x30000067, /* line 328 --- addr 51c */
+ 0x6500000f, /* line 329 --- addr 520 */
+ 0x59700000, /* line 330 --- addr 524 */
+ 0xc8000000, /* line 331 --- addr 528 */
+ 0x1c0e0078, /* line 332 --- addr 52c */
+ 0x6500000d, /* line 333 --- addr 530 */
+ 0x0c0001b6, /* line 334 --- addr 534 */
+ 0x6c200004, /* line 335 --- addr 538 */
+ 0x6c300008, /* line 336 --- addr 53c */
+ 0x0c010153, /* line 337 --- addr 540 */
+ 0x0c020185, /* line 338 --- addr 544 */
+ 0x30000000, /* line 339 --- addr 548 */
+ 0xb4060000, /* line 340 --- addr 54c */
+ 0xf9000002, /* line 341 --- addr 550 */
+ 0x28005181, /* line 342 --- addr 554 */
+ 0x65000013, /* line 343 --- addr 558 */
+ 0x2c005158, /* line 344 --- addr 55c */
+ 0x6d4000d9, /* line 345 --- addr 560 */
+ 0x2c00515a, /* line 346 --- addr 564 */
+ 0x744001c0, /* line 347 --- addr 568 */
+ 0x2c00515c, /* line 348 --- addr 56c */
+ 0x744002c0, /* line 349 --- addr 570 */
+ 0x2c00515e, /* line 350 --- addr 574 */
+ 0x744003c0, /* line 351 --- addr 578 */
+ 0x2c005160, /* line 352 --- addr 57c */
+ 0x59400080, /* line 353 --- addr 580 */
+ 0x2800717f, /* line 354 --- addr 584 */
+ 0x59040080, /* line 355 --- addr 588 */
+ 0x3c07017d, /* line 356 --- addr 58c */
+ 0x380100e1, /* line 357 --- addr 590 */
+ 0x28007181, /* line 358 --- addr 594 */
+ 0x59040080, /* line 359 --- addr 598 */
+ 0x38020179, /* line 360 --- addr 59c */
+ 0x28007181, /* line 361 --- addr 5a0 */
+ 0x59040080, /* line 362 --- addr 5a4 */
+ 0x38030179, /* line 363 --- addr 5a8 */
+ 0x28007181, /* line 364 --- addr 5ac */
+ 0x59040000, /* line 365 --- addr 5b0 */
+ 0x61000016, /* line 366 --- addr 5b4 */
+ 0x71000d02, /* line 367 --- addr 5b8 */
+ 0x6500000d, /* line 368 --- addr 5bc */
+ 0x08020175, /* line 369 --- addr 5c0 */
+ 0xb4030000, /* line 370 --- addr 5c4 */
+ 0xb0050000, /* line 371 --- addr 5c8 */
+ 0xfe000000, /* line 372 --- addr 5cc */
+ 0x30000189, /* line 373 --- addr 5d0 */
+ 0xb0050000, /* line 374 --- addr 5d4 */
+ 0xb0060000, /* line 375 --- addr 5d8 */
+ 0xfe000000, /* line 376 --- addr 5dc */
+ 0x30000140, /* line 377 --- addr 5e0 */
+ 0x71000702, /* line 378 --- addr 5e4 */
+ 0x28007176, /* line 379 --- addr 5e8 */
+ 0x59040080, /* line 380 --- addr 5ec */
+ 0x3000017a, /* line 381 --- addr 5f0 */
+ 0x71000c02, /* line 382 --- addr 5f4 */
+ 0x30000176, /* line 383 --- addr 5f8 */
+ 0x71000b02, /* line 384 --- addr 5fc */
+ 0x30000176, /* line 385 --- addr 600 */
+ 0x71001402, /* line 386 --- addr 604 */
+ 0x30000140, /* line 387 --- addr 608 */
+ 0x6c200004, /* line 388 --- addr 60c */
+ 0x6c300008, /* line 389 --- addr 610 */
+ 0x74400000, /* line 390 --- addr 614 */
+ 0xf9000002, /* line 391 --- addr 618 */
+ 0x28005181, /* line 392 --- addr 61c */
+ 0x6d4000d9, /* line 393 --- addr 620 */
+ 0x2c00518d, /* line 394 --- addr 624 */
+ 0x2c00518d, /* line 395 --- addr 628 */
+ 0x300001b2, /* line 396 --- addr 62c */
+ 0x28005140, /* line 397 --- addr 630 */
+ 0xb0060000, /* line 398 --- addr 634 */
+ 0x744001c0, /* line 399 --- addr 638 */
+ 0x2c005190, /* line 400 --- addr 63c */
+ 0x744003c0, /* line 401 --- addr 640 */
+ 0x2c005192, /* line 402 --- addr 644 */
+ 0x744001c0, /* line 403 --- addr 648 */
+ 0x65000014, /* line 404 --- addr 64c */
+ 0x2c005195, /* line 405 --- addr 650 */
+ 0x594000c0, /* line 406 --- addr 654 */
+ 0x65000015, /* line 407 --- addr 658 */
+ 0x2c005198, /* line 408 --- addr 65c */
+ 0x59400080, /* line 409 --- addr 660 */
+ 0x280071b4, /* line 410 --- addr 664 */
+ 0x59040080, /* line 411 --- addr 668 */
+ 0x3c0701b2, /* line 412 --- addr 66c */
+ 0x380100e1, /* line 413 --- addr 670 */
+ 0x28007181, /* line 414 --- addr 674 */
+ 0x59040080, /* line 415 --- addr 678 */
+ 0x38030179, /* line 416 --- addr 67c */
+ 0x28007181, /* line 417 --- addr 680 */
+ 0x59040080, /* line 418 --- addr 684 */
+ 0x38010179, /* line 419 --- addr 688 */
+ 0x28007181, /* line 420 --- addr 68c */
+ 0x59040080, /* line 421 --- addr 690 */
+ 0x61000017, /* line 422 --- addr 694 */
+ 0x28007181, /* line 423 --- addr 698 */
+ 0x59040080, /* line 424 --- addr 69c */
+ 0x61000018, /* line 425 --- addr 6a0 */
+ 0x71000a02, /* line 426 --- addr 6a4 */
+ 0x30000176, /* line 427 --- addr 6a8 */
+ 0xc0000000, /* line 428 --- addr 6ac */
+ 0xc0000000, /* line 429 --- addr 6b0 */
+ 0xc0000000, /* line 430 --- addr 6b4 */
+ 0xc0000000, /* line 431 --- addr 6b8 */
+ 0xc0000000, /* line 432 --- addr 6bc */
+ 0xc0000000, /* line 433 --- addr 6c0 */
+ 0xc0000000, /* line 434 --- addr 6c4 */
+ 0x71000902, /* line 435 --- addr 6c8 */
+ 0x30000176, /* line 436 --- addr 6cc */
+ 0x71000802, /* line 437 --- addr 6d0 */
+ 0x30000176, /* line 438 --- addr 6d4 */
+ 0xa000000e, /* line 439 --- addr 6d8 */
+ 0x08000000, /* line 440 --- addr 6dc */
+ 0x74400000, /* line 441 --- addr 6e0 */
+ 0xf90000d2, /* line 442 --- addr 6e4 */
+ 0x28005181, /* line 443 --- addr 6e8 */
+ 0x6d400084, /* line 444 --- addr 6ec */
+ 0x7900000c, /* line 445 --- addr 6f0 */
+ 0x7d000000, /* line 446 --- addr 6f4 */
+ 0xdc000100, /* line 447 --- addr 6f8 */
+ 0x6100000e, /* line 448 --- addr 6fc */
+ 0x1801004c, /* line 449 --- addr 700 */
+ 0xd1000110, /* line 450 --- addr 704 */
+ 0x3000004c, /* line 451 --- addr 708 */
+ 0xf90000ef, /* line 452 --- addr 70c */
+ 0xfe000000, /* line 453 --- addr 710 */
+ 0x280051c5, /* line 454 --- addr 714 */
+ 0x180501c5, /* line 455 --- addr 718 */


SHAR_EOF
true || echo 'restore of patch-2.0.37 failed'
fi

echo 'End of part 41'
echo 'File patch-2.0.37 is continued in part 42'
echo 42 > _shar_seq_.tmp

Thomas...@ciw.uni-karlsruhe.de

unread,
Jun 16, 1999, 3:00:00 AM6/16/99
to
Archive-name: v2.0/patch-2.0.37/part42

#!/bin/sh
# this is part 42 of a 45 - part archive


# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.0.37 continued
if test ! -r _shar_seq_.tmp; then
echo 'Please unpack part 1 first!'
exit 1
fi
(read Scheck

if test "$Scheck" != 42; then


echo Please unpack part "$Scheck" next!
exit 1
else
exit 0
fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.0.37'
else
echo 'x - continuing with patch-2.0.37'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.0.37' &&

+ 0x74400680, /* line 456 --- addr 71c */
+ 0xfb000000, /* line 457 --- addr 720 */
+ 0xfe000000, /* line 458 --- addr 724 */
+ 0xfe000000 /* line 459 --- addr 728 */
+ };
diff -u --recursive --new-file v2.0.36/linux/drivers/sound/audio.c linux/drivers/sound/audio.c
--- v2.0.36/linux/drivers/sound/audio.c Tue Oct 8 09:12:33 1996
+++ linux/drivers/sound/audio.c Sun Jun 13 10:21:03 1999
@@ -201,6 +201,9 @@
X p = 0;
X c = count;
X

+ if (count < 0)
+ return -EINVAL;
+

X if ((audio_mode[dev] & AM_READ) && !(audio_devs[dev]->flags & DMA_DUPLEX))
X { /* Direction change */
X }
diff -u --recursive --new-file v2.0.36/linux/fs/Config.in linux/fs/Config.in
--- v2.0.36/linux/fs/Config.in Sun Nov 15 10:49:47 1998
+++ linux/fs/Config.in Sun Jun 13 10:21:03 1999
@@ -19,32 +19,36 @@
X dep_tristate 'MSDOS fs support' CONFIG_MSDOS_FS $CONFIG_FAT_FS
X dep_tristate 'umsdos: Unix like fs on top of std MSDOS FAT fs' CONFIG_UMSDOS_FS $CONFIG_MSDOS_FS
X dep_tristate 'VFAT (Windows-95) fs support' CONFIG_VFAT_FS $CONFIG_FAT_FS
- dep_tristate 'Codepage 437' CONFIG_NLS_CODEPAGE_437 $CONFIG_NLS
- dep_tristate 'Codepage 737' CONFIG_NLS_CODEPAGE_737 $CONFIG_NLS
- dep_tristate 'Codepage 775' CONFIG_NLS_CODEPAGE_775 $CONFIG_NLS
- dep_tristate 'Codepage 850' CONFIG_NLS_CODEPAGE_850 $CONFIG_NLS
- dep_tristate 'Codepage 852' CONFIG_NLS_CODEPAGE_852 $CONFIG_NLS
- dep_tristate 'Codepage 855' CONFIG_NLS_CODEPAGE_855 $CONFIG_NLS
- dep_tristate 'Codepage 857' CONFIG_NLS_CODEPAGE_857 $CONFIG_NLS
- dep_tristate 'Codepage 860' CONFIG_NLS_CODEPAGE_860 $CONFIG_NLS
- dep_tristate 'Codepage 861' CONFIG_NLS_CODEPAGE_861 $CONFIG_NLS
- dep_tristate 'Codepage 862' CONFIG_NLS_CODEPAGE_862 $CONFIG_NLS
- dep_tristate 'Codepage 863' CONFIG_NLS_CODEPAGE_863 $CONFIG_NLS
- dep_tristate 'Codepage 864' CONFIG_NLS_CODEPAGE_864 $CONFIG_NLS
- dep_tristate 'Codepage 865' CONFIG_NLS_CODEPAGE_865 $CONFIG_NLS
- dep_tristate 'Codepage 866' CONFIG_NLS_CODEPAGE_866 $CONFIG_NLS
- dep_tristate 'Codepage 869' CONFIG_NLS_CODEPAGE_869 $CONFIG_NLS
- dep_tristate 'Codepage 874' CONFIG_NLS_CODEPAGE_874 $CONFIG_NLS
- dep_tristate 'NLS ISO 8859-1' CONFIG_NLS_ISO8859_1 $CONFIG_NLS
- dep_tristate 'NLS ISO 8859-2' CONFIG_NLS_ISO8859_2 $CONFIG_NLS
- dep_tristate 'NLS ISO 8859-3' CONFIG_NLS_ISO8859_3 $CONFIG_NLS
- dep_tristate 'NLS ISO 8859-4' CONFIG_NLS_ISO8859_4 $CONFIG_NLS
- dep_tristate 'NLS ISO 8859-5' CONFIG_NLS_ISO8859_5 $CONFIG_NLS
- dep_tristate 'NLS ISO 8859-6' CONFIG_NLS_ISO8859_6 $CONFIG_NLS
- dep_tristate 'NLS ISO 8859-7' CONFIG_NLS_ISO8859_7 $CONFIG_NLS
- dep_tristate 'NLS ISO 8859-8' CONFIG_NLS_ISO8859_8 $CONFIG_NLS
- dep_tristate 'NLS ISO 8859-9' CONFIG_NLS_ISO8859_9 $CONFIG_NLS
- dep_tristate 'NLS KOI8-R' CONFIG_NLS_KOI8_R $CONFIG_NLS
+ mainmenu_option next_comment
+ comment 'Select available code pages'
+ dep_tristate 'Codepage 437 (United States, Canada)' CONFIG_NLS_CODEPAGE_437 $CONFIG_NLS
+ dep_tristate 'Codepage 737 (Greek)' CONFIG_NLS_CODEPAGE_737 $CONFIG_NLS
+ dep_tristate 'Codepage 775 (Baltic Rim)' CONFIG_NLS_CODEPAGE_775 $CONFIG_NLS
+ dep_tristate 'Codepage 850 (Europe)' CONFIG_NLS_CODEPAGE_850 $CONFIG_NLS
+ dep_tristate 'Codepage 852 (Central/Eastern Europe)' CONFIG_NLS_CODEPAGE_852 $CONFIG_NLS
+ dep_tristate 'Codepage 855 (Cyrillic)' CONFIG_NLS_CODEPAGE_855 $CONFIG_NLS
+ dep_tristate 'Codepage 857 (Turkish)' CONFIG_NLS_CODEPAGE_857 $CONFIG_NLS
+ dep_tristate 'Codepage 860 (Portugese)' CONFIG_NLS_CODEPAGE_860 $CONFIG_NLS
+ dep_tristate 'Codepage 861 (Icelandic)' CONFIG_NLS_CODEPAGE_861 $CONFIG_NLS
+ dep_tristate 'Codepage 862 (Hebrew)' CONFIG_NLS_CODEPAGE_862 $CONFIG_NLS
+ dep_tristate 'Codepage 863 (Canadian French)' CONFIG_NLS_CODEPAGE_863 $CONFIG_NLS
+ dep_tristate 'Codepage 864 (Arabic)' CONFIG_NLS_CODEPAGE_864 $CONFIG_NLS
+ dep_tristate 'Codepage 865 (Nordic European)' CONFIG_NLS_CODEPAGE_865 $CONFIG_NLS
+ dep_tristate 'Codepage 866 (Cyrillic/Russian)' CONFIG_NLS_CODEPAGE_866 $CONFIG_NLS
+ dep_tristate 'Codepage 869 (Greek)' CONFIG_NLS_CODEPAGE_869 $CONFIG_NLS
+ dep_tristate 'Codepage 874 (Thai)' CONFIG_NLS_CODEPAGE_874 $CONFIG_NLS
+ dep_tristate 'NLS ISO 8859-1 (Latin 1; Western Europe)' CONFIG_NLS_ISO8859_1 $CONFIG_NLS
+ dep_tristate 'NLS ISO 8859-2 (Latin 2; Slavic/Central European)' CONFIG_NLS_ISO8859_2 $CONFIG_NLS
+ dep_tristate 'NLS ISO 8859-3 (Latin 3; Esperanto, Galician, Maltese, Turkish)' CONFIG_NLS_ISO8859_3 $CONFIG_NLS
+ dep_tristate 'NLS ISO 8859-4 (Latin 4; Estonian, Latvian, Lithuanian)' CONFIG_NLS_ISO8859_4 $CONFIG_NLS
+ dep_tristate 'NLS ISO 8859-5 (Cyrillic)' CONFIG_NLS_ISO8859_5 $CONFIG_NLS
+ dep_tristate 'NLS ISO 8859-6 (Arabic)' CONFIG_NLS_ISO8859_6 $CONFIG_NLS
+ dep_tristate 'NLS ISO 8859-7 (Modern Greek)' CONFIG_NLS_ISO8859_7 $CONFIG_NLS
+ dep_tristate 'NLS ISO 8859-8 (Hebrew)' CONFIG_NLS_ISO8859_8 $CONFIG_NLS
+ dep_tristate 'NLS ISO 8859-9 (Latin 5; Turkey)' CONFIG_NLS_ISO8859_9 $CONFIG_NLS
+ dep_tristate 'NLS ISO 8859-15 (Latin 9; Western European Languages with Euro)' CONFIG_NLS_ISO8859_15 $CONFIG_NLS
+ dep_tristate 'NLS KOI8-R (Russian)' CONFIG_NLS_KOI8_R $CONFIG_NLS
+ endmenu
X fi
X
X bool '/proc filesystem support' CONFIG_PROC_FS
@@ -64,6 +68,9 @@
X fi
X if [ "$CONFIG_IPX" != "n" ]; then
X tristate 'NCP filesystem support (to mount NetWare volumes)' CONFIG_NCP_FS
+ if [ "$CONFIG_NCP_FS" != "n" ]; then
+ source fs/ncpfs/Config.in
+ fi
X fi
X tristate 'OS/2 HPFS filesystem support (read only)' CONFIG_HPFS_FS
X tristate 'System V and Coherent filesystem support' CONFIG_SYSV_FS
diff -u --recursive --new-file v2.0.36/linux/fs/Makefile linux/fs/Makefile
--- v2.0.36/linux/fs/Makefile Mon Jul 13 13:46:37 1998
+++ linux/fs/Makefile Sun Jun 13 10:21:03 1999
@@ -481,6 +481,14 @@


X endif
X endif
X

+ifeq ($(CONFIG_NLS_ISO8859_15),y)
+NLS += nls_iso8859_15.o
+else
+ ifeq ($(CONFIG_NLS_ISO8859_15),m)
+ M_OBJS += nls_iso8859_15.o
+ endif
+endif
+
X ifeq ($(CONFIG_NLS_KOI8_R),y)
X NLS += nls_koi8_r.o
X else
diff -u --recursive --new-file v2.0.36/linux/fs/autofs/root.c linux/fs/autofs/root.c
--- v2.0.36/linux/fs/autofs/root.c Fri Sep 5 20:43:59 1997
+++ linux/fs/autofs/root.c Sun Jun 13 10:21:03 1999
@@ -108,6 +108,10 @@
X *result = NULL;
X if (!dir)
X return -ENOENT;
+
+ if (len > NAME_MAX)
+ return -ENOENT;
+
X if (!S_ISDIR(dir->i_mode)) {
X iput(dir);
X return -ENOTDIR;
@@ -194,6 +198,9 @@
X iput(dir);
X return -EPERM;
X }
+ if ( len > NAME_MAX)
+ return -ENAMETOOLONG;
+
X if ( autofs_hash_lookup(dh,hash,name,len) ) {
X iput(dir);
X return -EEXIST;
@@ -252,6 +259,9 @@
X
X if ( !autofs_oz_mode(sbi) )
X return -EPERM;
+
+ if(len > NAME_MAX)
+ return -ENAMETOOLONG;
X
X ent = autofs_hash_lookup(dh,hash,name,len);
X if ( !ent )
diff -u --recursive --new-file v2.0.36/linux/fs/ext2/fsync.c linux/fs/ext2/fsync.c
--- v2.0.36/linux/fs/ext2/fsync.c Sun Nov 15 10:49:47 1998
+++ linux/fs/ext2/fsync.c Sun Jun 13 10:21:03 1999
@@ -10,6 +10,8 @@
X * linux/fs/minix/truncate.c Copyright (C) 1991, 1992 Linus Torvalds
X *
X * ext2fs fsync primitive
+ *
+ * Fast 'fsync' on large files (Scott Laird <la...@pacificrim.net>)
X */
X
X #include <asm/segment.h>
@@ -172,6 +174,13 @@
X * Don't sync fast links!
X */
X goto skip;
+
+ /* fsync on large files is *slow*, so fall back to sync() if
+ * the file's over 10M */
+ if (inode->i_size>10000000) {
+ file_fsync(inode,file);
+ goto skip;
+ }
X
X for (wait=0; wait<=1; wait++)
X {
diff -u --recursive --new-file v2.0.36/linux/fs/ioctl.c linux/fs/ioctl.c
--- v2.0.36/linux/fs/ioctl.c Tue Jul 2 09:08:42 1996
+++ linux/fs/ioctl.c Sun Jun 13 10:21:03 1999
@@ -8,6 +8,7 @@
X
X #include <linux/sched.h>
X #include <linux/mm.h>
+#include <linux/file.h>
X #include <linux/errno.h>
X #include <linux/string.h>
X #include <linux/stat.h>
@@ -59,50 +60,57 @@
X {
X struct file * filp;
X int on;
+ int retval = 0;
X
- if (fd >= NR_OPEN || !(filp = current->files->fd[fd]))
+ filp = fget(fd);
+
+ if(filp==NULL)
X return -EBADF;
+
X switch (cmd) {
X case FIOCLEX:
X FD_SET(fd, &current->files->close_on_exec);
- return 0;
+ break;
X
X case FIONCLEX:
X FD_CLR(fd, &current->files->close_on_exec);
- return 0;
+ break;
X
X case FIONBIO:
- on = verify_area(VERIFY_READ, (unsigned int *)arg,
+ retval = verify_area(VERIFY_READ, (unsigned int *)arg,
X sizeof(unsigned int));
- if(on)
- return on;
- on = get_user((unsigned int *) arg);
- if (on)
- filp->f_flags |= O_NONBLOCK;
- else
- filp->f_flags &= ~O_NONBLOCK;
- return 0;
+ if(!retval)
+ {
+ on = get_user((unsigned int *) arg);
+ if (on)
+ filp->f_flags |= O_NONBLOCK;
+ else
+ filp->f_flags &= ~O_NONBLOCK;
+ }
+ break;
X
X case FIOASYNC: /* O_SYNC is not yet implemented,
X but it's here for completeness. */
- on = verify_area(VERIFY_READ, (unsigned int *)arg,
+ retval = verify_area(VERIFY_READ, (unsigned int *)arg,
X sizeof(unsigned int));
- if(on)
- return on;
- on = get_user ((unsigned int *) arg);
- if (on)
- filp->f_flags |= O_SYNC;
- else
- filp->f_flags &= ~O_SYNC;
- return 0;
+ if(!retval)
+ {
+ on = get_user ((unsigned int *) arg);
+ if (on)
+ filp->f_flags |= O_SYNC;
+ else
+ filp->f_flags &= ~O_SYNC;
+ }
+ break;
X
X default:
X if (filp->f_inode && S_ISREG(filp->f_inode->i_mode))
- return file_ioctl(filp, cmd, arg);
-
- if (filp->f_op && filp->f_op->ioctl)
- return filp->f_op->ioctl(filp->f_inode, filp, cmd, arg);
-
- return -ENOTTY;
+ retval = file_ioctl(filp, cmd, arg);
+ else if (filp->f_op && filp->f_op->ioctl)
+ retval = filp->f_op->ioctl(filp->f_inode, filp, cmd, arg);
+ else
+ retval = -ENOTTY;
X }
+ fput(filp, filp->f_inode);
+ return retval;
X }
diff -u --recursive --new-file v2.0.36/linux/fs/isofs/inode.c linux/fs/isofs/inode.c
--- v2.0.36/linux/fs/isofs/inode.c Sun Nov 15 21:51:47 1998
+++ linux/fs/isofs/inode.c Sun Jun 13 10:21:03 1999
@@ -32,6 +32,13 @@
X */
X #define IGNORE_WRONG_MULTI_VOLUME_SPECS
X
+/*
+ * A home-burnt Joliet level 3 cd-rom with a 100 MB zip file had more than
+ * 100 file sections, so the limit should be larger than that. What does the
+ * ISO9660 standard say? (Ulrik Dickow <u...@kampsax.dk>)
+ */
+#define MAX_FILE_SECTIONS 1000
+
X #ifdef LEAK_CHECK
X static int check_malloc = 0;
X static int check_bread = 0;
@@ -547,12 +554,17 @@


X return NULL;
X }
X

+#ifdef DO_FUNKY_BROKEN_MEDIA_CHANGE_CHECK
X if(!check_disk_change(s->s_dev)) {
X return s;
X }
X if (s->u.isofs_sb.s_nls_iocharset)
X unload_nls(s->u.isofs_sb.s_nls_iocharset);
X if (opt.iocharset) kfree(opt.iocharset);
+#else
+ check_disk_change(s->s_dev);
+ return s;
+#endif
X
X out: /* Kick out for various error conditions */
X brelse(bh);
@@ -646,8 +658,9 @@
X nextino = ino->u.isofs_i.i_next_section_ino;
X iput(ino);
X
- if(++i > 100) {
- printk("isofs_bmap: More than 100 file sections ?!?, aborting...\n");
+ if(++i > MAX_FILE_SECTIONS) {
+ printk("isofs_bmap: More than %d file sections ?!?, aborting...\n",
+ MAX_FILE_SECTIONS);
X printk("isofs_bmap: ino=%lu block=%d firstext=%u size=%u nextino=%lu\n",
X inode->i_ino, block, firstext, (unsigned)size, nextino);
X return 0;
@@ -688,9 +701,10 @@
X ino = inode->i_ino;
X i = 0;
X do {
- if(i > 100) {
- printk("isofs_read_level3_size: More than 100 file sections ?!?, aborting...\n"
- "isofs_read_level3_size: inode=%lu ino=%lu\n", inode->i_ino, ino);
+ if(i > MAX_FILE_SECTIONS) {
+ printk("isofs_read_level3_size: More than %d file sections ?!?, aborting...\n"
+ "isofs_read_level3_size: inode=%lu ino=%lu\n", MAX_FILE_SECTIONS,
+ inode->i_ino, ino);


X return 0;
X }
X

@@ -824,8 +838,9 @@
X }
X
X /* There are defective discs out there - we do this to protect
- ourselves. A cdrom will never contain more than 800Mb */
- if((inode->i_size < 0 || inode->i_size > 800000000) &&
+ ourselves. A cdrom will never contain more than 800Mb
+ Allow 1Gig for DVD however - Ulrich Habel */
+ if((inode->i_size < 0 || inode->i_size > 1073741824) &&
X inode->i_sb->u.isofs_sb.s_cruft == 'n') {
X printk("Warning: defective cdrom. Enabling \"cruft\" mount option.\n");
X inode->i_sb->u.isofs_sb.s_cruft = 'y';
diff -u --recursive --new-file v2.0.36/linux/fs/locks.c linux/fs/locks.c
--- v2.0.36/linux/fs/locks.c Sun Nov 15 21:51:47 1998
+++ linux/fs/locks.c Sun Jun 13 10:21:03 1999
@@ -107,6 +107,7 @@
X #include <linux/kernel.h>
X #include <linux/errno.h>
X #include <linux/stat.h>
+#include <linux/file.h>
X #include <linux/fcntl.h>
X
X #include <asm/segment.h>
@@ -255,17 +256,25 @@
X {
X struct file_lock file_lock;
X struct file *filp;
-
- if ((fd >= NR_OPEN) || !(filp = current->files->fd[fd]))
- return (-EBADF);
+ int err = -EINVAL;
+
+ filp = fget(fd);
+ if(filp==NULL)
+ return -EBADF;
+
X
X if (!flock_make_lock(filp, &file_lock, cmd))
- return (-EINVAL);
-
- if ((file_lock.fl_type != F_UNLCK) && !(filp->f_mode & 3))
- return (-EBADF);
+ goto out;
X
- return (flock_lock_file(filp, &file_lock, (cmd & (LOCK_UN | LOCK_NB)) ? 0 : 1));
+ if ((file_lock.fl_type != F_UNLCK) && !(filp->f_mode & 3))
+ {
+ err = -EBADF;
+ goto out;
+ }
+ err=flock_lock_file(filp, &file_lock, (cmd & (LOCK_UN | LOCK_NB)) ? 0 : 1);
+out:
+ fput(filp, filp->f_inode);
+ return err;
X }
X
X /* Report the first existing lock that would conflict with l.
@@ -278,19 +287,27 @@
X struct file *filp;
X struct file_lock *fl,file_lock;
X
- if ((fd >= NR_OPEN) || !(filp = current->files->fd[fd]))
- return (-EBADF);
X error = verify_area(VERIFY_WRITE, l, sizeof(*l));
X if (error)
X return (error);
X
+ filp = fget(fd);
+ if(filp==NULL)
+ return -EBADF;
+
X memcpy_fromfs(&flock, l, sizeof(flock));
X if ((flock.l_type != F_RDLCK) && (flock.l_type != F_WRLCK))
- return (-EINVAL);
+ {
+ error = -EINVAL;
+ goto out;
+ }
X
X if (!filp->f_inode || !posix_make_lock(filp, &file_lock, &flock))
- return (-EINVAL);
-
+ {
+ error = -EINVAL;
+ goto out;
+ }
+
X flock.l_type = F_UNLCK;
X for (fl = filp->f_inode->i_flock; fl != NULL; fl = fl->fl_next) {
X if (!(fl->fl_flags & FL_POSIX))
@@ -307,7 +324,9 @@
X }
X
X memcpy_tofs(l, &flock, sizeof(flock));
- return (0);
+out:
+ fput(filp, filp->f_inode);
+ return error;
X }
X
X /* Apply the lock described by l to an open file descriptor.
@@ -326,19 +345,20 @@
X /* Get arguments and validate them ...
X */
X
- if ((fd >= NR_OPEN) || !(filp = current->files->fd[fd]))
- return (-EBADF);
-
X error = verify_area(VERIFY_READ, l, sizeof(*l));
X if (error)
X return (error);
-
- if (!(inode = filp->f_inode))
- return (-EINVAL);
-
+
+ filp = fget(fd);
+ if(filp==NULL)
+ return -EBADF;
+
+ inode = filp->f_inode;
+
X /*
X * This might block, so we do it before checking the inode.
X */
+
X memcpy_fromfs(&flock, l, sizeof(flock));
X
X /* Don't allow mandatory locks on files that may be memory mapped
@@ -350,22 +370,34 @@
X struct vm_area_struct *vma = inode->i_mmap;
X do {
X if (vma->vm_flags & VM_MAYSHARE)
- return (-EAGAIN);
+ {
+ error = -EAGAIN;
+ goto out;
+ }
X vma = vma->vm_next_share;
X } while (vma != inode->i_mmap);
X }
X
X if (!posix_make_lock(filp, &file_lock, &flock))
- return (-EINVAL);
+ {
+ error = -EINVAL;
+ goto out;
+ }
X
X switch (flock.l_type) {
X case F_RDLCK:
X if (!(filp->f_mode & 1))
- return (-EBADF);
+ {
+ error = -EBADF;
+ goto out;
+ }
X break;
X case F_WRLCK:
X if (!(filp->f_mode & 2))
- return (-EBADF);
+ {
+ error = -EBADF;
+ goto out;
+ }
X break;
X case F_UNLCK:
X break;
@@ -384,13 +416,19 @@
X }
X #endif
X if (!(filp->f_mode & 3))
- return (-EBADF);
+ {
+ error = -EBADF;
+ goto out;
+ }
X break;
X default:
X return (-EINVAL);
X }
X
- return (posix_lock_file(filp, &file_lock, cmd == F_SETLKW));
+ error = posix_lock_file(filp, &file_lock, cmd == F_SETLKW);
+out:
+ fput(filp, filp->f_inode);
+ return error;
X }
X
X /* This function is called when the file is closed.
diff -u --recursive --new-file v2.0.36/linux/fs/ncpfs/Config.in linux/fs/ncpfs/Config.in
--- v2.0.36/linux/fs/ncpfs/Config.in Wed Dec 31 16:00:00 1969
+++ linux/fs/ncpfs/Config.in Sun Jun 13 10:21:03 1999
@@ -0,0 +1,9 @@
+#
+# NCP Filesystem configuration
+#
+bool ' Packet singatures' CONFIG_NCPFS_PACKET_SIGNING
+bool ' Proprietary file locking' CONFIG_NCPFS_IOCTL_LOCKING
+bool ' Clear remove/delete inhibit when needed' CONFIG_NCPFS_STRONG
+bool ' Use NFS namespace if available' CONFIG_NCPFS_NFS_NS
+bool ' Use LONG (OS/2) namespace if available' CONFIG_NCPFS_OS2_NS
+bool ' Allow mounting of volume subdirectories' CONFIG_NCPFS_MOUNT_SUBDIR
diff -u --recursive --new-file v2.0.36/linux/fs/ncpfs/Makefile linux/fs/ncpfs/Makefile
--- v2.0.36/linux/fs/ncpfs/Makefile Thu Feb 22 05:20:19 1996
+++ linux/fs/ncpfs/Makefile Sun Jun 13 10:21:03 1999
@@ -8,7 +8,8 @@
X # Note 2! The CFLAGS definitions are now in the main makefile...
X
X O_TARGET := ncpfs.o
-O_OBJS := dir.o file.o inode.o ioctl.o mmap.o ncplib_kernel.o sock.o
+O_OBJS := dir.o file.o inode.o ioctl.o mmap.o ncplib_kernel.o sock.o \
+ ncpsign_kernel.o
X M_OBJS := $(O_TARGET)
X
X # If you want debugging output, please uncomment the following line
diff -u --recursive --new-file v2.0.36/linux/fs/ncpfs/dir.c linux/fs/ncpfs/dir.c
--- v2.0.36/linux/fs/ncpfs/dir.c Thu Aug 14 21:02:34 1997
+++ linux/fs/ncpfs/dir.c Sun Jun 13 10:21:03 1999
@@ -5,6 +5,8 @@


X *
X */
X

+#include <linux/config.h>
+


X #include <linux/sched.h>
X #include <linux/errno.h>

X #include <linux/stat.h>
@@ -103,7 +105,14 @@
X static inline int
X ncp_preserve_case(struct inode *i)
X {
- return (ncp_namespace(i) == NW_NS_OS2);
+ return
+#ifdef CONFIG_NCPFS_OS2_NS
+ (ncp_namespace(i) == NW_NS_OS2) ||
+#endif /* CONFIG_NCPFS_OS2_NS */
+#ifdef CONFIG_NCPFS_NFS_NS
+ (ncp_namespace(i) == NW_NS_NFS) ||
+#endif /* CONFIG_NCPFS_NFS_NS */
+ 0;
X }
X
X static struct file_operations ncp_dir_operations = {
@@ -157,7 +166,7 @@
X ncp_info_ino(struct ncp_server *server, struct ncp_inode_info *info)
X {
X return ncp_single_volume(server)
- ? info->finfo.i.dirEntNum : (ino_t)info;
+ ? (info->finfo.i.dirEntNum == server->root.finfo.i.dirEntNum)?0:info->finfo.i.dirEntNum: (ino_t)info;
X }
X
X static inline int
@@ -937,6 +946,7 @@
X {
X struct nw_file_info finfo;
X __u8 _name[len+1];
+ int error;
X
X *result = NULL;
X
@@ -961,15 +971,18 @@
X }
X
X lock_super(dir->i_sb);
- if (ncp_open_create_file_or_subdir(NCP_SERVER(dir),
+ if ((error = ncp_open_create_file_or_subdir(NCP_SERVER(dir),
X NCP_ISTRUCT(dir), _name,
X OC_MODE_CREATE|OC_MODE_OPEN|
X OC_MODE_REPLACE,
X 0, AR_READ|AR_WRITE,
- &finfo) != 0)
+ &finfo)) != 0)
X {
X unlock_super(dir->i_sb);
X iput(dir);
+ if (error == 0x87) {
+ return -ENAMETOOLONG;
+ }
X return -EACCES;
X }
X
@@ -1095,6 +1108,65 @@
X return error;
X }
X
+
+#ifdef CONFIG_NCPFS_STRONG
+/* try to delete a readonly file (NW R bit set) */
+
+static int
+ncp_force_unlink(struct inode *dir,char *name,int len)
+{
+ int res=0x9c,res2;
+ struct inode *_inode;
+ struct iattr ia;
+
+ /* remove the Read-Only flag on the NW server */
+
+ dir->i_count++;
+ res2=ncp_lookup(dir,name,len,&_inode);
+ if (res2)
+ {
+ goto leave_me; /* abort operation */
+ }
+ memset(&ia,0,sizeof(struct iattr));
+ ia.ia_mode = _inode->i_mode;
+ ia.ia_mode |= NCP_SERVER(dir)->m.file_mode & 0222; /* set write bits */
+ ia.ia_valid = ATTR_MODE;
+
+ res2=ncp_notify_change(_inode,&ia);
+ if (res2)
+ {
+ iput(_inode);
+ goto leave_me;
+ }
+
+ /* now try again the delete operation */
+
+ res2 = ncp_del_file_or_subdir(NCP_SERVER(dir),NCP_ISTRUCT(dir),name);
+
+ res=res2; /* save status to use as return value */
+
+ res=res2;
+ if (res2) /* delete failed, set R bit again */
+ {
+ memset(&ia,0,sizeof(struct iattr));
+ ia.ia_mode = _inode->i_mode;
+ ia.ia_mode &= ~(NCP_SERVER(dir)->m.file_mode & 0222); /* clear write bits */
+ ia.ia_valid = ATTR_MODE;
+
+ res2=ncp_notify_change(_inode,&ia);
+ if (res2)
+ {
+ iput(_inode);
+ goto leave_me;
+ }
+ }
+ iput(_inode);
+
+ leave_me:
+ return(res);
+}
+#endif /* CONFIG_NCPFS_STRONG */
+
X static int
X ncp_unlink(struct inode *dir, const char *name, int len)
X {
@@ -1126,14 +1198,21 @@
X str_upper(_name);
X }
X
- if ((error = ncp_del_file_or_subdir(NCP_SERVER(dir),
- NCP_ISTRUCT(dir),
- _name)) == 0)
- {
- ncp_invalid_dir_cache(dir);
- }
- else
- {
+ error = ncp_del_file_or_subdir(NCP_SERVER(dir),
+ NCP_ISTRUCT(dir),
+ _name);
+#ifdef CONFIG_NCPFS_STRONG
+ if (error == 0x9c && NCP_SERVER(dir)->m.flags & NCP_MOUNT_STRONG) /* readonly */
+ {
+ error = ncp_force_unlink(dir,_name,len); /* special treatment */
+ }
+#endif /* CONFIG_NCPFS_STRONG */
+
+ if (error == 0) {
+ ncp_invalid_dir_cache(dir);
+ } else if (error == 0xFF) {
+ error = -ENOENT;
+ } else {
X error = -EACCES;
X }
X }
@@ -1141,6 +1220,83 @@
X return error;
X }
X
+#ifdef CONFIG_NCPFS_STRONG
+static int
+ncp_force_rename(struct inode *old_dir, const char *old_name, char *_old_name, int old_len,
+ struct inode *new_dir, const char *new_name, char *_new_name, int new_len)
+{
+ int res=0x90,res2;
+ char _rename_old[old_len+1];
+ char _rename_new[new_len+1];
+ struct inode *_inode,*x_dir;
+ struct iattr ia;
+
+ strncpy(_rename_old,old_name,old_len);
+ _rename_old[old_len] = 0;
+ strncpy(_rename_new,new_name,new_len);
+ _rename_new[new_len] = 0;
+
+ /* remove the Read-Only flag on the NW server */
+
+ old_dir->i_count++;
+ res2=ncp_lookup(old_dir,_rename_old,old_len,&_inode);
+ if (res2)
+ {
+ goto leave_me;
+ }
+ memset(&ia,0,sizeof(struct iattr));
+ ia.ia_mode = _inode->i_mode;
+ ia.ia_mode |= NCP_SERVER(old_dir)->m.file_mode & 0222; /* set write bits */
+ ia.ia_valid = ATTR_MODE;
+
+ res2=ncp_notify_change(_inode,&ia);
+ if (res2)
+ {
+ iput(_inode);
+ goto leave_me;
+ }
+
+ /* now try again the rename operation */
+ res2 = ncp_ren_or_mov_file_or_subdir(NCP_SERVER(old_dir),
+ NCP_ISTRUCT(old_dir), _old_name,
+ NCP_ISTRUCT(new_dir), _new_name);
+
+ res=res2;
+ if (!res2) /* rename succeeded, get a new inode for the new file */
+ {
+ x_dir=new_dir;
+ new_dir->i_count++;
+ iput(_inode);
+ res2=ncp_lookup(new_dir,_rename_new,new_len,&_inode);
+ if (res2)
+ {
+ goto leave_me;
+ }
+ }
+ else
+ {
+ x_dir=old_dir;
+ }
+
+ memset(&ia,0,sizeof(struct iattr));
+ ia.ia_mode = _inode->i_mode;
+ ia.ia_mode &= ~(NCP_SERVER(x_dir)->m.file_mode & 0222); /* clear write bits */
+ ia.ia_valid = ATTR_MODE;
+
+ res2=ncp_notify_change(_inode,&ia);
+ iput(_inode);
+ if (res2)
+ {
+ printk(KERN_INFO "ncpfs: ncp_notify_change (2) failed: %08x\n",res2);
+ goto leave_me;
+ }
+
+ leave_me:
+ return(res);
+}
+#endif /* CONFIG_NCPFS_STRONG */


+
+
X static int

X ncp_rename(struct inode *old_dir, const char *old_name, int old_len,
X struct inode *new_dir, const char *new_name, int new_len,
@@ -1197,14 +1353,26 @@
X NCP_ISTRUCT(old_dir), _old_name,
X NCP_ISTRUCT(new_dir), _new_name);
X
- if (res == 0)
+#ifdef CONFIG_NCPFS_STRONG
+ if (res == 0x90 && NCP_SERVER(old_dir)->m.flags & NCP_MOUNT_STRONG) /* file is readonly */
X {
- ncp_invalid_dir_cache(old_dir);
- ncp_invalid_dir_cache(new_dir);
- }
+ res=ncp_force_rename(old_dir,old_name,_old_name,old_len,new_dir,new_name,_new_name,new_len);
+ }
+#endif /* CONFIG_NCPFS_STRONG */
+
+ if (res == 0)
+ {
+ ncp_invalid_dir_cache(old_dir);
+ ncp_invalid_dir_cache(new_dir);
+ }
X else
X {
- res = -EACCES;
+ if (res == 0x9E)
+ res = -ENAMETOOLONG;
+ else if (res == 0xFF)
+ res = -ENOENT;
+ else
+ res = -EACCES;
X }
X
X finished:
diff -u --recursive --new-file v2.0.36/linux/fs/ncpfs/inode.c linux/fs/ncpfs/inode.c
--- v2.0.36/linux/fs/ncpfs/inode.c Mon Jul 13 13:46:38 1998
+++ linux/fs/ncpfs/inode.c Sun Jun 13 10:21:03 1999
@@ -32,7 +32,6 @@
X static void ncp_read_inode(struct inode *);
X static void ncp_put_super(struct super_block *);
X static void ncp_statfs(struct super_block *sb, struct statfs *buf, int bufsiz);
-static int ncp_notify_change(struct inode *inode, struct iattr *attr);
X
X static struct super_operations ncp_sops = {
X ncp_read_inode, /* read inode */
@@ -83,6 +82,9 @@
X else
X {
X inode->i_mode = NCP_SERVER(inode)->m.file_mode;
+#if 1
+ if (NCP_ISTRUCT(inode)->attributes & /* 0x60001 incl. DiRi */ 1) inode->i_mode &= ~0222;
+#endif
X inode->i_size = NCP_ISTRUCT(inode)->dataStreamSize;
X }
X
@@ -144,10 +146,11 @@
X */
X lock_super(sb);
X
- if (inode->i_count > 1) {
-printk("ncp_put_inode: inode in use device %s, inode %ld, count=%ld\n",
-kdevname(inode->i_dev), inode->i_ino, inode->i_count);
- goto unlock;
+ if (inode->i_count > 1)
+ {
+ printk("ncp_put_inode: inode in use device %s, inode %ld, count=%ld\n",
+ kdevname(inode->i_dev), inode->i_ino, inode->i_count);
+ goto unlock;
X }
X
X DDPRINTK("ncp_put_inode: put %s\n",
@@ -198,6 +201,9 @@
X struct file *msg_filp;
X kdev_t dev = sb->s_dev;
X int error;
+#ifdef CONFIG_NCPFS_PACKET_SIGNING
+ int options;
+#endif
X
X if (data == NULL)
X {
@@ -274,7 +280,10 @@
X server->packet = NULL;
X server->buffer_size = 0;
X server->conn_status = 0;
-
+#ifdef CONFIG_NCPFS_PACKET_SIGNING
+ server->sign_wanted = 0;
+ server->sign_active = 0;
+#endif
X server->m = *data;
X server->m.file_mode = (server->m.file_mode &
X (S_IRWXU|S_IRWXG|S_IRWXO)) | S_IFREG;
@@ -342,6 +351,29 @@
X goto disconnect;
X }
X
+#ifdef CONFIG_NCPFS_PACKET_SIGNING
+ if (ncp_negotiate_size_and_options(server, NCP_DEFAULT_BUFSIZE,
+ NCP_DEFAULT_OPTIONS, &(server->buffer_size), &options) == 0)
+ {
+ if (options != NCP_DEFAULT_OPTIONS)
+ {
+ if (ncp_negotiate_size_and_options(server,
+ NCP_DEFAULT_BUFSIZE,
+ options & 2,
+ &(server->buffer_size), &options) != 0)
+
+ {
+ sb->s_dev = 0;
+ printk("ncp_read_super: "
+ "could not set options\n");
+ goto disconnect;
+ }
+ }
+ if (options & 2)
+ server->sign_wanted = 1;
+ }
+ else
+#endif /* CONFIG_NCPFS_PACKET_SIGNING */
X if (ncp_negotiate_buffersize(server, NCP_DEFAULT_BUFSIZE,
X &(server->buffer_size)) != 0)
X {
@@ -449,7 +481,7 @@
X memcpy_tofs(buf, &tmp, bufsiz);
X }
X
-static int
+int
X ncp_notify_change(struct inode *inode, struct iattr *attr)
X {
X int result = 0;
@@ -479,6 +511,33 @@
X
X info_mask = 0;
X memset(&info, 0, sizeof(info));
+
+#if 1
+ if ((attr->ia_valid & ATTR_MODE) != 0)
+ {
+ if (NCP_ISTRUCT(inode)->attributes & aDIR)
+ {
+ return -EPERM;
+ }
+ else
+ {
+ umode_t newmode;
+
+ info_mask |= DM_ATTRIBUTES;
+ newmode=attr->ia_mode;
+ newmode &= NCP_SERVER(inode)->m.file_mode;
+
+ if (newmode & 0222) /* any write bit set */
+ {
+ info.attributes &= ~0x60001;
+ }
+ else
+ {
+ info.attributes |= 0x60001;
+ }
+ }
+ }
+#endif
X
X if ((attr->ia_valid & ATTR_CTIME) != 0)
X {
diff -u --recursive --new-file v2.0.36/linux/fs/ncpfs/ioctl.c linux/fs/ncpfs/ioctl.c
--- v2.0.36/linux/fs/ncpfs/ioctl.c Fri Mar 22 02:58:41 1996
+++ linux/fs/ncpfs/ioctl.c Sun Jun 13 10:21:03 1999
@@ -5,6 +5,8 @@


X *
X */
X

+#include <linux/config.h>
+
X #include <asm/segment.h>
X #include <linux/errno.h>
X #include <linux/fs.h>
@@ -13,6 +15,7 @@
X #include <linux/sched.h>
X #include <linux/mm.h>
X #include <linux/ncp.h>
+#include "ncplib_kernel.h"
X
X int
X ncp_ioctl (struct inode * inode, struct file * filp,
@@ -151,6 +154,242 @@
X }
X put_fs_word(server->m.mounted_uid, (uid_t*) arg);
X return 0;
+
+#if 0
+ case NCP_IOC_GETMOUNTUID_INT:
+ if ( (permission(inode, MAY_READ) != 0)
+ && (current->uid != server->m.mounted_uid))
+ {
+ return -EACCES;
+ }
+
+ if ((result = verify_area(VERIFY_WRITE, (unsigned int*)arg,
+ sizeof(unsigned int))) != 0)
+ {
+ return result;
+ }
+ {
+ unsigned int tmp=server->m.mounted_uid;
+ put_fs_long(tmp, (unsigned int*) arg);
+ }
+ return 0;
+#endif
+
+#ifdef CONFIG_NCPFS_MOUNT_SUBDIR
+ case NCP_IOC_GETROOT:
+ {
+ struct ncp_setroot_ioctl sr;
+
+ if ( (permission(inode, MAY_READ) != 0)
+ && (current->uid != server->m.mounted_uid))
+ {
+ return -EACCES;
+ }
+ if (server->m.mounted_vol[0]) {
+ sr.volNumber = server->root.finfo.i.volNumber;
+ sr.dirEntNum = server->root.finfo.i.dirEntNum;
+ sr.namespace = server->name_space[sr.volNumber];
+ } else {
+ sr.volNumber = -1;
+ sr.namespace = 0;
+ sr.dirEntNum = 0;
+ }
+ if ((result = verify_area(VERIFY_WRITE,
+ (struct ncp_setroot_ioctl*)arg,
+ sizeof(sr))) != 0)
+ {
+ return result;
+ }
+ memcpy_tofs((struct ncp_setroot_ioctl*)arg,
+ &sr, sizeof(sr));
+ return 0;
+ }
+ case NCP_IOC_SETROOT:
+ {
+ struct ncp_setroot_ioctl sr;
+
+ if ( (permission(inode, MAY_WRITE) != 0)
+ && (current->uid != server->m.mounted_uid))
+ {
+ return -EACCES;
+ }
+ if ((result = verify_area(VERIFY_READ,
+ (struct ncp_setroot_ioctl*)arg,
+ sizeof(sr))) != 0)
+ {
+ return result;
+ }
+ memcpy_fromfs(&sr, (struct ncp_setroot_ioctl*)arg, sizeof(sr));
+ if (sr.volNumber < 0) {
+ server->m.mounted_vol[0] = 0;
+ server->root.finfo.i.volNumber = 0;
+ server->root.finfo.i.dirEntNum = 0;
+ } else if (sr.volNumber >= NCP_NUMBER_OF_VOLUMES) {
+ return -EINVAL;
+ } else {
+ if (ncp_mount_subdir(server, sr.volNumber, sr.namespace, sr.dirEntNum)) {
+ return -ENOENT;


+ }
+ }
+ return 0;
+ }

+#endif /* CONFIG_NCPFS_MOUNT_SUBDIR */
+
+#ifdef CONFIG_NCPFS_PACKET_SIGNING
+ case NCP_IOC_SIGN_INIT:
+ if ((permission(inode, MAY_WRITE) != 0)
+ && (current->uid != server->m.mounted_uid))
+ {
+ return -EACCES;
+ }
+ if ((result = verify_area(VERIFY_READ, (struct ncp_sign_init*)arg,
+ sizeof(struct ncp_sign_init))) != 0)
+ {
+ return result;
+ }
+ if (server->sign_active)
+ {
+ return -EINVAL;
+ }
+ if (server->sign_wanted)
+ {
+ struct ncp_sign_init sign;
+
+ memcpy_fromfs(&sign, (struct ncp_sign_init *) arg,
+ sizeof(sign));
+ memcpy(server->sign_root,sign.sign_root,8);
+ memcpy(server->sign_last,sign.sign_last,16);
+ server->sign_active = 1;
+ }
+ /* ignore when signatures not wanted */
+ return 0;
+
+ case NCP_IOC_SIGN_WANTED:
+ if ( (permission(inode, MAY_READ) != 0)
+ && (current->uid != server->m.mounted_uid))
+ {
+ return -EACCES;
+ }
+ if ((result = verify_area(VERIFY_WRITE, (int*) arg,
+ sizeof(int))) != 0)
+ {
+ return result;
+ }
+ /* Should not it be put_fs_long? Vand...@vc.cvut.cz */
+ put_fs_word(server->sign_wanted, (int*) arg);
+ return 0;
+
+ case NCP_IOC_SET_SIGN_WANTED:
+ {
+ int newstate;
+
+ if ( (permission(inode, MAY_WRITE) != 0)
+ && (current->uid != server->m.mounted_uid))
+ {
+ return -EACCES;
+ }
+ if ((result = verify_area(VERIFY_READ, (int*) arg,
+ sizeof(int))) != 0)
+ {
+ return result;
+ }
+ /* get only low 8 bits... */
+ newstate = get_fs_byte((unsigned char*)arg);
+ if (server->sign_active) {
+ /* cannot turn signatures OFF when active */
+ if (!newstate) return -EINVAL;
+ } else {
+ server->sign_wanted = newstate != 0;


+ }
+ return 0;
+ }
+

+#endif /* CONFIG_NCPFS_PACKET_SIGNING */
+
+#ifdef CONFIG_NCPFS_IOCTL_LOCKING
+ case NCP_IOC_LOCKUNLOCK:
+ if ( (permission(inode, MAY_WRITE) != 0)
+ && (current->uid != server->m.mounted_uid))
+ {
+ return -EACCES;
+ }
+ {
+ struct ncp_lock_ioctl rqdata;
+ struct nw_file_info *finfo;
+ int result;
+
+ if ((result = verify_area(VERIFY_READ,
+ (struct ncp_lock_ioctl*)arg,
+ sizeof(rqdata))) != 0)
+ {
+ return result;
+ }
+ memcpy_fromfs(&rqdata, (struct ncp_lock_ioctl*)arg,
+ sizeof(rqdata));
+ if (rqdata.origin != 0)
+ return -EINVAL;
+ /* check for cmd */
+ switch (rqdata.cmd) {
+ case NCP_LOCK_EX:
+ case NCP_LOCK_SH:
+ if (rqdata.timeout == 0)
+ rqdata.timeout = NCP_LOCK_DEFAULT_TIMEOUT;
+ else if (rqdata.timeout > NCP_LOCK_MAX_TIMEOUT)
+ rqdata.timeout = NCP_LOCK_MAX_TIMEOUT;
+ break;
+ case NCP_LOCK_LOG:
+ rqdata.timeout = NCP_LOCK_DEFAULT_TIMEOUT; /* has no effect */
+ case NCP_LOCK_CLEAR:
+ break;
+ default:
+ return -EINVAL;
+ }
+ if ((result = ncp_make_open(inode, O_RDWR)) != 0)
+ {
+ return result;
+ }
+ if (!ncp_conn_valid(server))
+ {
+ return -EIO;
+ }
+ if (!S_ISREG(inode->i_mode))
+ {
+ return -EISDIR;
+ }
+ finfo=NCP_FINFO(inode);
+ if (!finfo->opened)
+ {
+ return -EBADFD;
+ }
+ if (rqdata.cmd == NCP_LOCK_CLEAR)
+ {
+ result = ncp_ClearPhysicalRecord(NCP_SERVER(inode),
+ finfo->file_handle,
+ rqdata.offset,
+ rqdata.length);
+ if (result > 0) result = 0; /* no such lock */
+ }
+ else
+ {
+ int lockcmd;
+
+ switch (rqdata.cmd)
+ {
+ case NCP_LOCK_EX: lockcmd=1; break;
+ case NCP_LOCK_SH: lockcmd=3; break;
+ default: lockcmd=0; break;
+ }
+ result = ncp_LogPhysicalRecord(NCP_SERVER(inode),
+ finfo->file_handle,
+ lockcmd,
+ rqdata.offset,
+ rqdata.length,
+ rqdata.timeout);
+ if (result > 0) result = -EAGAIN;
+ }
+ return result;
+ }
+#endif /* CONFIG_NCPFS_IOCTL_LOCKING */
X
X default:
X return -EINVAL;
diff -u --recursive --new-file v2.0.36/linux/fs/ncpfs/ncplib_kernel.c linux/fs/ncpfs/ncplib_kernel.c
--- v2.0.36/linux/fs/ncpfs/ncplib_kernel.c Thu Jul 18 05:52:00 1996
+++ linux/fs/ncpfs/ncplib_kernel.c Sun Jun 13 10:21:03 1999
@@ -5,6 +5,8 @@


X *
X */
X

+#include <linux/config.h>
+
X #include "ncplib_kernel.h"
X
X typedef __u8 byte;
@@ -129,6 +131,33 @@
X return *(dword *)(ncp_reply_data(server, offset));
X }
X
+
+/* options:
+ * bit 0 ipx checksum
+ * bit 1 packet signing
+ */
+int
+ncp_negotiate_size_and_options(struct ncp_server *server,
+ int size, int options, int *ret_size, int *ret_options) {
+ int result;
+
+ ncp_init_request(server);
+ ncp_add_word(server, htons(size));
+ ncp_add_byte(server, options);
+
+ if ((result = ncp_request(server, 0x61)) != 0)
+ {
+ ncp_unlock_server(server);


+ return result;
+ }
+

+ *ret_size = min(ntohs(ncp_reply_word(server, 0)), size);
+ *ret_options = ncp_reply_byte(server, 4);
+
+ ncp_unlock_server(server);


+ return 0;
+}
+

X int
X ncp_negotiate_buffersize(struct ncp_server *server,
X int size, int *target)
@@ -261,7 +290,7 @@
X ncp_add_byte(server, 6); /* subfunction */
X ncp_add_byte(server, server->name_space[vol_num]);
X ncp_add_byte(server, server->name_space[vol_num]);
- ncp_add_word(server, 0xff); /* get all */
+ ncp_add_word(server, 0x8006); /* get all */
X ncp_add_dword(server, RIM_ALL);
X ncp_add_handle_path(server, vol_num, dir_base, 1, path);
X

@@ -277,8 +306,9 @@
X }

X
X static inline int
-ncp_has_os2_namespace(struct ncp_server *server, __u8 volume)
+ncp_get_known_namespace(struct ncp_server *server, __u8 volume)
X {
+#if defined(CONFIG_NCPFS_OS2_NS) || defined(CONFIG_NCPFS_NFS_NS)
X int result;
X __u8 *namespace;
X __u16 no_namespaces;
@@ -291,9 +321,10 @@
X if ((result = ncp_request(server, 87)) != 0)
X {
X ncp_unlock_server(server);
- return 0;
+ return NW_NS_DOS;
X }
X
+ result=NW_NS_DOS;
X no_namespaces = ncp_reply_word(server, 0);
X namespace = ncp_reply_data(server, 2);
X
@@ -301,16 +332,104 @@
X {
X DPRINTK("get_namespaces: found %d on %d\n", *namespace,volume);
X
- if (*namespace == 4)
+#ifdef CONFIG_NCPFS_NFS_NS
+ if ((*namespace == NW_NS_NFS) && !(server->m.flags&NCP_MOUNT_NO_NFS))
+ {
+ result = NW_NS_NFS;
+ break;
+ }
+#endif /* CONFIG_NCPFS_NFS_NS */
+#ifdef CONFIG_NCPFS_OS2_NS
+ if ((*namespace == NW_NS_OS2) && !(server->m.flags&NCP_MOUNT_NO_OS2))
X {
- DPRINTK("get_namespaces: found OS2\n");
- ncp_unlock_server(server);
- return 1;
+ result = NW_NS_OS2;
X }
+#endif /* CONFIG_NCPFS_OS2_NS */
X namespace += 1;
X no_namespaces -= 1;
X }
X ncp_unlock_server(server);
+ return result;
+#else /* neither OS2 nor NFS - only DOS */
+ return NW_NS_DOS;
+#endif /* defined(CONFIG_NCPFS_OS2_NS) || defined(CONFIG_NCPFS_NFS_NS) */
+}
+
+static int
+ncp_ObtainSpecificDirBase(struct ncp_server *server,
+ __u8 nsSrc, __u8 nsDst, __u8 vol_num, __u32 dir_base,
+ char *path, /* At most 1 component */
+ __u32 *dirEntNum)


+{
+ int result;
+

+ ncp_init_request(server);
+ ncp_add_byte(server, 6); /* subfunction */
+ ncp_add_byte(server, nsSrc);
+ ncp_add_byte(server, nsDst);
+ ncp_add_word(server, 0x8006); /* get all */
+ ncp_add_dword(server, RIM_ALL);
+ ncp_add_handle_path(server, vol_num, dir_base, 1, path);
+
+ if ((result = ncp_request(server, 87)) != 0)
+ {
+ ncp_unlock_server(server);


+ return result;
+ }
+

+ if (dirEntNum)
+ *dirEntNum = ncp_reply_dword(server, 0x30);
+ ncp_unlock_server(server);


+ return 0;
+}
+
+int

+ncp_mount_subdir(struct ncp_server *server,
+ __u8 volNumber,
+ __u8 srcNS, __u32 dirEntNum)
+{
+ int dstNS;
+ int result;
+ __u32 newDirEnt;
+
+ dstNS = ncp_get_known_namespace(server, volNumber);
+ if ((result = ncp_ObtainSpecificDirBase(server, srcNS, dstNS, volNumber,
+ dirEntNum, NULL, &newDirEnt)) != 0)
+ {
+ return result;
+ }
+ server->name_space[volNumber] = dstNS;
+ server->root.finfo.i.volNumber = volNumber;
+ server->root.finfo.i.dirEntNum = newDirEnt;
+ server->m.mounted_vol[1] = 0;
+ server->m.mounted_vol[0] = 'X';


+ return 0;
+}
+

+static int
+ncp_obtain_DOS_dir_base(struct ncp_server *server,
+ struct nw_info_struct* file,
+ char *path, /* At most 1 component */
+ __u32 *DOS_dir_base)


+{
+ int result;
+

+ ncp_init_request(server);
+ ncp_add_byte(server, 6); /* subfunction */
+ ncp_add_byte(server, server->name_space[file->volNumber]);
+ ncp_add_byte(server, server->name_space[file->volNumber]);
+ ncp_add_word(server, 0x8006); /* get all */
+ ncp_add_dword(server, RIM_DIRECTORY);
+ ncp_add_handle_path(server, file->volNumber, file->dirEntNum, 1, path);
+
+ if ((result = ncp_request(server, 87)) != 0)
+ {
+ ncp_unlock_server(server);


+ return result;
+ }
+

+ if (DOS_dir_base) *DOS_dir_base=ncp_reply_dword(server, 0x34);
+ ncp_unlock_server(server);


X return 0;
X }
X

@@ -348,7 +467,8 @@
X target->volNumber = volnum = ncp_reply_byte(server, 8);
X ncp_unlock_server(server);
X
- server->name_space[volnum] = ncp_has_os2_namespace(server,volnum)?4:0;
+ server->name_space[volnum] =
+ ncp_get_known_namespace(server, volnum);
X
X DPRINTK("lookup_vol: namespace[%d] = %d\n",
X volnum, server->name_space[volnum]);
@@ -383,25 +503,44 @@
X return result;
X }
X
-int
-ncp_del_file_or_subdir(struct ncp_server *server,
- struct nw_info_struct *dir, char *name)
+static int
+ncp_DeleteNSEntry(struct ncp_server *server,
+ __u8 have_dir_base, __u8 volume, __u32 dir_base,
+ char* name, __u8 ns, int attr)
X {
X int result;
X
X ncp_init_request(server);
X ncp_add_byte(server, 8); /* subfunction */
- ncp_add_byte(server, server->name_space[dir->volNumber]);
+ ncp_add_byte(server, ns); /* namespace */
X ncp_add_byte(server, 0); /* reserved */
- ncp_add_word(server, 0x8006); /* search attribs: all */
- ncp_add_handle_path(server, dir->volNumber,
- dir->dirEntNum, 1, name);
+ ncp_add_word(server, attr); /* search attribs */
+ ncp_add_handle_path(server, volume, dir_base, have_dir_base, name);
X
X result = ncp_request(server, 87);
X ncp_unlock_server(server);
X return result;
X }
X
+int
+ncp_del_file_or_subdir(struct ncp_server *server,
+ struct nw_info_struct *dir, char *name)
+{
+#ifdef CONFIG_NCPFS_NFS_NS
+ if (server->name_space[dir->volNumber]==NW_NS_NFS)
+ {
+ __u32 DOS_dir_base;
+ int result;
+
+ result=ncp_obtain_DOS_dir_base(server, dir, name, &DOS_dir_base);
+ if (result) return result;
+ return ncp_DeleteNSEntry(server, 1, dir->volNumber, DOS_dir_base, NULL, NW_NS_DOS, 0x8006);
+ }
+ else
+#endif /* CONFIG_NCPFS_NFS_NS */
+ return ncp_DeleteNSEntry(server, 1, dir->volNumber, dir->dirEntNum, name, server->name_space[dir->volNumber], 0x8006);
+}
+
X static inline void
X ConvertToNWfromDWORD ( __u32 sfd , __u8 ret[6] )
X {
@@ -428,7 +567,7 @@
X if ((create_attributes & aDIR) != 0)
X {
X search_attribs |= 0x8000;
-}
+ }
X
X ncp_init_request(server);
X ncp_add_byte(server, 1); /* subfunction */
@@ -464,7 +603,7 @@
X if (dir != NULL)
X {
X /* in target there's a new finfo to fill */
- ncp_extract_file_info(ncp_reply_data(server, 5), &(target->i));
+ ncp_extract_file_info(ncp_reply_data(server, 6), &(target->i));
X }
X
X ConvertToNWfromDWORD(target->server_file_handle, target->file_handle);
@@ -511,12 +650,21 @@
X ncp_add_byte(server, 3); /* subfunction */
X ncp_add_byte(server, server->name_space[seq->volNumber]);
X ncp_add_byte(server, 0); /* data stream (???) */
- ncp_add_word(server, 0xffff); /* Search attribs */
+ ncp_add_word(server, 0x8006); /* Search attribs */
X ncp_add_dword(server, RIM_ALL); /* return info mask */
X ncp_add_mem(server, seq, 9);
- ncp_add_byte(server, 2); /* 2 byte pattern */
- ncp_add_byte(server, 0xff); /* following is a wildcard */
- ncp_add_byte(server, '*');
+#ifdef CONFIG_NCPFS_NFS_NS
+ if (server->name_space[seq->volNumber]==NW_NS_NFS)
+ {
+ ncp_add_byte(server, 0);
+ }
+ else
+#endif /* CONFIG_NCPFS_NFS_NS */
+ {
+ ncp_add_byte(server, 2); /* 2 byte pattern */
+ ncp_add_byte(server, 0xff); /* following is a wildcard */
+ ncp_add_byte(server, '*');
+ }
X
X if ((result = ncp_request(server, 87)) != 0)
X {


@@ -532,9 +680,9 @@
X }

X
X int
-ncp_ren_or_mov_file_or_subdir(struct ncp_server *server,
- struct nw_info_struct *old_dir, char *old_name,
- struct nw_info_struct *new_dir, char *new_name)
+ncp_RenameNSEntry(struct ncp_server *server,
+ struct nw_info_struct *old_dir, char *old_name, int old_type,
+ struct nw_info_struct *new_dir, char *new_name)
X {
X int result;
X
@@ -546,7 +694,7 @@
X ncp_add_byte(server, 4); /* subfunction */
X ncp_add_byte(server, server->name_space[old_dir->volNumber]);
X ncp_add_byte(server, 1); /* rename flag */
- ncp_add_word(server, 0x8006); /* search attributes */
+ ncp_add_word(server, old_type); /* search attributes */
X
X /* source Handle Path */
X ncp_add_byte(server, old_dir->volNumber);
@@ -570,6 +718,31 @@
X return result;
X }
X
+int
+ncp_ren_or_mov_file_or_subdir(struct ncp_server *server,
+ struct nw_info_struct *old_dir, char *old_name,
+ struct nw_info_struct *new_dir, char *new_name)
+{
+ int result;
+ int old_type = 0x0006;
+
+/* If somebody can do it atomic, call me... vand...@vc.cvut.cz */
+ result = ncp_RenameNSEntry(server, old_dir, old_name, old_type,
+ new_dir, new_name);
+ if (result == 0xFF) /* File Not Found, try directory */
+ {
+ old_type = 0x0016;
+ result = ncp_RenameNSEntry(server, old_dir, old_name, old_type,
+ new_dir, new_name);
+ }
+ if (result != 0x92) return result; /* All except NO_FILES_RENAMED */
+ result = ncp_del_file_or_subdir(server, new_dir, new_name);
+ if (result != 0) return -EACCES;
+ result = ncp_RenameNSEntry(server, old_dir, old_name, old_type,
+ new_dir, new_name);
+ return result;
+}
+
X
X /* We have to transfer to/from user space */
X int
@@ -624,4 +797,49 @@
X ncp_unlock_server(server);
X return 0;
X }
+
+#ifdef CONFIG_NCPFS_IOCTL_LOCKING
+int
+ncp_LogPhysicalRecord(struct ncp_server *server, const char *file_id,
+ __u8 locktype, __u32 offset, __u32 length, __u16 timeout)


+{
+ int result;
+

+ ncp_init_request(server);
+ ncp_add_byte(server, locktype);
+ ncp_add_mem(server, file_id, 6);
+ ncp_add_dword(server, htonl(offset));
+ ncp_add_dword(server, htonl(length));
+ ncp_add_word(server, htons(timeout));
+
+ if ((result = ncp_request(server, 0x1A)) != 0)
+ {
+ ncp_unlock_server(server);
+ return result;
+ }
+ ncp_unlock_server(server);


+ return 0;
+}
+
+int

+ncp_ClearPhysicalRecord(struct ncp_server *server, const char *file_id,
+ __u32 offset, __u32 length)


+{
+ int result;
+

+ ncp_init_request(server);
+ ncp_add_byte(server, 0); /* who knows... lanalyzer says that */
+ ncp_add_mem(server, file_id, 6);
+ ncp_add_dword(server, htonl(offset));
+ ncp_add_dword(server, htonl(length));
+
+ if ((result = ncp_request(server, 0x1E)) != 0)
+ {
+ ncp_unlock_server(server);
+ return result;
+ }
+ ncp_unlock_server(server);
+ return 0;
+}
+#endif /* CONFIG_NCPFS_IOCTL_LOCKING */
X
diff -u --recursive --new-file v2.0.36/linux/fs/ncpfs/ncplib_kernel.h linux/fs/ncpfs/ncplib_kernel.h
--- v2.0.36/linux/fs/ncpfs/ncplib_kernel.h Wed Oct 15 15:26:30 1997
+++ linux/fs/ncpfs/ncplib_kernel.h Sun Jun 13 10:21:03 1999
@@ -8,6 +8,8 @@
X #ifndef _NCPLIB_H
X #define _NCPLIB_H
X
+#include <linux/config.h>
+
X #include <linux/fs.h>
X #include <linux/ncp.h>
X #include <linux/ncp_fs.h>
@@ -23,6 +25,9 @@
X #include <linux/ncp.h>
X
X int
+ncp_negotiate_size_and_options(struct ncp_server *server, int size,
+ int options, int *ret_size, int *ret_options);
+int
X ncp_negotiate_buffersize(struct ncp_server *server, int size,
X int *target);
X int
@@ -165,5 +170,22 @@
X struct nw_info_struct *old_dir, char *old_name,
X struct nw_info_struct *new_dir, char *new_name);
X
+#ifdef CONFIG_NCPFS_IOCTL_LOCKING
+int
+ncp_LogPhysicalRecord(struct ncp_server *server,
+ const char *file_id, __u8 locktype,
+ __u32 offset, __u32 length, __u16 timeout);
+
+int
+ncp_ClearPhysicalRecord(struct ncp_server *server,
+ const char *file_id,
+ __u32 offset, __u32 length);
+#endif /* CONFIG_NCPFS_IOCTL_LOCKING */
+
+#ifdef CONFIG_NCPFS_MOUNT_SUBDIR
+int
+ncp_mount_subdir(struct ncp_server* server, __u8 volNumber,
+ __u8 srcNS, __u32 srcDirEntNum);
+#endif /* CONFIG_NCPFS_MOUNT_SUBDIR */
X
X #endif /* _NCPLIB_H */
diff -u --recursive --new-file v2.0.36/linux/fs/ncpfs/ncpsign_kernel.c linux/fs/ncpfs/ncpsign_kernel.c
--- v2.0.36/linux/fs/ncpfs/ncpsign_kernel.c Wed Dec 31 16:00:00 1969
+++ linux/fs/ncpfs/ncpsign_kernel.c Sun Jun 13 10:21:03 1999
@@ -0,0 +1,125 @@
+/*
+ * ncpsign_kernel.c
+ *
+ * Arne de Bruijn (ar...@knoware.nl), 1997


+ *
+ */
+

+#include <linux/config.h>
+
+#ifdef CONFIG_NCPFS_PACKET_SIGNING
+
+#if 0


+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>

+#endif
+#endif
+
+#include <linux/string.h>
+#include <linux/ncp.h>
+#if 0
+#include <linux/ncp_fs.h>
+#include <linux/ncp_fs_sb.h>
+#endif
+#include "ncpsign_kernel.h"
+
+#define rol32(i,c) (((((i)&0xffffffff)<<c)&0xffffffff)| \
+ (((i)&0xffffffff)>>(32-c)))
+/* i386: 32-bit, little endian, handles mis-alignment */
+#ifdef __i386__
+#define GET_LE32(p) (*(int *)(p))
+#define PUT_LE32(p,v) { *(int *)(p)=v; }
+#else
+/* from include/ncplib.h */
+#define BVAL(buf,pos) (((__u8 *)(buf))[pos])
+#define PVAL(buf,pos) ((unsigned)BVAL(buf,pos))
+#define BSET(buf,pos,val) (BVAL(buf,pos) = (val))
+
+static inline word
+WVAL_LH(__u8 * buf, int pos)
+{
+ return PVAL(buf, pos) | PVAL(buf, pos + 1) << 8;
+}
+static inline dword
+DVAL_LH(__u8 * buf, int pos)
+{
+ return WVAL_LH(buf, pos) | WVAL_LH(buf, pos + 2) << 16;
+}
+static inline void
+WSET_LH(__u8 * buf, int pos, word val)
+{
+ BSET(buf, pos, val & 0xff);
+ BSET(buf, pos + 1, val >> 8);
+}
+static inline void
+DSET_LH(__u8 * buf, int pos, dword val)
+{
+ WSET_LH(buf, pos, val & 0xffff);
+ WSET_LH(buf, pos + 2, val >> 16);
+}
+
+#define GET_LE32(p) DVAL_LH(p,0)
+#define PUT_LE32(p,v) DSET_LH(p,0,v)
+#endif
+
+#define min(a,b) ((a)<(b)?(a):(b))
+
+static void nwsign(char *r_data1, char *r_data2, char *outdata) {
+ int i;
+ unsigned int w0,w1,w2,w3;
+ static int rbit[4]={0, 2, 1, 3};
+#ifdef __i386__
+ unsigned int *data2=(int *)r_data2;
+#else
+ unsigned int data2[16];
+ for (i=0;i<16;i++)
+ data2[i]=GET_LE32(r_data2+(i<<2));
+#endif
+ w0=GET_LE32(r_data1);
+ w1=GET_LE32(r_data1+4);
+ w2=GET_LE32(r_data1+8);
+ w3=GET_LE32(r_data1+12);
+ for (i=0;i<16;i+=4) {
+ w0=rol32(w0 + ((w1 & w2) | ((~w1) & w3)) + data2[i+0],3);
+ w3=rol32(w3 + ((w0 & w1) | ((~w0) & w2)) + data2[i+1],7);
+ w2=rol32(w2 + ((w3 & w0) | ((~w3) & w1)) + data2[i+2],11);
+ w1=rol32(w1 + ((w2 & w3) | ((~w2) & w0)) + data2[i+3],19);
+ }
+ for (i=0;i<4;i++) {
+ w0=rol32(w0 + (((w2 | w3) & w1) | (w2 & w3)) + 0x5a827999 + data2[i+0],3);
+ w3=rol32(w3 + (((w1 | w2) & w0) | (w1 & w2)) + 0x5a827999 + data2[i+4],5);
+ w2=rol32(w2 + (((w0 | w1) & w3) | (w0 & w1)) + 0x5a827999 + data2[i+8],9);
+ w1=rol32(w1 + (((w3 | w0) & w2) | (w3 & w0)) + 0x5a827999 + data2[i+12],13);
+ }
+ for (i=0;i<4;i++) {
+ w0=rol32(w0 + ((w1 ^ w2) ^ w3) + 0x6ed9eba1 + data2[rbit[i]+0],3);
+ w3=rol32(w3 + ((w0 ^ w1) ^ w2) + 0x6ed9eba1 + data2[rbit[i]+8],9);
+ w2=rol32(w2 + ((w3 ^ w0) ^ w1) + 0x6ed9eba1 + data2[rbit[i]+4],11);
+ w1=rol32(w1 + ((w2 ^ w3) ^ w0) + 0x6ed9eba1 + data2[rbit[i]+12],15);
+ }
+ PUT_LE32(outdata,(w0+GET_LE32(r_data1)) & 0xffffffff);
+ PUT_LE32(outdata+4,(w1+GET_LE32(r_data1+4)) & 0xffffffff);
+ PUT_LE32(outdata+8,(w2+GET_LE32(r_data1+8)) & 0xffffffff);
+ PUT_LE32(outdata+12,(w3+GET_LE32(r_data1+12)) & 0xffffffff);
+}
+
+/* Make a signature for the current packet and add it at the end of the */
+/* packet. */
+void sign_packet(struct ncp_server *server, int *size) {
+ char data[64];
+
+ memset(data,0,64);
+ memcpy(data,server->sign_root,8);
+ PUT_LE32(data+8,(*size));
+ memcpy(data+12,server->packet+sizeof(struct ncp_request_header)-1,
+ min((*size)-sizeof(struct ncp_request_header)+1,52));
+
+ nwsign(server->sign_last,data,server->sign_last);
+
+ memcpy(server->packet+(*size),server->sign_last,8);
+ (*size)+=8;
+}
+
+#endif /* CONFIG_NCPFS_PACKET_SIGNING */
+
diff -u --recursive --new-file v2.0.36/linux/fs/ncpfs/ncpsign_kernel.h linux/fs/ncpfs/ncpsign_kernel.h
--- v2.0.36/linux/fs/ncpfs/ncpsign_kernel.h Wed Dec 31 16:00:00 1969
+++ linux/fs/ncpfs/ncpsign_kernel.h Sun Jun 13 10:21:03 1999
@@ -0,0 +1,16 @@
+/*
+ * ncpsign_kernel.h
+ *
+ * Arne de Bruijn (ar...@knoware.nl), 1997


+ *
+ */
+

+#ifndef _NCPSIGN_KERNEL_H
+#define _NCPSIGN_KERNEL_H
+
+#include <linux/ncp_fs.h>
+#include <linux/ncp_fs_sb.h>
+
+void sign_packet(struct ncp_server *server, int *size);
+
+#endif
diff -u --recursive --new-file v2.0.36/linux/fs/ncpfs/sock.c linux/fs/ncpfs/sock.c
--- v2.0.36/linux/fs/ncpfs/sock.c Tue Dec 2 13:52:32 1997
+++ linux/fs/ncpfs/sock.c Sun Jun 13 10:21:03 1999
@@ -7,6 +7,8 @@


X *
X */
X

+#include <linux/config.h>
+
X #include <linux/sched.h>
X #include <linux/ncp_fs.h>
X #include <linux/errno.h>
@@ -25,6 +27,7 @@
X #include <linux/ncp_fs_sb.h>
X #include <net/sock.h>
X
+#include "ncpsign_kernel.h"
X
X #define _S(nr) (1<<((nr)-1))
X static int _recvfrom(struct socket *sock, unsigned char *ubuf,
@@ -562,7 +565,12 @@
X printk("ncpfs: Server not locked!\n");
X return -EIO;
X }
-
+#ifdef CONFIG_NCPFS_PACKET_SIGNING
+ if (server->sign_active)
+ {
+ sign_packet(server, &size);
+ }
+#endif /* CONFIG_NCPFS_PACKET_SIGNING */
X if (!ncp_conn_valid(server))
X {
X return -EIO;
diff -u --recursive --new-file v2.0.36/linux/fs/nls.c linux/fs/nls.c
--- v2.0.36/linux/fs/nls.c Mon Jul 13 13:46:38 1998
+++ linux/fs/nls.c Sun Jun 13 10:21:03 1999
@@ -455,6 +455,9 @@
X #ifdef CONFIG_NLS_ISO8859_9
X init_nls_iso8859_9();
X #endif
+#ifdef CONFIG_NLS_ISO8859_15
+ init_nls_iso8859_15();
+#endif
X #ifdef CONFIG_NLS_CODEPAGE_437
X init_nls_cp437();
X #endif
diff -u --recursive --new-file v2.0.36/linux/fs/nls_iso8859_15.c linux/fs/nls_iso8859_15.c
--- v2.0.36/linux/fs/nls_iso8859_15.c Wed Dec 31 16:00:00 1969
+++ linux/fs/nls_iso8859_15.c Sun Jun 13 10:21:03 1999
@@ -0,0 +1,268 @@
+/*
+ * linux/fs/nls_iso8859-15.c
+ *
+ * Charset iso8859-15 translation tables.
+ * The Unicode to charset table has only exact mappings.


+ */
+
+#include <linux/module.h>

+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/nls.h>
+
+static struct nls_unicode charset2uni[256] = {
+ /* 0x00*/
+ {0x00, 0x00}, {0x01, 0x00}, {0x02, 0x00}, {0x03, 0x00},
+ {0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x00},
+ {0x08, 0x00}, {0x09, 0x00}, {0x0a, 0x00}, {0x0b, 0x00},
+ {0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00},
+ /* 0x10*/
+ {0x10, 0x00}, {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00},
+ {0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00},
+ {0x18, 0x00}, {0x19, 0x00}, {0x1a, 0x00}, {0x1b, 0x00},
+ {0x1c, 0x00}, {0x1d, 0x00}, {0x1e, 0x00}, {0x1f, 0x00},
+ /* 0x20*/
+ {0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00},
+ {0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00},
+ {0x28, 0x00}, {0x29, 0x00}, {0x2a, 0x00}, {0x2b, 0x00},
+ {0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x2f, 0x00},
+ /* 0x30*/
+ {0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00},
+ {0x34, 0x00}, {0x35, 0x00}, {0x36, 0x00}, {0x37, 0x00},
+ {0x38, 0x00}, {0x39, 0x00}, {0x3a, 0x00}, {0x3b, 0x00},
+ {0x3c, 0x00}, {0x3d, 0x00}, {0x3e, 0x00}, {0x3f, 0x00},
+ /* 0x40*/
+ {0x40, 0x00}, {0x41, 0x00}, {0x42, 0x00}, {0x43, 0x00},
+ {0x44, 0x00}, {0x45, 0x00}, {0x46, 0x00}, {0x47, 0x00},
+ {0x48, 0x00}, {0x49, 0x00}, {0x4a, 0x00}, {0x4b, 0x00},
+ {0x4c, 0x00}, {0x4d, 0x00}, {0x4e, 0x00}, {0x4f, 0x00},
+ /* 0x50*/
+ {0x50, 0x00}, {0x51, 0x00}, {0x52, 0x00}, {0x53, 0x00},
+ {0x54, 0x00}, {0x55, 0x00}, {0x56, 0x00}, {0x57, 0x00},
+ {0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x00}, {0x5b, 0x00},
+ {0x5c, 0x00}, {0x5d, 0x00}, {0x5e, 0x00}, {0x5f, 0x00},
+ /* 0x60*/
+ {0x60, 0x00}, {0x61, 0x00}, {0x62, 0x00}, {0x63, 0x00},
+ {0x64, 0x00}, {0x65, 0x00}, {0x66, 0x00}, {0x67, 0x00},
+ {0x68, 0x00}, {0x69, 0x00}, {0x6a, 0x00}, {0x6b, 0x00},
+ {0x6c, 0x00}, {0x6d, 0x00}, {0x6e, 0x00}, {0x6f, 0x00},
+ /* 0x70*/
+ {0x70, 0x00}, {0x71, 0x00}, {0x72, 0x00}, {0x73, 0x00},
+ {0x74, 0x00}, {0x75, 0x00}, {0x76, 0x00}, {0x77, 0x00},
+ {0x78, 0x00}, {0x79, 0x00}, {0x7a, 0x00}, {0x7b, 0x00},
+ {0x7c, 0x00}, {0x7d, 0x00}, {0x7e, 0x00}, {0x7f, 0x00},
+ /* 0x80*/
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ /* 0x90*/
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ /* 0xa0*/
+ {0xa0, 0x00}, {0xa1, 0x00}, {0xa2, 0x00}, {0xa3, 0x00},
+ {0xac, 0x20}, {0xa5, 0x00}, {0x60, 0x01}, {0xa7, 0x00},
+ {0x61, 0x01}, {0xa9, 0x00}, {0xaa, 0x00}, {0xab, 0x00},
+ {0xac, 0x00}, {0xad, 0x00}, {0xae, 0x00}, {0xaf, 0x00},
+ /* 0xb0*/
+ {0xb0, 0x00}, {0xb1, 0x00}, {0xb2, 0x00}, {0xb3, 0x00},
+ {0x7d, 0x01}, {0xb5, 0x00}, {0xb6, 0x00}, {0xb7, 0x00},
+ {0x7e, 0x01}, {0xb9, 0x00}, {0xba, 0x00}, {0xbb, 0x00},
+ {0x52, 0x01}, {0x53, 0x01}, {0x78, 0x01}, {0xbf, 0x00},
+ /* 0xc0*/
+ {0xc0, 0x00}, {0xc1, 0x00}, {0xc2, 0x00}, {0xc3, 0x00},
+ {0xc4, 0x00}, {0xc5, 0x00}, {0xc6, 0x00}, {0xc7, 0x00},
+ {0xc8, 0x00}, {0xc9, 0x00}, {0xca, 0x00}, {0xcb, 0x00},
+ {0xcc, 0x00}, {0xcd, 0x00}, {0xce, 0x00}, {0xcf, 0x00},
+ /* 0xd0*/
+ {0xd0, 0x00}, {0xd1, 0x00}, {0xd2, 0x00}, {0xd3, 0x00},
+ {0xd4, 0x00}, {0xd5, 0x00}, {0xd6, 0x00}, {0xd7, 0x00},
+ {0xd8, 0x00}, {0xd9, 0x00}, {0xda, 0x00}, {0xdb, 0x00},
+ {0xdc, 0x00}, {0xdd, 0x00}, {0xde, 0x00}, {0xdf, 0x00},
+ /* 0xe0*/
+ {0xe0, 0x00}, {0xe1, 0x00}, {0xe2, 0x00}, {0xe3, 0x00},
+ {0xe4, 0x00}, {0xe5, 0x00}, {0xe6, 0x00}, {0xe7, 0x00},
+ {0xe8, 0x00}, {0xe9, 0x00}, {0xea, 0x00}, {0xeb, 0x00},
+ {0xec, 0x00}, {0xed, 0x00}, {0xee, 0x00}, {0xef, 0x00},
+ /* 0xf0*/
+ {0xf0, 0x00}, {0xf1, 0x00}, {0xf2, 0x00}, {0xf3, 0x00},
+ {0xf4, 0x00}, {0xf5, 0x00}, {0xf6, 0x00}, {0xf7, 0x00},
+ {0xf8, 0x00}, {0xf9, 0x00}, {0xfa, 0x00}, {0xfb, 0x00},
+ {0xfc, 0x00}, {0xfd, 0x00}, {0xfe, 0x00}, {0xff, 0x00},


SHAR_EOF
true || echo 'restore of patch-2.0.37 failed'
fi

echo 'End of part 42'
echo 'File patch-2.0.37 is continued in part 43'
echo 43 > _shar_seq_.tmp

Thomas...@ciw.uni-karlsruhe.de

unread,
Jun 16, 1999, 3:00:00 AM6/16/99
to
Archive-name: v2.0/patch-2.0.37/part38

#!/bin/sh
# this is part 38 of a 45 - part archive


# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.0.37 continued
if test ! -r _shar_seq_.tmp; then
echo 'Please unpack part 1 first!'
exit 1
fi
(read Scheck

if test "$Scheck" != 38; then


echo Please unpack part "$Scheck" next!
exit 1
else
exit 0
fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.0.37'
else
echo 'x - continuing with patch-2.0.37'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.0.37' &&

X {
- ULONG wlval, flags;


- USHORT ioport;
- UCHAR bval;

+ printk ("DC390: Rst_Detect: laststat = %08lx\n", dc390_laststatus);
+ //DEBUG0(printk(KERN_INFO "RST_DETECT,");)
X
-#ifdef DC390_DEBUG0
- printk("RST_DETEC");
-#endif
- save_flags(flags);
- sti();
- wlval = jiffies + HZ;
- while( jiffies < wlval ); /* delay 1 sec */
-
- cli();


- ioport = pACB->IOPortBase;

- bval = DMA_IDLE_CMD;
- outb(bval,ioport+DMA_Cmd);
- bval = CLEAR_FIFO_CMD;
- outb(bval,ioport+ScsiCmd);

+ DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);


+ /* Unlock before ? */

+ /* delay a second */
+ { unsigned int msec = 1*1000; while (--msec) udelay(1000); }
+ DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
X
X if( pACB->ACBFlag & RESET_DEV )
X pACB->ACBFlag |= RESET_DONE;
@@ -1456,30 +1659,32 @@
X {
X pACB->ACBFlag |= RESET_DETECT;


X
- ResetDevParam( pACB );

-/* DoingSRB_Done( pACB ); ???? */
- RecoverSRB( pACB );
+ dc390_ResetDevParam( pACB );
+/* dc390_DoingSRB_Done( pACB ); ???? */
+ dc390_RecoverSRB( pACB );


X pACB->pActiveDCB = NULL;
X pACB->ACBFlag = 0;
- DoWaitingSRB( pACB );

+ dc390_DoWaitingSRB( pACB );


X }
- restore_flags(flags);
X return;
X }
X
X
-static void

-RequestSense( PACB pACB, PDCB pDCB, PSRB pSRB )
+static void __inline__
+dc390_RequestSense( PACB pACB, PDCB pDCB, PSRB pSRB )
X {
X PSCSICMD pcmd;
X
+ REMOVABLEDEBUG(printk (KERN_INFO "DC390: RequestSense (Cmd %02x, Id %02x, LUN %02x)\n",\
+ pSRB->CmdBlock[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN);)
+
X pSRB->SRBFlag |= AUTO_REQSENSE;
- pSRB->Segment0[0] = *((PULONG) &(pSRB->CmdBlock[0]));
- pSRB->Segment0[1] = *((PULONG) &(pSRB->CmdBlock[4]));
+ pSRB->Segment0[0] = (ULONG) pSRB->CmdBlock[0];
+ pSRB->Segment0[1] = (ULONG) pSRB->CmdBlock[4];
X pSRB->Segment1[0] = (ULONG) ((pSRB->ScsiCmdLen << 8) + pSRB->SGcount);
X pSRB->Segment1[1] = pSRB->TotalXferredLen;
X pSRB->AdaptStatus = 0;


- pSRB->TargetStatus = 0;

+ pSRB->TargetStatus = 0; /* SCSI_STAT_CHECKCOND; */
X
X pcmd = pSRB->pcmd;
X
@@ -1489,52 +1694,24 @@
X pSRB->SGcount = 1;
X pSRB->SGIndex = 0;
X
- *((PULONG) &(pSRB->CmdBlock[0])) = 0x00000003;
+ pSRB->CmdBlock[0] = REQUEST_SENSE;
X pSRB->CmdBlock[1] = pDCB->IdentifyMsg << 5;
- *((PUSHORT) &(pSRB->CmdBlock[4])) = sizeof(pcmd->sense_buffer);
+ (USHORT) pSRB->CmdBlock[2] = 0;
+ (USHORT) pSRB->CmdBlock[4] = sizeof(pcmd->sense_buffer);
X pSRB->ScsiCmdLen = 6;
X
X pSRB->TotalXferredLen = 0;
X pSRB->SGToBeXferLen = 0;
- if( DC390_StartSCSI( pACB, pDCB, pSRB ) )
- RewaitSRB( pDCB, pSRB );
+ if( dc390_StartSCSI( pACB, pDCB, pSRB ) )
+ dc390_RewaitSRB( pDCB, pSRB );
X }
X
X
-static void
-EnableMsgOut2( PACB pACB, PSRB pSRB )


-{
- USHORT ioport;
- UCHAR bval;

X

- ioport = pACB->IOPortBase;

- pSRB->MsgCnt = 1;
- bval = SET_ATN_CMD;
- outb(bval, ioport+ScsiCmd);
-}
-
-
-static void
-EnableMsgOut( PACB pACB, PSRB pSRB )
+static void __inline__
+dc390_InvalidCmd( PACB pACB )
X {
- pSRB->MsgOutBuf[0] = MSG_ABORT;
- EnableMsgOut2( pACB, pSRB );
-}
-
-
-static void
-DC390_InvalidCmd( PACB pACB )
-{
- UCHAR bval;
- USHORT ioport;
- PSRB pSRB;
-
- pSRB = pACB->pActiveDCB->pActiveSRB;
- if( pSRB->SRBState & (SRB_START_+SRB_MSGOUT) )
- {
- ioport = pACB->IOPortBase;
- bval = CLEAR_FIFO_CMD;
- outb(bval,(ioport+ScsiCmd));
- }
+ if( pACB->pActiveDCB->pActiveSRB->SRBState & (SRB_START_+SRB_MSGOUT) )
+ DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
X }
X
diff -u --recursive --new-file v2.0.36/linux/drivers/scsi/seagate.c linux/drivers/scsi/seagate.c
--- v2.0.36/linux/drivers/scsi/seagate.c Sun Nov 15 21:51:47 1998
+++ linux/drivers/scsi/seagate.c Sun Jun 13 10:21:03 1999
@@ -164,7 +164,7 @@
X } Signature;
X
X static const Signature signatures[] = {
-#ifdef CONFIG_SCSI_SEAGATE
+#if defined(CONFIG_SCSI_SEAGATE) || defined(CONFIG_SCSI_SEAGATE_MODULE)
X {"ST01 v1.7 (C) Copyright 1987 Seagate", 15, 37, SEAGATE},
X {"SCSI BIOS 2.00 (C) Copyright 1987 Seagate", 15, 40, SEAGATE},
X
diff -u --recursive --new-file v2.0.36/linux/drivers/scsi/sym53c416.c linux/drivers/scsi/sym53c416.c
--- v2.0.36/linux/drivers/scsi/sym53c416.c Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/sym53c416.c Sun Jun 13 10:21:03 1999
@@ -0,0 +1,805 @@
+/*
+ * sym53c416.c
+ * Low-level SCSI driver for sym53c416 chip.
+ * Copyright (C) 1998 Lieven Willems (lw_l...@hotmail.com)
+ *
+ * LILO command line usage: sym53c416=<PORTBASE>[,<IRQ>]
+ *


+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.

+ *


+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.

+ *
+ */
+

+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>


+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <asm/dma.h>
+#include <asm/system.h>

+#include <asm/io.h>
+#include <linux/blk.h>
+#include "scsi.h"
+#include "hosts.h"

+#include "sd.h"
+#include "sym53c416.h"
+
+#define VERSION_STRING "Version 1.0.0"
+
+#define TC_LOW 0x00 /* Transfer counter low */
+#define TC_MID 0x01 /* Transfer counter mid */
+#define SCSI_FIFO 0x02 /* SCSI FIFO register */
+#define COMMAND_REG 0x03 /* Command Register */
+#define STATUS_REG 0x04 /* Status Register (READ) */
+#define DEST_BUS_ID 0x04 /* Destination Bus ID (WRITE) */
+#define INT_REG 0x05 /* Interrupt Register (READ) */
+#define TOM 0x05 /* Time out multiplier (WRITE) */
+#define STP 0x06 /* Synchronous Transfer period */
+#define SYNC_OFFSET 0x07 /* Synchronous Offset */
+#define CONF_REG_1 0x08 /* Configuration register 1 */
+#define CONF_REG_2 0x0B /* Configuration register 2 */
+#define CONF_REG_3 0x0C /* Configuration register 3 */
+#define CONF_REG_4 0x0D /* Configuration register 4 */
+#define TC_HIGH 0x0E /* Transfer counter high */
+#define PIO_FIFO_1 0x10 /* PIO FIFO register 1 */
+#define PIO_FIFO_2 0x11 /* PIO FIFO register 2 */
+#define PIO_FIFO_3 0x12 /* PIO FIFO register 3 */
+#define PIO_FIFO_4 0x13 /* PIO FIFO register 4 */
+#define PIO_FIFO_CNT 0x14 /* PIO FIFO count */
+#define PIO_INT_REG 0x15 /* PIO interrupt register */
+#define CONF_REG_5 0x16 /* Configuration register 5 */
+#define FEATURE_EN 0x1D /* Feature Enable register */
+
+/* Configuration register 1 entries: */
+/* Bits 2-0: SCSI ID of host adapter */
+#define SCM 0x80 /* Slow Cable Mode */
+#define SRID 0x40 /* SCSI Reset Interrupt Disable */
+#define PTM 0x20 /* Parity Test Mode */
+#define EPC 0x10 /* Enable Parity Checking */
+#define CTME 0x08 /* Special Test Mode */
+
+/* Configuration register 2 entries: */
+#define FE 0x40 /* Features Enable */
+#define SCSI2 0x08 /* SCSI 2 Enable */
+#define TBPA 0x04 /* Target Bad Parity Abort */
+
+/* Configuration register 3 entries: */
+#define IDMRC 0x80 /* ID Message Reserved Check */
+#define QTE 0x40 /* Queue Tag Enable */
+#define CDB10 0x20 /* Command Descriptor Block 10 */
+#define FSCSI 0x10 /* FastSCSI */
+#define FCLK 0x08 /* FastClock */
+
+/* Configuration register 4 entries: */
+#define RBS 0x08 /* Register bank select */
+#define EAN 0x04 /* Enable Active Negotiation */
+
+/* Configuration register 5 entries: */
+#define LPSR 0x80 /* Lower Power SCSI Reset */
+#define IE 0x20 /* Interrupt Enable */
+#define LPM 0x02 /* Low Power Mode */
+#define WSE0 0x01 /* 0WS Enable */
+
+/* Interrupt register entries: */
+#define SRST 0x80 /* SCSI Reset */
+#define ILCMD 0x40 /* Illegal Command */
+#define DIS 0x20 /* Disconnect */
+#define BS 0x10 /* Bus Service */
+#define FC 0x08 /* Function Complete */
+#define RESEL 0x04 /* Reselected */
+#define SI 0x03 /* Selection Interrupt */
+
+/* Status Register Entries: */
+#define SCI 0x80 /* SCSI Core Int */
+#define GE 0x40 /* Gross Error */
+#define PE 0x20 /* Parity Error */
+#define TC 0x10 /* Terminal Count */
+#define VGC 0x08 /* Valid Group Code */
+#define PHBITS 0x07 /* Phase bits */
+
+/* PIO Interrupt Register Entries: */
+#define SCI 0x80 /* SCSI Core Int */
+#define PFI 0x40 /* PIO FIFO Interrupt */
+#define FULL 0x20 /* PIO FIFO Full */
+#define EMPTY 0x10 /* PIO FIFO Empty */
+#define CE 0x08 /* Collision Error */
+#define OUE 0x04 /* Overflow / Underflow error */
+#define FIE 0x02 /* Full Interrupt Enable */
+#define EIE 0x01 /* Empty Interrupt Enable */
+
+/* SYM53C416 SCSI phases (lower 3 bits of SYM53C416_STATUS_REG) */
+#define PHASE_DATA_OUT 0x00
+#define PHASE_DATA_IN 0x01
+#define PHASE_COMMAND 0x02
+#define PHASE_STATUS 0x03
+#define PHASE_RESERVED_1 0x04
+#define PHASE_RESERVED_2 0x05
+#define PHASE_MESSAGE_OUT 0x06
+#define PHASE_MESSAGE_IN 0x07
+
+/* SYM53C416 core commands */
+#define NOOP 0x00
+#define FLUSH_FIFO 0x01
+#define RESET_CHIP 0x02
+#define RESET_SCSI_BUS 0x03
+#define DISABLE_SEL_RESEL 0x45
+#define RESEL_SEQ 0x40
+#define SEL_WITHOUT_ATN_SEQ 0x41
+#define SEL_WITH_ATN_SEQ 0x42
+#define SEL_WITH_ATN_AND_STOP_SEQ 0x43
+#define ENABLE_SEL_RESEL 0x44
+#define SEL_WITH_ATN3_SEQ 0x46
+#define RESEL3_SEQ 0x47
+#define SND_MSG 0x20
+#define SND_STAT 0x21
+#define SND_DATA 0x22
+#define DISCONNECT_SEQ 0x23
+#define TERMINATE_SEQ 0x24
+#define TARGET_COMM_COMPLETE_SEQ 0x25
+#define DISCONN 0x27
+#define RECV_MSG_SEQ 0x28
+#define RECV_CMD 0x29
+#define RECV_DATA 0x2A
+#define RECV_CMD_SEQ 0x2B
+#define TARGET_ABORT_PIO 0x04
+#define TRANSFER_INFORMATION 0x10
+#define INIT_COMM_COMPLETE_SEQ 0x11
+#define MSG_ACCEPTED 0x12
+#define TRANSFER_PAD 0x18
+#define SET_ATN 0x1A
+#define RESET_ATN 0x1B
+#define ILLEGAL 0xFF
+
+#define PIO_MODE 0x80
+
+#define IO_RANGE 0x20 /* 0x00 - 0x1F */
+#define ID "sym53c416"
+#define PIO_SIZE 128 /* Size of PIO fifo is 128 bytes */
+
+#define READ_TIMEOUT 150
+#define WRITE_TIMEOUT 150
+
+#ifdef MODULE
+
+#define sym53c416_base sym53c416
+#define sym53c416_base_1 sym53c416_1
+#define sym53c416_base_2 sym53c416_2
+#define sym53c416_base_3 sym53c416_3
+
+static unsigned short sym53c416_base = 0;
+static unsigned int sym53c416_irq = 0;
+static unsigned short sym53c416_base_1 = 0;
+static unsigned int sym53c416_irq_1 = 0;
+static unsigned short sym53c416_base_2 = 0;
+static unsigned int sym53c416_irq_2 = 0;
+static unsigned short sym53c416_base_3 = 0;
+static unsigned int sym53c416_irq_3 = 0;
+
+#endif


+
+/* #define DEBUG */
+

+/* Macro for debugging purposes */


+
+#ifdef DEBUG
+#define DEB(x) x
+#else
+#define DEB(x)
+#endif
+

+#define MAXHOSTS 4
+
+enum phases
+ {
+ idle,
+ data_out,
+ data_in,
+ command_ph,
+ status_ph,
+ message_out,
+ message_in
+ };
+
+typedef struct
+ {
+ int base;
+ int irq;
+ int scsi_id;
+ } host;
+
+host hosts[MAXHOSTS] = {
+ {0, 0, SYM53C416_SCSI_ID},
+ {0, 0, SYM53C416_SCSI_ID},
+ {0, 0, SYM53C416_SCSI_ID},
+ {0, 0, SYM53C416_SCSI_ID}
+ };
+
+static int host_index = 0;
+
+static char info[120];
+
+static Scsi_Cmnd *current_command = NULL;
+
+struct proc_dir_entry proc_scsi_sym53c416 = {PROC_SCSI_SYM53C416, 7, ID, S_IFDIR | S_IRUGO | S_IXUGO, 2};
+
+int fastpio = 1;
+
+int probeaddrs[] = {0x200, 0x220, 0x240, 0};
+
+static void sym53c416_set_transfer_counter(int base, unsigned int len)
+ {
+ /* Program Transfer Counter */
+ outb(len & 0x0000FF, base + TC_LOW);
+ outb((len & 0x00FF00) >> 8, base + TC_MID);
+ outb((len & 0xFF0000) >> 16, base + TC_HIGH);
+ }
+
+/* Returns the number of bytes read */
+static __inline__ unsigned int sym53c416_read(int base, unsigned char *buffer, unsigned int len)
+ {
+ unsigned int orig_len = len;
+ unsigned long flags = 0;
+ unsigned int bytes_left;
+ int i;
+ int timeout = READ_TIMEOUT;
+
+ /* Do transfer */
+ save_flags(flags);
+ cli();
+ while(len && timeout)
+ {
+ bytes_left = inb(base + PIO_FIFO_CNT); /* Number of bytes in the PIO FIFO */
+ if(fastpio && bytes_left > 3)
+ {
+ insl(base + PIO_FIFO_1, buffer, bytes_left >> 2);
+ buffer += bytes_left & 0xFC;
+ len -= bytes_left & 0xFC;
+ }
+ else if(bytes_left > 0)
+ {
+ len -= bytes_left;
+ for(; bytes_left > 0; bytes_left--)
+ *(buffer++) = inb(base + PIO_FIFO_1);
+ }
+ else
+ {
+ i = jiffies + timeout;
+ restore_flags(flags);
+ while(jiffies < i && (inb(base + PIO_INT_REG) & EMPTY) && timeout)
+ if(inb(base + PIO_INT_REG) & SCI)
+ timeout = 0;
+ save_flags(flags);
+ cli();
+ if(inb(base + PIO_INT_REG) & EMPTY)
+ timeout = 0;
+ }
+ }
+ restore_flags(flags);
+ return orig_len - len;
+ }
+
+/* Returns the number of bytes written */
+static __inline__ unsigned int sym53c416_write(int base, unsigned char *buffer, unsigned int len)
+ {
+ unsigned int orig_len = len;
+ unsigned long flags = 0;
+ unsigned int bufferfree;
+ unsigned int i;
+ unsigned int timeout = WRITE_TIMEOUT;
+
+ /* Do transfer */
+ save_flags(flags);
+ cli();
+ while(len && timeout)
+ {
+ bufferfree = PIO_SIZE - inb(base + PIO_FIFO_CNT);
+ if(bufferfree > len)
+ bufferfree = len;
+ if(fastpio && bufferfree > 3)
+ {
+ outsl(base + PIO_FIFO_1, buffer, bufferfree >> 2);
+ buffer += bufferfree & 0xFC;
+ len -= bufferfree & 0xFC;
+ }
+ else if(bufferfree > 0)
+ {
+ len -= bufferfree;
+ for(; bufferfree > 0; bufferfree--)
+ outb(*(buffer++), base + PIO_FIFO_1);
+ }
+ else
+ {
+ i = jiffies + timeout;
+ restore_flags(flags);
+ while(jiffies < i && (inb(base + PIO_INT_REG) & FULL) && timeout)


+ ;
+ save_flags(flags);
+ cli();

+ if(inb(base + PIO_INT_REG) & FULL)
+ timeout = 0;
+ }
+ }
+ restore_flags(flags);
+ return orig_len - len;
+ }
+
+static void sym53c416_intr_handle(int irq, void *dev_id, struct pt_regs *regs)
+ {
+ int base = 0;
+ int i;
+ unsigned long flags = 0;
+ unsigned char status_reg, pio_int_reg, int_reg;
+ struct scatterlist *sglist;
+ unsigned int sgcount;
+ unsigned int tot_trans = 0;
+
+ /* We search the base address of the host adapter which caused the interrupt */
+ for(i = 0; i < host_index && !base; i++)
+ if(irq == hosts[i].irq)
+ base = hosts[i].base;
+ /* If no adapter found, we cannot handle the interrupt. Leave a message */
+ /* and continue. This should never happen... */
+ if(!base)
+ {
+ printk("sym53c416: No host adapter defined for interrupt %d\n", irq);
+ return;
+ }
+ /* Now we have the base address and we can start handling the interrupt */
+ save_flags(flags);
+ cli();
+ status_reg = inb(base + STATUS_REG);
+ pio_int_reg = inb(base + PIO_INT_REG);
+ int_reg = inb(base + INT_REG);
+ restore_flags(flags);
+
+ /* First, we handle error conditions */
+ if(int_reg & SCI) /* SCSI Reset */
+ {
+ printk("sym53c416: Warning: Reset received\n");
+ current_command->SCp.phase = idle;
+ current_command->result = DID_RESET << 16;
+ current_command->scsi_done(current_command);
+ return;
+ }
+ if(int_reg & ILCMD) /* Illegal Command */
+ {
+ printk("sym53c416: Warning: Illegal Command: 0x%02x\n", inb(base + COMMAND_REG));
+ current_command->SCp.phase = idle;
+ current_command->result = DID_ERROR << 16;
+ current_command->scsi_done(current_command);
+ return;
+ }
+ if(status_reg & GE) /* Gross Error */
+ {
+ printk("sym53c416: Warning: Gross Error\n");
+ current_command->SCp.phase = idle;
+ current_command->result = DID_ERROR << 16;
+ current_command->scsi_done(current_command);
+ return;
+ }
+ if(status_reg & PE) /* Parity Error */
+ {
+ printk("sym53c416: Warning: Parity Error\n");
+ current_command->SCp.phase = idle;
+ current_command->result = DID_PARITY << 16;
+ current_command->scsi_done(current_command);
+ return;
+ }
+ if(pio_int_reg & (CE | OUE))
+ {
+ printk("sym53c416: Warning: PIO Interrupt Error\n");
+ current_command->SCp.phase = idle;
+ current_command->result = DID_ERROR << 16;
+ current_command->scsi_done(current_command);
+ return;
+ }
+ if(int_reg & DIS) /* Disconnect */
+ {
+ if(current_command->SCp.phase != message_in)
+ current_command->result = DID_NO_CONNECT << 16;
+ else
+ current_command->result = (current_command->SCp.Status & 0xFF) | ((current_command->SCp.Message & 0xFF) << 8) | (DID_OK << 16);
+ current_command->SCp.phase = idle;
+ current_command->scsi_done(current_command);
+ return;
+ }
+ /* Now we handle SCSI phases */
+ switch(status_reg & PHBITS) /* Filter SCSI phase out of status reg */
+ {
+ case PHASE_DATA_OUT:
+ {
+ if(int_reg & BS)
+ {
+ current_command->SCp.phase = data_out;
+ outb(FLUSH_FIFO, base + COMMAND_REG);
+ sym53c416_set_transfer_counter(base, current_command->request_bufflen);
+ outb(TRANSFER_INFORMATION | PIO_MODE, base + COMMAND_REG);
+ if(!current_command->use_sg)
+ tot_trans = sym53c416_write(base, current_command->request_buffer, current_command->request_bufflen);
+ else
+ {
+ sgcount = current_command->use_sg;
+ sglist = current_command->request_buffer;
+ while(sgcount--)
+ {
+ tot_trans += sym53c416_write(base, sglist->address, sglist->length);
+ sglist++;
+ }
+ }
+ if(tot_trans < current_command->underflow)
+ printk("sym53c416: Warning: underflow, wrote %d bytes, request for %d bytes\n", tot_trans, current_command->underflow);
+ }
+ break;
+ }
+ case PHASE_DATA_IN:
+ {
+ if(int_reg & BS)
+ {
+ current_command->SCp.phase = data_in;
+ outb(FLUSH_FIFO, base + COMMAND_REG);
+ sym53c416_set_transfer_counter(base, current_command->request_bufflen);
+ outb(TRANSFER_INFORMATION | PIO_MODE, base + COMMAND_REG);
+ if(!current_command->use_sg)
+ tot_trans = sym53c416_read(base, current_command->request_buffer, current_command->request_bufflen);
+ else
+ {
+ sgcount = current_command->use_sg;
+ sglist = current_command->request_buffer;
+ while(sgcount--)
+ {
+ tot_trans += sym53c416_read(base, sglist->address, sglist->length);
+ sglist++;
+ }
+ }
+ if(tot_trans < current_command->underflow)
+ printk("sym53c416: Warning: underflow, read %d bytes, request for %d bytes\n", tot_trans, current_command->underflow);
+ }
+ break;
+ }
+ case PHASE_COMMAND:
+ {
+ current_command->SCp.phase = command_ph;
+ printk("sym53c416: Warning: Unknown interrupt in command phase\n");
+ break;
+ }
+ case PHASE_STATUS:
+ {
+ current_command->SCp.phase = status_ph;
+ outb(FLUSH_FIFO, base + COMMAND_REG);
+ outb(INIT_COMM_COMPLETE_SEQ, base + COMMAND_REG);
+ break;
+ }
+ case PHASE_RESERVED_1:
+ case PHASE_RESERVED_2:
+ {
+ printk("sym53c416: Warning: Reserved phase\n");
+ break;
+ }
+ case PHASE_MESSAGE_OUT:
+ {
+ current_command->SCp.phase = message_out;
+ outb(SET_ATN, base + COMMAND_REG);
+ outb(MSG_ACCEPTED, base + COMMAND_REG);
+ break;
+ }
+ case PHASE_MESSAGE_IN:
+ {
+ current_command->SCp.phase = message_in;
+ current_command->SCp.Status = inb(base + SCSI_FIFO);
+ current_command->SCp.Message = inb(base + SCSI_FIFO);
+ if(current_command->SCp.Message == SAVE_POINTERS || current_command->SCp.Message == DISCONNECT)
+ outb(SET_ATN, base + COMMAND_REG);
+ outb(MSG_ACCEPTED, base + COMMAND_REG);


+ break;
+ }
+ }
+ }
+

+static void sym53c416_init(int base, int scsi_id)
+ {
+ outb(RESET_CHIP, base + COMMAND_REG);
+ outb(NOOP, base + COMMAND_REG);
+ outb(0x99, base + TOM); /* Time out of 250 ms */
+ outb(0x05, base + STP);
+ outb(0x00, base + SYNC_OFFSET);
+ outb(EPC | scsi_id, base + CONF_REG_1);
+ outb(FE | SCSI2 | TBPA, base + CONF_REG_2);
+ outb(IDMRC | QTE | CDB10 | FSCSI | FCLK, base + CONF_REG_3);
+ outb(0x83 | EAN, base + CONF_REG_4);
+ outb(IE | WSE0, base + CONF_REG_5);
+ outb(0, base + FEATURE_EN);
+ }
+
+static int sym53c416_probeirq(int base, int scsi_id)
+ {
+ int irq, irqs, i;
+
+ /* Clear interrupt register */
+ inb(base + INT_REG);
+ /* Start probing for irq's */
+ irqs = probe_irq_on();
+ /* Reinit chip */
+ sym53c416_init(base, scsi_id);
+ /* Cause interrupt */
+ outb(NOOP, base + COMMAND_REG);
+ outb(ILLEGAL, base + COMMAND_REG);
+ outb(0x07, base + DEST_BUS_ID);
+ outb(0x00, base + DEST_BUS_ID);
+ /* Wait for interrupt to occur */
+ i = jiffies + 20;
+ while(i > jiffies && !(inb(base + STATUS_REG) & SCI))
+ barrier();
+ if(i <= jiffies) /* timed out */
+ return 0;
+ /* Get occurred irq */
+ irq = probe_irq_off(irqs);
+ sym53c416_init(base, scsi_id);
+ return irq;
+ }
+
+/* Setup: sym53c416=base,irq */
+void sym53c416_setup(char *str, int *ints)
+ {
+ int i;
+
+ if(host_index >= MAXHOSTS)
+ {
+ printk("sym53c416.c: Too many hosts defined\n");
+ }
+ else
+ {
+ if(ints[0] < 1 || ints[0] > 2)
+ {
+ printk("sym53c416.c: Wrong number of parameters:\n");
+ printk("sym53c416.c: usage: sym53c416=<base>[,<irq>]\n");
+ }
+ else
+ {
+ for(i = 0; i < host_index && i >= 0; i++)
+ if(hosts[i].base == ints[1])
+ i = -2;
+ if(i >= 0)
+ {
+ hosts[host_index].base = ints[1];
+ hosts[host_index].irq = (ints[0] == 2)? ints[2] : 0;
+ host_index++;


+ }
+ }
+ }
+ }
+

+static int sym53c416_test(int base)
+ {
+ outb(RESET_CHIP, base + COMMAND_REG);
+ outb(NOOP, base + COMMAND_REG);
+ if(inb(base + COMMAND_REG) != NOOP)
+ return 0;
+ if(!inb(base + TC_HIGH) || inb(base + TC_HIGH) == 0xFF)
+ return 0;
+ if((inb(base + PIO_INT_REG) & (FULL | EMPTY | CE | OUE | FIE | EIE)) != EMPTY)
+ return 0;


+ return 1;
+ }
+

+void sym53c416_probe(void)
+ {
+ int *base = probeaddrs;
+ int ints[2];
+
+ ints[0] = 1;
+ for(; *base; base++)
+ if(!check_region(*base, IO_RANGE) && sym53c416_test(*base))
+ {
+ ints[1] = *base;
+ sym53c416_setup(NULL, ints);
+ }
+ }
+
+int sym53c416_detect(Scsi_Host_Template *tpnt)
+ {
+ unsigned long flags;
+ struct Scsi_Host * shpnt = NULL;
+ int i;
+ int count;
+
+#ifdef MODULE
+ int ints[3];
+
+ ints[0] = 2;
+ if(sym53c416_base)
+ {
+ ints[1] = sym53c416_base;
+ ints[2] = sym53c416_irq;
+ sym53c416_setup(NULL, ints);
+ }
+ if(sym53c416_base_1)
+ {
+ ints[1] = sym53c416_base_1;
+ ints[2] = sym53c416_irq_1;
+ sym53c416_setup(NULL, ints);
+ }
+ if(sym53c416_base_2)
+ {
+ ints[1] = sym53c416_base_2;
+ ints[2] = sym53c416_irq_2;
+ sym53c416_setup(NULL, ints);
+ }
+ if(sym53c416_base_3)
+ {
+ ints[1] = sym53c416_base_3;
+ ints[2] = sym53c416_irq_3;
+ sym53c416_setup(NULL, ints);
+ }
+#endif
+
+ printk("sym53c416.c: %s\n", VERSION_STRING);
+
+ sym53c416_probe();
+
+ /* Now we register and set up each host adapter found... */
+ for(count = 0, i = 0; i < host_index; i++)
+ if(!sym53c416_test(hosts[i].base))
+ printk("No sym53c416 found at address 0x%03x\n", hosts[i].base);
+ else
+ {
+ if(hosts[i].irq == 0)
+ /* We don't have an irq yet, so we should probe for one */
+ if((hosts[i].irq = sym53c416_probeirq(hosts[i].base, hosts[i].scsi_id)) == 0)
+ printk("irq autoprobing failed for sym53c416 at address 0x%03x\n", hosts[i].base);
+ if(hosts[i].irq && !check_region(hosts[i].base, IO_RANGE))


+ {
+ shpnt = scsi_register(tpnt, 0);

+ save_flags(flags);
+ cli();
+ /* Request for specified IRQ */
+ if(request_irq(hosts[i].irq, sym53c416_intr_handle, 0, ID, NULL))
+ {
+ restore_flags(flags);
+ printk("Unable to assign IRQ %d\n", hosts[i].irq);
+ scsi_unregister(shpnt);
+ }
+ else
+ {
+ /* Inform the kernel of our IO range */
+ request_region(hosts[i].base, IO_RANGE, ID);
+ shpnt->unique_id = hosts[i].base;
+ shpnt->io_port = hosts[i].base;
+ shpnt->n_io_port = IO_RANGE;
+ shpnt->irq = hosts[i].irq;
+ shpnt->this_id = hosts[i].scsi_id;
+ sym53c416_init(hosts[i].base, hosts[i].scsi_id);
+ count++;


+ restore_flags(flags);
+ }
+ }
+ }

+ return count;
+ }
+
+const char *sym53c416_info(struct Scsi_Host *SChost)
+ {
+ int i;
+ int base = SChost->io_port;
+ int irq = SChost->irq;
+ int scsi_id = 0;
+ int rev = inb(base + TC_HIGH);
+
+ for(i = 0; i < host_index; i++)
+ if(hosts[i].base == base)
+ scsi_id = hosts[i].scsi_id;
+ sprintf(info, "Symbios Logic 53c416 (rev. %d) at 0x%03x, irq %d, SCSI-ID %d, %s pio", rev, base, irq, scsi_id, (fastpio)? "fast" : "slow");
+ return info;
+ }
+
+int sym53c416_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
+ {
+ int base;
+ unsigned long flags = 0;
+ int i;
+
+ /* Store base register as we can have more than one controller in the system */
+ base = SCpnt->host->io_port;
+ current_command = SCpnt; /* set current command */
+ current_command->scsi_done = done; /* set ptr to done function */
+ current_command->SCp.phase = command_ph; /* currect phase is the command phase */
+ current_command->SCp.Status = 0;
+ current_command->SCp.Message = 0;


+
+ save_flags(flags);
+ cli();

+ outb(SCpnt->target, base + DEST_BUS_ID); /* Set scsi id target */
+ outb(FLUSH_FIFO, base + COMMAND_REG); /* Flush SCSI and PIO FIFO's */
+ /* Write SCSI command into the SCSI fifo */
+ for(i = 0; i < SCpnt->cmd_len; i++)
+ outb(SCpnt->cmnd[i], base + SCSI_FIFO);
+ /* Start selection sequence */
+ outb(SEL_WITHOUT_ATN_SEQ, base + COMMAND_REG);
+ /* Now an interrupt will be generated which we will catch in out interrupt routine */
+ restore_flags(flags);


+ return 0;
+ }
+

+static void internal_done(Scsi_Cmnd *SCpnt)


+ {
+ SCpnt->SCp.Status++;
+ }
+

+int sym53c416_command(Scsi_Cmnd *SCpnt)
+ {
+ sym53c416_queuecommand(SCpnt, internal_done);


+ SCpnt->SCp.Status = 0;

+ while(!SCpnt->SCp.Status)


+ barrier();
+ return SCpnt->result;
+ }
+

+int sym53c416_abort(Scsi_Cmnd *SCpnt)
+ {
+ printk("sym53c416_abort\n");
+
+ /* We don't know how to abort for the moment */
+ return SCSI_ABORT_SNOOZE;
+ }
+
+int sym53c416_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags)
+ {
+ int base;
+ int scsi_id = -1;
+ int i;
+
+ printk("sym53c416_reset\n");
+ base = SCpnt->host->io_port;
+ /* search scsi_id */
+ for(i = 0; i < host_index && scsi_id != -1; i++)
+ if(hosts[i].base == base)
+ scsi_id = hosts[i].scsi_id;
+ outb(RESET_CHIP, base + COMMAND_REG);
+ outb(NOOP | PIO_MODE, base + COMMAND_REG);
+ outb(RESET_SCSI_BUS, base + COMMAND_REG);
+ sym53c416_init(base, scsi_id);
+ return SCSI_RESET_PENDING;
+ }
+
+int sym53c416_bios_param(Disk *disk, kdev_t dev, int *ip)
+ {
+ int size;
+
+ size = disk->capacity;
+ ip[0] = 64; /* heads */
+ ip[1] = 32; /* sectors */
+ if((ip[2] = size >> 11) > 1024) /* cylinders, test for big disk */
+ {
+ ip[0] = 255; /* heads */
+ ip[1] = 63; /* sectors */
+ ip[2] = size / (255 * 63); /* cylinders */


+ }
+ return 0;
+ }
+

+/* Loadable module support */
+#ifdef MODULE
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,26)
+MODULE_AUTHOR("Lieven Willems");
+MODULE_PARM(sym53c416, "1-2i");
+MODULE_PARM(sym53c416_1, "1-2i");
+MODULE_PARM(sym53c416_2, "1-2i");
+MODULE_PARM(sym53c416_3, "1-2i");
+#endif
+
+Scsi_Host_Template driver_template = SYM53C416;
+
+#include "scsi_module.c"
+#endif
diff -u --recursive --new-file v2.0.36/linux/drivers/scsi/sym53c416.h linux/drivers/scsi/sym53c416.h
--- v2.0.36/linux/drivers/scsi/sym53c416.h Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/sym53c416.h Sun Jun 13 10:21:03 1999
@@ -0,0 +1,91 @@
+/*
+ * sym53c416.h
+ *
+ * Copyright (C) 1998 Lieven Willems (lw_l...@hotmail.com)
+ *


+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.

+ *


+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.

+ *
+ */
+

+#ifndef _SYM53C416_H
+#define _SYM53C416_H
+
+#if !defined(LINUX_VERSION_CODE)
+#include <linux/version.h>
+#endif
+
+#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))


+
+#include <linux/types.h>
+#include <linux/kdev_t.h>
+

+#define SYM53C416_SCSI_ID 7
+
+extern struct proc_dir_entry proc_scsi_sym53c416;
+
+extern int sym53c416_detect(Scsi_Host_Template *);
+extern const char *sym53c416_info(struct Scsi_Host *);
+extern int sym53c416_command(Scsi_Cmnd *);
+extern int sym53c416_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+extern int sym53c416_abort(Scsi_Cmnd *);
+extern int sym53c416_reset(Scsi_Cmnd *, unsigned int);
+extern int sym53c416_bios_param(Disk *, kdev_t, int *);
+extern void sym53c416_setup(char *str, int *ints);
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,75)
+
+#define SYM53C416 { \
+ proc_dir: &proc_scsi_sym53c416, \
+ name: "Symbios Logic 53c416", \
+ detect: sym53c416_detect, \
+ info: sym53c416_info, \
+ command: sym53c416_command, \
+ queuecommand: sym53c416_queuecommand, \
+ abort: sym53c416_abort, \
+ reset: sym53c416_reset, \
+ bios_param: sym53c416_bios_param, \
+ can_queue: 1, \
+ this_id: SYM53C416_SCSI_ID, \
+ sg_tablesize: 32, \
+ cmd_per_lun: 1, \
+ unchecked_isa_dma: 1, \
+ use_clustering: ENABLE_CLUSTERING \
+ }
+
+#else
+
+#define SYM53C416 { \
+ NULL, \
+ NULL, \
+ &proc_scsi_sym53c416, \
+ NULL, \
+ "Symbios Logic 53c416", \
+ sym53c416_detect, \
+ NULL, \
+ sym53c416_info, \
+ sym53c416_command, \
+ sym53c416_queuecommand, \
+ sym53c416_abort, \
+ sym53c416_reset, \
+ NULL, \
+ sym53c416_bios_param, \
+ 1, \
+ SYM53C416_SCSI_ID, \
+ 32, /* ???? */ \
+ 1, \
+ 0, \
+ 1, \
+ ENABLE_CLUSTERING \
+ }
+
+#endif
+
+#endif
diff -u --recursive --new-file v2.0.36/linux/drivers/scsi/tmscsim.c linux/drivers/scsi/tmscsim.c
--- v2.0.36/linux/drivers/scsi/tmscsim.c Mon Jul 13 13:46:36 1998
+++ linux/drivers/scsi/tmscsim.c Sun Jun 13 10:21:03 1999
@@ -5,36 +5,141 @@
X * Bus Master Host Adapter *
X * (C)Copyright 1995-1996 Tekram Technology Co., Ltd. *
X ***********************************************************************/
-/* Minor enhancements and bugfixes by *
- * Kurt Garloff <K.Ga...@ping.de> *
+/* (C) Copyright: put under GNU GPL in 10/96 *
+*************************************************************************/
+/* $Id: tmscsim.c,v 2.16 1998/12/25 17:54:44 garloff Exp $ */
+/* Enhancements and bugfixes by *
+ * Kurt Garloff <ku...@garloff.de> *
X ***********************************************************************/
X /* HISTORY: *
X * *
X * REV# DATE NAME DESCRIPTION *
- * 1.00 04/24/96 CLH First release *
- * 1.01 06/12/96 CLH Fixed bug of Media Change for Removable *
+ * 1.00 96/04/24 CLH First release *
+ * 1.01 96/06/12 CLH Fixed bug of Media Change for Removable *
X * Device, scan all LUN. Support Pre2.0.10 *
- * 1.02 06/18/96 CLH Fixed bug of Command timeout ... *
- * 1.03 09/25/96 KG Added tmscsim_proc_info() *
- * 1.04 10/11/96 CLH Updating for support KV 2.0.x *
- * 1.05 10/18/96 KG Fixed bug in DC390_abort(null ptr deref)*
- * 1.06 10/25/96 KG Fixed module support *
- * 1.07 11/09/96 KG Fixed tmscsim_proc_info() *
- * 1.08 11/18/96 KG Fixed null ptr in DC390_Disconnect() *
- * 1.09 11/30/96 KG Added register the allocated IO space *
- * 1.10 12/05/96 CLH Modified tmscsim_proc_info(), and reset *
+ * 1.02 96/06/18 CLH Fixed bug of Command timeout ... *
+ * 1.03 96/09/25 KG Added tmscsim_proc_info() *
+ * 1.04 96/10/11 CLH Updating for support KV 2.0.x *
+ * 1.05 96/10/18 KG Fixed bug in DC390_abort(null ptr deref)*
+ * 1.06 96/10/25 KG Fixed module support *
+ * 1.07 96/11/09 KG Fixed tmscsim_proc_info() *
+ * 1.08 96/11/18 KG Fixed null ptr in DC390_Disconnect() *
+ * 1.09 96/11/30 KG Added register the allocated IO space *
+ * 1.10 96/12/05 CLH Modified tmscsim_proc_info(), and reset *
X * pending interrupt in DC390_detect() *
- * 1.11 02/05/97 KG/CLH Fixeds problem with partitions greater *
- * than 1GB *
+ * 1.11 97/02/05 KG/CLH Fixeds problem with partitions greater *
+ * than 1GB *
+ * 1.12 98/02/15 MJ Rewritten PCI probing *
+ * 1.13 98/04/08 KG Support for non DC390, __initfunc decls,*
+ * changed max devs from 10 to 16 *
+ * 1.14a 98/05/05 KG Dynamic DCB allocation, add-single-dev *
+ * for LUNs if LUN_SCAN (BIOS) not set *
+ * runtime config using /proc interface *
+ * 1.14b 98/05/06 KG eliminated cli (); sti (); spinlocks *
+ * 1.14c 98/05/07 KG 2.0.x compatibility *
+ * 1.20a 98/05/07 KG changed names of funcs to be consistent *
+ * DC390_ (entry points), dc390_ (internal)*
+ * reworked locking *
+ * 1.20b 98/05/12 KG bugs: version, kfree, _ctmp *
+ * debug output *
+ * 1.20c 98/05/12 KG bugs: kfree, parsing, EEpromDefaults *
+ * 1.20d 98/05/14 KG bugs: list linkage, clear flag after *
+ * reset on startup, code cleanup *
+ * 1.20e 98/05/15 KG spinlock comments, name space cleanup *
+ * pLastDCB now part of ACB structure *
+ * added stats, timeout for 2.1, TagQ bug *
+ * RESET and INQUIRY interface commands *
+ * 1.20f 98/05/18 KG spinlocks fixes, max_lun fix, free DCBs *
+ * for missing LUNs, pending int *
+ * 1.20g 98/05/19 KG Clean up: Avoid short *
+ * 1.20h 98/05/21 KG Remove AdaptSCSIID, max_lun ... *
+ * 1.20i 98/05/21 KG Aiiie: Bug with TagQMask *
+ * 1.20j 98/05/24 KG Handle STAT_BUSY, handle pACB->pLinkDCB *
+ * == 0 in remove_dev and DoingSRB_Done *
+ * 1.20k 98/05/25 KG DMA_INT (experimental) *
+ * 1.20l 98/05/27 KG remove DMA_INT; DMA_IDLE cmds added; *
+ * 1.20m 98/06/10 KG glitch configurable; made some global *
+ * vars part of ACB; use DC390_readX *
+ * 1.20n 98/06/11 KG startup params *
+ * 1.20o 98/06/15 KG added TagMaxNum to boot/module params *
+ * Device Nr -> Idx, TagMaxNum power of 2 *
+ * 1.20p 98/06/17 KG Docu updates. Reset depends on settings *
+ * pci_set_master added; 2.0.xx: pcibios_* *
+ * used instead of MechNum things ... *
+ * 1.20q 98/06/23 KG Changed defaults. Added debug code for *
+ * removable media and fixed it. TagMaxNum *
+ * fixed for DC390. Locking: ACB, DRV for *
+ * better IRQ sharing. Spelling: Queueing *
+ * Parsing and glitch_cfg changes. Display *
+ * real SyncSpeed value. Made DisConn *
+ * functional (!) *
+ * 1.20r 98/06/30 KG Debug macros, allow disabling DsCn, set *
+ * BIT4 in CtrlR4, EN_PAGE_INT, 2.0 module *
+ * param -1 fixed. *
+ * 1.20s 98/08/20 KG Debug info on abort(), try to check PCI,*
+ * phys_to_bus instead of phys_to_virt, *
+ * fixed sel. process, fixed locking, *
+ * added MODULE_XXX infos, changed IRQ *
+ * request flags, disable DMA_INT *
+ * 1.20t 98/09/07 KG TagQ report fixed; Write Erase DMA Stat;*
+ * initfunc -> __init; better abort; *
+ * Timeout for XFER_DONE & BLAST_COMPLETE; *
+ * Allow up to 33 commands being processed *
+ * 2.0a 98/10/14 KG Max Cmnds back to 17. DMA_Stat clearing *
+ * all flags. Clear within while() loops *
+ * in DataIn_0/Out_0. Null ptr in dumpinfo *
+ * for pSRB==0. Better locking during init.*
+ * bios_param() now respects part. table. *
+ * 2.0b 98/10/24 KG Docu fixes. Timeout Msg in DMA Blast. *
+ * Disallow illegal idx in INQUIRY/REMOVE *
+ * 2.0c 98/11/19 KG Cleaned up detect/init for SMP boxes, *
+ * Write Erase DMA (1.20t) caused problems *
+ * 2.0d 98/12/25 KG Christmas release ;-) Message handling *
+ * competely reworked. Handle target ini- *
+ * tiated SDTR correctly. *
X ***********************************************************************/
X
+/* Uncomment SA_INTERRUPT, if the driver refuses to share its IRQ with other devices */
+#define DC390_IRQ SA_SHIRQ /* | SA_INTERRUPT */
X
-#define DC390_DEBUG
+/* DEBUG options */
+//#define DC390_DEBUG0
+//#define DC390_DEBUG1
+//#define DC390_DCBDEBUG
+//#define DC390_PARSEDEBUG
+//#define DC390_REMOVABLEDEBUG
X
-#define SCSI_MALLOC
+/* Debug definitions */
+#ifdef DC390_DEBUG0
+# define DEBUG0(x) x;
+#else
+# define DEBUG0(x)
+#endif
+#ifdef DC390_DEBUG1
+# define DEBUG1(x) x;
+#else
+# define DEBUG1(x)
+#endif
+#ifdef DC390_DCBDEBUG
+# define DCBDEBUG(x) x;
+#else
+# define DCBDEBUG(x)
+#endif
+#ifdef DC390_PARSEDEBUG
+# define PARSEDEBUG(x) x;
+#else
+# define PARSEDEBUG(x)
+#endif
+#ifdef DC390_REMOVABLEDEBUG
+# define REMOVABLEDEBUG(x) x;
+#else
+# define REMOVABLEDEBUG(x)
+#endif
+#define DCBDEBUG1(x)
X
+/* Includes */
X #ifdef MODULE
-#include <linux/module.h>
+# include <linux/module.h>
X #endif
X
X #include <asm/dma.h>
@@ -46,23 +151,17 @@
X #include <linux/errno.h>
X #include <linux/kernel.h>
X #include <linux/ioport.h>


-#include <linux/bios32.h>
X #include <linux/pci.h>

X #include <linux/proc_fs.h>
X #include <linux/string.h>
+#include <linux/ctype.h>
X #include <linux/mm.h>
X #include <linux/config.h>
-
X #include <linux/version.h>
-#if LINUX_VERSION_CODE < 66354 /* 1.3.50 */
-#include "../block/blk.h"
-#else
X #include <linux/blk.h>
-#endif
X

X #include "scsi.h"
X #include "hosts.h"

-#include "tmscsim.h"
X #include "constants.h"
X #include "sd.h"
X #include <linux/stat.h>
@@ -71,112 +170,530 @@
X
X #define PCI_DEVICE_ID_AMD53C974 PCI_DEVICE_ID_AMD_SCSI
X
+/* Locking */
X
-#ifndef VERSION_ELF_1_2_13
-struct proc_dir_entry proc_scsi_tmscsim ={
- PROC_SCSI_DC390T, 7 ,"tmscsim",
- S_IFDIR | S_IRUGO | S_IXUGO, 2
- };
+/* Note: Starting from 2.1.9x, the mid-level scsi code issues a
+ * spinlock_irqsave (&io_request_lock) before calling the driver's
+ * routines, so we don't need to lock.
+ * TODO: Verify, if we are locked in every case!
+ * The policy 3, let the midlevel scsi code do the io_request_locks
+ * and us locking on a driver specific lock, shouldn't hurt anybody; it
+ * just causes a minor performance degradation for setting the locks.
+ */
+
+/* spinlock things
+ * level 3: lock on both adapter specific locks and (global) io_request_lock
+ * level 2: lock on adapter specific locks only
+ * level 1: rely on the locking of the mid level code (io_request_lock)
+ * undef : traditional save_flags; cli; restore_flags;
+ */
+
+//#define DEBUG_SPINLOCKS 2 /* Set to 0, 1 or 2 in include/asm/spinlock.h */
+
+#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,30)
+# include <linux/init.h>
+# include <asm/spinlock.h>
X #endif
X
-static USHORT DC390_StartSCSI( PACB pACB, PDCB pDCB, PSRB pSRB );
-static void DC390_DataOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
-static void DC390_DataIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
-static void DC390_Command_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
-static void DC390_Status_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
-static void DC390_MsgOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
-static void DC390_MsgIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
-static void DC390_DataOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
-static void DC390_DataInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
-static void DC390_CommandPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
-static void DC390_StatusPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
-static void DC390_MsgOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
-static void DC390_MsgInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
-static void DC390_Nop_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
-static void DC390_Nop_1( PACB pACB, PSRB pSRB, PUCHAR psstatus);
-
-static void SetXferRate( PACB pACB, PDCB pDCB );
-static void DC390_Disconnect( PACB pACB );
-static void DC390_Reselect( PACB pACB );
-static void SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB );
-static void DoingSRB_Done( PACB pACB );
-static void DC390_ScsiRstDetect( PACB pACB );
-static void DC390_ResetSCSIBus( PACB pACB );
-static void RequestSense( PACB pACB, PDCB pDCB, PSRB pSRB );
-static void EnableMsgOut2( PACB pACB, PSRB pSRB );
-static void EnableMsgOut( PACB pACB, PSRB pSRB );
-static void DC390_InvalidCmd( PACB pACB );
X
-int DC390_initAdapter( PSH psh, ULONG io_port, UCHAR Irq, USHORT index );
-void DC390_initDCB( PACB pACB, PDCB pDCB, PSCSICMD cmd );
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,93)
+# define USE_SPINLOCKS 1
+# define NEW_PCI 1
+#else
+# undef NEW_PCI


+# if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,30)

+# define USE_SPINLOCKS 2
+# endif
+#endif
+
+#ifdef USE_SPINLOCKS
+
+# if USE_SPINLOCKS == 3 /* both */
+
+# if defined (__SMP__) || DEBUG_SPINLOCKS > 0
+# define DC390_LOCKA_INIT { spinlock_t __unlocked = SPIN_LOCK_UNLOCKED; pACB->lock = __unlocked; };
+# else
+# define DC390_LOCKA_INIT
+# endif
+ spinlock_t dc390_drvlock = SPIN_LOCK_UNLOCKED;
+
+# define DC390_AFLAGS unsigned long aflags;
+# define DC390_IFLAGS unsigned long iflags;
+# define DC390_DFLAGS unsigned long dflags;
+
+# define DC390_LOCK_IO spin_lock_irqsave (&io_request_lock, iflags)
+# define DC390_UNLOCK_IO spin_unlock_irqrestore (&io_request_lock, iflags)
+
+# define DC390_LOCK_DRV spin_lock_irqsave (&dc390_drvlock, dflags)
+# define DC390_UNLOCK_DRV spin_unlock_irqrestore (&dc390_drvlock, dflags)
+# define DC390_LOCK_DRV_NI spin_lock (&dc390_drvlock)
+# define DC390_UNLOCK_DRV_NI spin_unlock (&dc390_drvlock)
+
+# define DC390_LOCK_ACB spin_lock_irqsave (&(pACB->lock), aflags)
+# define DC390_UNLOCK_ACB spin_unlock_irqrestore (&(pACB->lock), aflags)
+# define DC390_LOCK_ACB_NI spin_lock (&(pACB->lock))
+# define DC390_UNLOCK_ACB_NI spin_unlock (&(pACB->lock))
+//# define DC390_LOCKA_INIT spin_lock_init (&(pACB->lock))
+
+# else
+
+# if USE_SPINLOCKS == 2 /* adapter specific locks */
+
+# if defined (__SMP__) || DEBUG_SPINLOCKS > 0
+# define DC390_LOCKA_INIT { spinlock_t __unlocked = SPIN_LOCK_UNLOCKED; pACB->lock = __unlocked; };
+# else
+# define DC390_LOCKA_INIT
+# endif
+ spinlock_t dc390_drvlock = SPIN_LOCK_UNLOCKED;
+# define DC390_AFLAGS unsigned long aflags;
+# define DC390_IFLAGS
+# define DC390_DFLAGS unsigned long dflags;
+# define DC390_LOCK_IO /* spin_lock_irqsave (&io_request_lock, iflags) */
+# define DC390_UNLOCK_IO /* spin_unlock_irqrestore (&io_request_lock, iflags) */
+# define DC390_LOCK_DRV spin_lock_irqsave (&dc390_drvlock, dflags)
+# define DC390_UNLOCK_DRV spin_unlock_irqrestore (&dc390_drvlock, dflags)
+# define DC390_LOCK_DRV_NI spin_lock (&dc390_drvlock)
+# define DC390_UNLOCK_DRV_NI spin_unlock (&dc390_drvlock)
+# define DC390_LOCK_ACB spin_lock_irqsave (&(pACB->lock), aflags)
+# define DC390_UNLOCK_ACB spin_unlock_irqrestore (&(pACB->lock), aflags)
+# define DC390_LOCK_ACB_NI spin_lock (&(pACB->lock))
+# define DC390_UNLOCK_ACB_NI spin_unlock (&(pACB->lock))
+//# define DC390_LOCKA_INIT spin_lock_init (&(pACB->lock))
+
+# else /* USE_SPINLOCKS == 1: global lock io_request_lock */
+
+# define DC390_AFLAGS
+# define DC390_IFLAGS unsigned long iflags;
+# define DC390_DFLAGS unsigned long dflags;
+ spinlock_t dc390_drvlock = SPIN_LOCK_UNLOCKED;
+# define DC390_LOCK_IO spin_lock_irqsave (&io_request_lock, iflags)
+# define DC390_UNLOCK_IO spin_unlock_irqrestore (&io_request_lock, iflags)
+# define DC390_LOCK_DRV spin_lock_irqsave (&dc390_drvlock, dflags)
+# define DC390_UNLOCK_DRV spin_unlock_irqrestore (&dc390_drvlock, dflags)
+# define DC390_LOCK_DRV_NI spin_lock (&dc390_drvlock)
+# define DC390_UNLOCK_DRV_NI spin_unlock (&dc390_drvlock)
+# define DC390_LOCK_ACB /* DC390_LOCK_IO */
+# define DC390_UNLOCK_ACB /* DC390_UNLOCK_IO */
+# define DC390_LOCK_ACB_NI /* spin_lock (&(pACB->lock)) */
+# define DC390_UNLOCK_ACB_NI /* spin_unlock (&(pACB->lock)) */
+# define DC390_LOCKA_INIT /* DC390_LOCKA_INIT */
+
+# endif /* 2 */
+# endif /* 3 */
+
+#else /* USE_SPINLOCKS undefined */
+
+# define DC390_AFLAGS unsigned long aflags;
+# define DC390_IFLAGS unsigned long iflags;
+# define DC390_DFLAGS unsigned long dflags;
+# define DC390_LOCK_IO save_flags (iflags); cli ()
+# define DC390_UNLOCK_IO restore_flags (iflags)
+# define DC390_LOCK_DRV save_flags (dflags); cli ()
+# define DC390_UNLOCK_DRV restore_flags (dflags)
+# define DC390_LOCK_DRV_NI
+# define DC390_UNLOCK_DRV_NI
+# define DC390_LOCK_ACB save_flags (aflags); cli ()
+# define DC390_UNLOCK_ACB restore_flags (aflags)
+# define DC390_LOCK_ACB_NI
+# define DC390_UNLOCK_ACB_NI
+# define DC390_LOCKA_INIT
+#endif /* def */
+
+
+/* These macros are used for uniform access to 2.0.x and 2.1.x PCI config space*/
+
+#ifdef NEW_PCI
+# define PDEV pdev
+# define PDEVDECL struct pci_dev *pdev
+# define PDEVDECL0 struct pci_dev *pdev = NULL
+# define PDEVDECL1 struct pci_dev *pdev
+# define PDEVSET pACB->pdev=pdev
+# define PDEVSET1 pdev=pACB->pdev
+# define PCI_WRITE_CONFIG_BYTE(pd, rv, bv) pci_write_config_byte (pd, rv, bv)
+# define PCI_READ_CONFIG_BYTE(pd, rv, bv) pci_read_config_byte (pd, rv, bv)
+# define PCI_WRITE_CONFIG_WORD(pd, rv, bv) pci_write_config_word (pd, rv, bv)
+# define PCI_READ_CONFIG_WORD(pd, rv, bv) pci_read_config_word (pd, rv, bv)
+# define PCI_BUS_DEV pdev->bus->number, pdev->devfn
+# define PCI_PRESENT pci_present ()
+# define PCI_SET_MASTER pci_set_master (pdev)
+# define PCI_FIND_DEVICE(vend, id) (pdev = pci_find_device (vend, id, pdev))
+# define PCI_GET_IO_AND_IRQ io_port = pdev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK; irq = pdev->irq
+#else
+# include <linux/bios32.h>
+# define PDEV pbus, pdevfn
+# define PDEVDECL UCHAR pbus, UCHAR pdevfn
+# define PDEVDECL0 UCHAR pbus = 0; UCHAR pdevfn = 0; USHORT pci_index = 0; int error
+# define PDEVDECL1 UCHAR pbus; UCHAR pdevfn /*; USHORT pci_index */
+# define PDEVSET pACB->pbus=pbus; pACB->pdevfn=pdevfn /*; pACB->pci_index=pci_index */
+# define PDEVSET1 pbus=pACB->pbus; pdevfn=pACB->pdevfn /*; pci_index=pACB->pci_index */
+# define PCI_WRITE_CONFIG_BYTE(pd, rv, bv) pcibios_write_config_byte (pd, rv, bv)
+# define PCI_READ_CONFIG_BYTE(pd, rv, bv) pcibios_read_config_byte (pd, rv, bv)
+# define PCI_WRITE_CONFIG_WORD(pd, rv, bv) pcibios_write_config_word (pd, rv, bv)
+# define PCI_READ_CONFIG_WORD(pd, rv, bv) pcibios_read_config_word (pd, rv, bv)
+# define PCI_BUS_DEV pbus, pdevfn
+# define PCI_PRESENT pcibios_present ()
+# define PCI_SET_MASTER dc390_set_master (pbus, pdevfn)
+# define PCI_FIND_DEVICE(vend, id) (!pcibios_find_device (vend, id, pci_index++, &pbus, &pdevfn))
+# define PCI_GET_IO_AND_IRQ error = pcibios_read_config_dword (pbus, pdevfn, PCI_BASE_ADDRESS_0, &io_port); \
+ error |= pcibios_read_config_byte (pbus, pdevfn, PCI_INTERRUPT_LINE, &irq); \
+ io_port &= 0xfffe; \
+ if (error) { printk (KERN_ERR "DC390_detect: Error reading PCI config registers!\n"); continue; }
+#endif
+
+#include "tmscsim.h"
+
+#ifndef __init
+# define __init
+#endif
+
+UCHAR dc390_StartSCSI( PACB pACB, PDCB pDCB, PSRB pSRB );
+void dc390_DataOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+void dc390_DataIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void dc390_Command_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void dc390_Status_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void dc390_MsgOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+void dc390_MsgIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void dc390_DataOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void dc390_DataInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+void dc390_CommandPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void dc390_StatusPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+void dc390_MsgOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void dc390_MsgInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void dc390_Nop_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void dc390_Nop_1( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+
+static void dc390_SetXferRate( PACB pACB, PDCB pDCB );
+void dc390_Disconnect( PACB pACB );
+void dc390_Reselect( PACB pACB );
+void dc390_SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB );
+void dc390_DoingSRB_Done( PACB pACB );
+static void dc390_ScsiRstDetect( PACB pACB );
+static void dc390_ResetSCSIBus( PACB pACB );
+static void __inline__ dc390_RequestSense( PACB pACB, PDCB pDCB, PSRB pSRB );
+static void __inline__ dc390_InvalidCmd( PACB pACB );
+static void __inline__ dc390_EnableMsgOut_Abort (PACB, PSRB);
+static void dc390_remove_dev (PACB pACB, PDCB pDCB);
+void do_DC390_Interrupt( int, void *, struct pt_regs *);
+
+int dc390_initAdapter( PSH psh, ULONG io_port, UCHAR Irq, UCHAR index );
+void dc390_initDCB( PACB pACB, PDCB *ppDCB, PSCSICMD cmd );
+void dc390_updateDCB (PACB pACB, PDCB pDCB);
X
X #ifdef MODULE
-static int DC390_release(struct Scsi_Host *host);
-static int DC390_shutdown (struct Scsi_Host *host);
+ static int DC390_release(struct Scsi_Host *host);
+ static int dc390_shutdown (struct Scsi_Host *host);
X #endif
X
X
-static PSHT pSHT_start = NULL;
-static PSH pSH_start = NULL;
-static PSH pSH_current = NULL;
-static PACB pACB_start= NULL;
-static PACB pACB_current = NULL;
-static PDCB pPrevDCB = NULL;
-static USHORT adapterCnt = 0;
-static USHORT InitialTime = 0;
-static USHORT CurrSyncOffset = 0;
-static ULONG mech1addr;
-static UCHAR mech2bus, mech2Agent, mech2CfgSPenR;
-
-static PVOID DC390_phase0[]={
- DC390_DataOut_0,
- DC390_DataIn_0,
- DC390_Command_0,
- DC390_Status_0,
- DC390_Nop_0,
- DC390_Nop_0,
- DC390_MsgOut_0,
- DC390_MsgIn_0,
- DC390_Nop_1
+//static PSHT dc390_pSHT_start = NULL;
+//static PSH dc390_pSH_start = NULL;
+//static PSH dc390_pSH_current = NULL;
+static PACB dc390_pACB_start= NULL;
+static PACB dc390_pACB_current = NULL;
+static UCHAR dc390_adapterCnt = 0;
+static UCHAR dc390_CurrSyncOffset = 0;
+static ULONG dc390_lastabortedpid = 0;
+static ULONG dc390_laststatus = 0;
+
+#ifndef CONFIG_SCSI_DC390T_NOGENSUPP
+/* Startup values, to be overriden on the commandline */
+int tmscsim[] = {7, 1 /* 8MHz */,
+ PARITY_CHK_ | SEND_START_ | EN_DISCONNECT_
+ | SYNC_NEGO_ | TAG_QUEUEING_,
+ MORE2_DRV | GREATER_1G | RST_SCSI_BUS | ACTIVE_NEGATION
+ /* | NO_SEEK */
+# ifdef CONFIG_SCSI_MULTI_LUN
+ | LUN_CHECK
+# endif
+ , 3 /* 16 Tags per LUN */};
+
+# if defined(MODULE) && LINUX_VERSION_CODE >= LinuxVersionCode(2,1,30)
+MODULE_PARM(tmscsim, "1-5i");
+MODULE_PARM_DESC(tmscsim, "Host SCSI ID, Speed (0=10MHz), Device Flags, Adapter Flags, Max Tags (log2(tags)-1)");
+# endif


+
+#endif /* CONFIG_SCSI_DC390T_NOGENSUPP */
+

+#if defined(MODULE) && LINUX_VERSION_CODE >= LinuxVersionCode(2,1,30)
+MODULE_AUTHOR("C.L. Huang / Kurt Garloff");
+MODULE_DESCRIPTION("SCSI host adapter driver for Tekram DC390 and other AMD53C974A based PCI SCSI adapters");
+MODULE_SUPPORTED_DEVICE("sd,sr,sg,st");
+#endif
+
+static PVOID dc390_phase0[]={
+ dc390_DataOut_0,
+ dc390_DataIn_0,
+ dc390_Command_0,
+ dc390_Status_0,
+ dc390_Nop_0,
+ dc390_Nop_0,
+ dc390_MsgOut_0,
+ dc390_MsgIn_0,
+ dc390_Nop_1
X };
X
-static PVOID DC390_phase1[]={
- DC390_DataOutPhase,
- DC390_DataInPhase,
- DC390_CommandPhase,
- DC390_StatusPhase,
- DC390_Nop_0,
- DC390_Nop_0,
- DC390_MsgOutPhase,
- DC390_MsgInPhase,
- DC390_Nop_1,
+static PVOID dc390_phase1[]={
+ dc390_DataOutPhase,
+ dc390_DataInPhase,
+ dc390_CommandPhase,
+ dc390_StatusPhase,
+ dc390_Nop_0,
+ dc390_Nop_0,
+ dc390_MsgOutPhase,
+ dc390_MsgInPhase,
+ dc390_Nop_1
X };
X
-UCHAR eepromBuf[MAX_ADAPTER_NUM][128];
-
-
-UCHAR clock_period1[] = {4, 5, 6, 7, 8, 10, 13, 20};
+#ifdef DC390_DEBUG1
+static char* dc390_p0_str[] = {
+ "dc390_DataOut_0",
+ "dc390_DataIn_0",
+ "dc390_Command_0",
+ "dc390_Status_0",
+ "dc390_Nop_0",
+ "dc390_Nop_0",
+ "dc390_MsgOut_0",
+ "dc390_MsgIn_0",
+ "dc390_Nop_1"
+ };
+
+static char* dc390_p1_str[] = {
+ "dc390_DataOutPhase",
+ "dc390_DataInPhase",
+ "dc390_CommandPhase",
+ "dc390_StatusPhase",
+ "dc390_Nop_0",
+ "dc390_Nop_0",
+ "dc390_MsgOutPhase",
+ "dc390_MsgInPhase",
+ "dc390_Nop_1"
+ };
+#endif
X
-UCHAR baddevname1[2][28] ={
+/* Devices erroneously pretending to be able to do TagQ */
+UCHAR dc390_baddevname1[2][28] ={
X "SEAGATE ST3390N 9546",
X "HP C3323-300 4269"};
-
X #define BADDEVCNT 2
X
+static char* dc390_adapname = "DC390";
+UCHAR dc390_eepromBuf[MAX_ADAPTER_NUM][EE_LEN];
+UCHAR dc390_clock_period1[] = {4, 5, 6, 7, 8, 10, 13, 20};
+
+struct proc_dir_entry DC390_proc_scsi_tmscsim ={
+ PROC_SCSI_DC390T, 7 ,"tmscsim",


+ S_IFDIR | S_IRUGO | S_IXUGO, 2

+ };
+
X
X /***********************************************************************

+ * Functions for access to DC390 EEPROM
+ * and some to emulate it
X *
- *
+ **********************************************************************/
+
+
+static void __init dc390_EnDisableCE( UCHAR mode, PDEVDECL, PUCHAR regval )


+{
+ UCHAR bval;
+
+ bval = 0;

+ if(mode == ENABLE_CE)
+ *regval = 0xc0;
+ else


+ *regval = 0x80;
+ PCI_WRITE_CONFIG_BYTE(PDEV, *regval, bval);

+ if(mode == DISABLE_CE)
+ PCI_WRITE_CONFIG_BYTE(PDEV, *regval, bval);


SHAR_EOF
true || echo 'restore of patch-2.0.37 failed'
fi

echo 'End of part 38'
echo 'File patch-2.0.37 is continued in part 39'
echo 39 > _shar_seq_.tmp

Thomas...@ciw.uni-karlsruhe.de

unread,
Jun 16, 1999, 3:00:00 AM6/16/99
to
Archive-name: v2.0/patch-2.0.37/part45

#!/bin/sh
# this is part 45 of a 45 - part archive


# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.0.37 continued
if test ! -r _shar_seq_.tmp; then
echo 'Please unpack part 1 first!'
exit 1
fi
(read Scheck

if test "$Scheck" != 45; then


echo Please unpack part "$Scheck" next!
exit 1
else
exit 0
fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.0.37'
else
echo 'x - continuing with patch-2.0.37'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.0.37' &&

+ printk(" Call ID %X -> %X.\n", ntohs(ms_gre->sport), ntohs(ms_gre->mport));
+#ifdef DEBUG_IP_MASQUERADE_PPTP
+ printk(KERN_DEBUG "ip_masq_pptp(): ");
+ printk("unmasqed call ID %X\n",
+ ntohs(pptpReq.icack->callID));
+#endif /* DEBUG_IP_MASQUERADE_PPTP */
+ } else {
+ printk(KERN_INFO "ip_masq_pptp(): ");
+ printk("Lost GRE masq table entry (%s)\n", "IN_CALL_REPLY");
+ }
+ }
+ break;
+ case PPTP_CALL_DISCONNECT_NOTIFY:
+ if (iph->daddr == ms->daddr) /* outbound only */
+ {
+#ifdef DEBUG_IP_MASQUERADE_PPTP
+ printk(KERN_DEBUG "ip_masq_pptp(): ");
+ printk("Disconnect notify, call ID %X\n",
+ ntohs(pptpReq.disc->callID));
+#endif /* DEBUG_IP_MASQUERADE_PPTP */
+ ms_gre = ip_masq_out_get_2(IPPROTO_GRE,
+ iph->saddr, pptpReq.disc->callID,
+ iph->daddr, 0);
+ if (ms_gre != NULL)
+ {
+ /*
+ * expire the data channel
+ * table entry quickly now.
+ */
+ ip_masq_set_expire(ms_gre, 0);
+ ip_masq_set_expire(ms_gre, 30*HZ);
+ ms->control = NULL;
+ ms_gre->flags &= ~IP_MASQ_F_CONTROL;
+ pptpReq.disc->callID = ms_gre->mport;
+ printk(KERN_INFO "ip_masq_pptp(): ");
+ printk("Disconnect PPTP sess %s", in_ntoa(ms->saddr));
+ printk(" -> %s", in_ntoa(ms->daddr));
+ printk(" Call ID %X -> %X.\n", ntohs(ms_gre->sport), ntohs(ms_gre->mport));
+#ifdef DEBUG_IP_MASQUERADE_PPTP
+ printk(KERN_DEBUG "ip_masq_pptp(): ");
+ printk("masqed call ID %X\n",
+ ntohs(pptpReq.disc->callID));
+#endif /* DEBUG_IP_MASQUERADE_PPTP */
+ }
+ }
+ break;
+ case PPTP_WAN_ERROR_NOTIFY:
+ if (iph->saddr == ms->daddr) /* inbound only */
+ {
+#ifdef DEBUG_IP_MASQUERADE_PPTP
+ printk(KERN_DEBUG "ip_masq_pptp(): ");
+ printk("Error notify, peer call ID %X\n",
+ ntohs(pptpReq.wanerr->peersCallID));
+#endif /* DEBUG_IP_MASQUERADE_PPTP */
+ ms_gre = ip_masq_getbym(IPPROTO_GRE,
+ ms->maddr, pptpReq.wanerr->peersCallID);
+ if (ms_gre != NULL)
+ {
+ pptpReq.wanerr->peersCallID = ms_gre->sport;
+#ifdef DEBUG_IP_MASQUERADE_PPTP
+ printk(KERN_DEBUG "ip_masq_pptp(): ");
+ printk("unmasqed call ID %X\n",
+ ntohs(pptpReq.wanerr->peersCallID));
+#endif /* DEBUG_IP_MASQUERADE_PPTP */
+ } else {
+ printk(KERN_INFO "ip_masq_pptp(): ");
+ printk("Lost GRE masq table entry (%s)\n", "WAN_ERROR_NOTIFY");
+ }
+ }
+ break;
+ case PPTP_SET_LINK_INFO:
+ if (iph->saddr == ms->daddr) /* inbound only */
+ {
+#ifdef DEBUG_IP_MASQUERADE_PPTP
+ printk(KERN_DEBUG "ip_masq_pptp(): ");
+ printk("Set link info, peer call ID %X\n",
+ ntohs(pptpReq.setlink->peersCallID));
+#endif /* DEBUG_IP_MASQUERADE_PPTP */
+ ms_gre = ip_masq_getbym(IPPROTO_GRE,
+ ms->maddr, pptpReq.setlink->peersCallID);
+ if (ms_gre != NULL)
+ {
+ pptpReq.setlink->peersCallID = ms_gre->sport;
+#ifdef DEBUG_IP_MASQUERADE_PPTP
+ printk(KERN_DEBUG "ip_masq_pptp(): ");
+ printk("unmasqed call ID %X\n",
+ ntohs(pptpReq.setlink->peersCallID));
+#endif /* DEBUG_IP_MASQUERADE_PPTP */
+ } else {
+ printk(KERN_INFO "ip_masq_pptp(): ");
+ printk("Lost GRE masq table entry (%s)\n", "SET_LINK_INFO");
+ }


+ }
+ break;
+ }
+ }

+}
+#endif /* CONFIG_IP_MASQUERADE_PPTP_MULTICLIENT */
+
+static struct symbol_table pptp_masq_syms = {
+#include <linux/symtab_begin.h>
+ X(ip_fw_masq_gre),
+ X(ip_fw_demasq_gre),
+#ifdef CONFIG_IP_MASQUERADE_PPTP_MULTICLIENT
+ X(ip_masq_pptp),
+#endif /* CONFIG_IP_MASQUERADE_PPTP_MULTICLIENT */
+#include <linux/symtab_end.h>
+};
+
+#endif /* CONFIG_IP_MASQUERADE_PPTP */
+
+
+#ifdef CONFIG_IP_MASQUERADE_IPSEC
+/*
+ * Quick-and-dirty handling of ESP connections
+ * John Hardin <jha...@wolfenet.com> gets all blame...
+ */
+
+/*
+ * Handle outbound ESP packets.
+ *
+ * This is largely a copy of ip_fw_masquerade()
+ *
+ * To associate inbound traffic with outbound traffic, we only
+ * allow one session per remote host to be negotiated at a time.
+ * If a packet comes in and there's no masq table entry for it,
+ * then check for other masq table entries for the same server
+ * with the inbound SPI set to zero (i.e. no response yet). If
+ * found, discard the packet.
+ * This will DoS the server for the duration of the connection
+ * attempt, so keep the masq entry's lifetime short until a
+ * response comes in.
+ * If multiple masqueraded hosts are in contention for the same
+ * remote host, enforce round-robin access. This may lead to
+ * misassociation of response traffic if the response is delayed
+ * a great deal, but the masqueraded hosts will clean that up
+ * if it happens.
+ */
+
+int ip_fw_masq_esp(struct sk_buff **skb_p, struct device *dev)
+{
+ struct sk_buff *skb = *skb_p;
+ struct iphdr *iph = skb->h.iph;
+ struct ip_masq *ms;
+ unsigned long flags;
+ __u32 o_spi;
+ __u16 fake_sport;
+ unsigned long timeout = MASQUERADE_EXPIRE_IPSEC;
+
+ o_spi = *((__u32 *)&(((char *)iph)[iph->ihl*4]));
+ fake_sport = (__u16) ntohl(o_spi) & 0xffff;
+
+#ifdef DEBUG_IP_MASQUERADE_IPSEC
+ printk(KERN_DEBUG "ip_fw_masq_esp(): ");
+ printk("pkt %s", in_ntoa(iph->saddr));
+ printk(" -> %s SPI %lX (fakeport %X)\n", in_ntoa(iph->daddr), ntohl(o_spi), fake_sport);
+#endif /* DEBUG_IP_MASQUERADE_IPSEC */
+
+ if (o_spi == 0) {
+ /* illegal SPI - discard */
+ printk(KERN_INFO "ip_fw_masq_esp(): ");
+ printk("zero SPI from %s discarded\n", in_ntoa(iph->saddr));
+ return -1;
+ }
+
+ /*
+ * Look for masq table entry
+ */
+
+ ms = ip_masq_out_get_ipsec(IPPROTO_ESP,
+ iph->saddr, fake_sport,
+ iph->daddr, 0,
+ o_spi);
+
+ if (ms!=NULL) {
+ if (ms->ispi == IPSEC_INIT_SQUELCHED) {
+ /* squelched: toss the packet without changing the timer */
+#ifdef DEBUG_IP_MASQUERADE_IPSEC
+ printk(KERN_INFO "ip_fw_masq_esp(): ");
+ printk("init %s ", in_ntoa(iph->saddr));
+ printk("-> %s SPI %lX ", in_ntoa(iph->daddr), ntohl(o_spi));
+ printk("squelched\n");
+#endif /* DEBUG_IP_MASQUERADE_IPSEC */
+ return -1;
+ }
+
+ /* delete the expiration timer */
+ ip_masq_set_expire(ms,0);
+
+ /*
+ * Make sure that the masq IP address is correct
+ * for dynamic IP...
+ */
+ if ( (ms->maddr != dev->pa_addr) && (sysctl_ip_dynaddr & 3) ) {
+ printk(KERN_INFO "ip_fw_masq_esp(): ");
+ printk("change maddr from %s", in_ntoa(ms->maddr));
+ printk(" to %s\n", in_ntoa(dev->pa_addr));
+ save_flags(flags);
+ cli();
+ ip_masq_unhash(ms);
+ ms->maddr = dev->pa_addr;
+ ip_masq_hash(ms);
+ restore_flags(flags);
+ }
+
+ if (ms->ispi == 0) {
+ /* no response yet, keep timeout short */
+ timeout = MASQUERADE_EXPIRE_IPSEC_INIT;
+ if (ms->blocking) {
+ /* prevent DoS: limit init packet timer resets */
+ ms->ocnt++;
+ #ifdef DEBUG_IP_MASQUERADE_IPSEC
+ printk(KERN_INFO "ip_fw_masq_esp(): ");
+ printk("init %s ", in_ntoa(iph->saddr));
+ printk("-> %s SPI %lX ", in_ntoa(iph->daddr), ntohl(o_spi));
+ printk("retry %d\n", ms->ocnt);
+ #endif /* DEBUG_IP_MASQUERADE_IPSEC */
+ if (ms->ocnt > IPSEC_INIT_RETRIES) {
+ /* more than IPSEC_INIT_RETRIES tries, give up */
+ printk(KERN_INFO "ip_fw_masq_esp(): ");
+ printk("init %s ", in_ntoa(iph->saddr));
+ printk("-> %s SPI %lX ", in_ntoa(iph->daddr), ntohl(o_spi));
+ printk("no response after %d tries, unblocking & squelching\n", ms->ocnt);
+ /* squelch that source+SPI for a bit */
+ timeout = 30*HZ;
+ save_flags(flags);
+ cli();
+ ip_masq_unhash(ms);
+ ms->ispi = IPSEC_INIT_SQUELCHED;
+ ms->dport = IPSEC_INIT_SQUELCHED;
+ ip_masq_hash(ms);
+ restore_flags(flags);
+ ip_masq_set_expire(ms, timeout);
+ /* toss the packet */
+ return -1;
+ }
+ }
+ }
+ } else {
+ /*
+ * Nope, not found, create a new entry for it, maybe
+ */
+
+ /* see if there are any pending inits with the same destination... */
+ ms = ip_masq_in_get_ipsec(IPPROTO_ESP,
+ iph->daddr, 0,
+ 0, 0,
+ 0);
+
+ if (ms != NULL) {
+ /* found one with ispi == 0 */
+ if (ms->saddr != iph->saddr) {
+ /* it's not ours, don't step on their toes */
+ printk(KERN_INFO "ip_fw_masq_esp(): ");
+ printk("init %s ", in_ntoa(iph->saddr));
+ printk("-> %s ", in_ntoa(iph->daddr));
+ printk("temporarily blocked by pending ");
+ printk("%s init\n", in_ntoa(ms->saddr));
+ /* let it know it has competition */
+ ms->blocking = 1;
+ /* toss the packet */
+ return -1;
+ }
+ if (ms->ospi != o_spi) {
+ /* SPIs differ, still waiting for a previous attempt to expire */
+ printk(KERN_INFO "ip_fw_masq_esp(): ");
+ printk("init %s ", in_ntoa(iph->saddr));
+ printk("-> %s SPI %lX ", in_ntoa(iph->daddr), ntohl(o_spi));
+ printk("temporarily blocked by pending ");
+ printk("init w/ SPI %lX\n", ntohl(ms->ospi));
+ /* let it know it has competition */
+ ms->blocking = 1;
+ /* toss the packet */
+ return -1;
+ }
+ } else /* nothing pending, make new entry, pending response */
+ ms = ip_masq_new(dev, iph->protocol,
+ iph->saddr, fake_sport,
+ iph->daddr, 0,
+ 0);
+
+ if (ms == NULL) {
+ printk(KERN_NOTICE "ip_fw_masq_esp(): Couldn't create masq table entry.\n");
+ return -1;
+ }
+
+ ms->blocking = ms->ocnt = 0;
+ ms->ospi = o_spi;
+ timeout = MASQUERADE_EXPIRE_IPSEC_INIT; /* fairly brief timeout while waiting for a response */
+ }
+
+ /*
+ * Set iph source addr from ip_masq obj.
+ */
+ iph->saddr = ms->maddr;
+
+ /*
+ * set timeout and check IP header
+ */
+
+ ip_masq_set_expire(ms, timeout);
+ ip_send_check(iph);
+
+#ifdef DEBUG_IP_MASQUERADE_IPSEC_VERBOSE
+ printk(KERN_DEBUG "MASQ: ESP O-routed from %s over %s\n",
+ in_ntoa(ms->maddr), dev->name);
+#endif /* DEBUG_IP_MASQUERADE_IPSEC_VERBOSE */


+
+ return 0;
+}
+
+/*

+ * Handle inbound ESP packets.


+ *
+ */
+

+int ip_fw_demasq_esp(struct sk_buff **skb_p, struct device *dev)
+{
+ struct sk_buff *skb = *skb_p;
+ struct iphdr *iph = skb->h.iph;
+ struct ip_masq *ms;
+ unsigned long flags;
+ __u32 i_spi;
+ __u16 fake_sport;
+#ifndef CONFIG_IP_MASQUERADE_IPSEC_NOGUESS
+ #define ESP_GUESS_SZ 5 /* minimum 3, please */
+ #define ESP_CAND_MIN_TM 5*60*HZ /* max 10*60*HZ? */
+ unsigned hash;
+ int i, ii,
+ ncand = 0, nguess = 0;
+ __u16 isakmp;
+ __u32 cand_ip,
+ guess_ip[ESP_GUESS_SZ];
+ unsigned long cand_tm,
+ guess_tm[ESP_GUESS_SZ];
+ struct sk_buff *skb_cl;
+ struct iphdr *iph_cl;
+#endif /* CONFIG_IP_MASQUERADE_IPSEC_NOGUESS */
+
+ i_spi = *((__u32 *)&(((char *)iph)[iph->ihl*4]));
+ fake_sport = (__u16) ntohl(i_spi) & 0xffff;
+
+#ifdef DEBUG_IP_MASQUERADE_IPSEC
+ printk(KERN_DEBUG "ip_fw_demasq_esp(): ");
+ printk("pkt %s", in_ntoa(iph->saddr));
+ printk(" -> %s SPI %lX (fakeport %X)\n", in_ntoa(iph->daddr), ntohl(i_spi), fake_sport);
+#endif /* DEBUG_IP_MASQUERADE_IPSEC */
+
+ if (i_spi == 0) {
+ /* illegal SPI - discard */
+ printk(KERN_INFO "ip_fw_demasq_esp(): ");
+ printk("zero SPI from %s discarded\n", in_ntoa(iph->saddr));
+ return -1;
+ }
+
+ if (i_spi == IPSEC_INIT_SQUELCHED) {
+ /* Ack! This shouldn't happen! */
+ /* IPSEC_INIT_SQUELCHED is chosen to be a reserved value as of 4/99 */
+ printk(KERN_NOTICE "ip_fw_demasq_esp(): ");
+ printk("SPI from %s is IPSEC_INIT_SQUELCHED - modify ip_masq.c!\n", in_ntoa(iph->saddr));
+ return -1;
+ }
+
+ /*
+ * Look for a masq table entry and reroute if found
+ */
+
+ ms = ip_masq_in_get_ipsec(IPPROTO_ESP,
+ iph->saddr, fake_sport,
+ iph->daddr, 0,
+ i_spi);
+
+ if (ms != NULL)
+ {
+ /* delete the expiration timer */
+ ip_masq_set_expire(ms,0);
+
+ iph->daddr = ms->saddr;
+
+ if (ms->ispi == 0) {
+#ifdef DEBUG_IP_MASQUERADE_IPSEC
+ printk(KERN_INFO "ip_fw_demasq_esp(): ");
+ printk("resp from %s SPI %lX", in_ntoa(iph->saddr), ntohl(i_spi));
+ printk(" routed to %s (SPI %lX)\n", in_ntoa(ms->saddr), ntohl(ms->ospi));
+#endif /* DEBUG_IP_MASQUERADE_IPSEC */
+ save_flags(flags);
+ cli();
+ ip_masq_unhash(ms);
+ ms->ispi = i_spi;
+ ms->dport = fake_sport;
+ ip_masq_hash(ms);
+ restore_flags(flags);
+ }
+
+ /*
+ * resum checksums and set timeout
+ */
+ ip_masq_set_expire(ms, MASQUERADE_EXPIRE_IPSEC);
+ ip_send_check(iph);
+
+#ifdef DEBUG_IP_MASQUERADE_IPSEC_VERBOSE
+ printk(KERN_DEBUG "MASQ: ESP I-routed to %s\n", in_ntoa(iph->daddr));
+#endif /* DEBUG_IP_MASQUERADE_IPSEC_VERBOSE */


+ return 1;
+ }
+

+#ifndef CONFIG_IP_MASQUERADE_IPSEC_NOGUESS
+ /* Guess who this packet is likely intended for:
+ * Scan the UDP masq table for local hosts that have communicated via
+ * ISAKMP with the host who sent this packet.
+ * Using an insertion sort with duplicate IP suppression, build a list
+ * of the ESP_GUESS_SZ most recent ISAKMP sessions (determined by
+ * sorting in decreasing order of timeout timer).
+ * Clone the original packet and send it to those hosts, but DON'T make
+ * a masq table entry, as we're only guessing. It is assumed that the correct
+ * host will respond to the traffic and that will create a masq table entry.
+ * To limit the list a bit, don't consider any ISAKMP masq entries with
+ * less than ESP_CAND_MIN_TM time to live. This should be some value less
+ * than the IPSEC table timeout or *all* entries will be ignored...
+ */
+
+#ifdef DEBUG_IP_MASQUERADE_IPSEC_VERBOSE
+ printk(KERN_DEBUG "ip_fw_demasq_esp(): ");
+ printk("guessing from %s SPI %lX\n", in_ntoa(iph->saddr), ntohl(i_spi));
+#endif /* DEBUG_IP_MASQUERADE_IPSEC_VERBOSE */
+
+ /* zero out the guess table */
+ for (i = 0;i < ESP_GUESS_SZ; i++) {
+ guess_ip[i] = 0;
+ guess_tm[i] = 0;
+ }
+
+ /* scan ISAKMP sessions with the source host */
+ isakmp = htons(UDP_PORT_ISAKMP);
+ hash = ip_masq_hash_key(IPPROTO_UDP, iph->saddr, isakmp);
+ for(ms = ip_masq_d_tab[hash]; ms ; ms = ms->d_link) {
+ if (ms->protocol == IPPROTO_UDP &&
+ ms->daddr == iph->saddr &&
+ ms->sport == isakmp &&
+ ms->dport == isakmp &&
+ ms->mport == isakmp &&
+ ms->ospi != 0) {
+ /* a candidate... */
+ ncand++;
+ cand_ip = ms->saddr;
+ cand_tm = ms->timer.expires - jiffies;
+#ifdef DEBUG_IP_MASQUERADE_IPSEC_VERBOSE
+ printk(KERN_DEBUG "ip_fw_demasq_esp(): ");
+ printk("cand %d: IP %s TM %ld\n", ncand, in_ntoa(cand_ip), cand_tm);
+#endif /* DEBUG_IP_MASQUERADE_IPSEC_VERBOSE */
+ if (cand_tm > ESP_CAND_MIN_TM) {
+ /* traffic is recent enough, add to list (maybe) */
+ for (i = 0; i < ESP_GUESS_SZ; i++) {
+ if (cand_tm > guess_tm[i]) {
+ /* newer */
+ if (guess_ip[i] != 0 && cand_ip != guess_ip[i]) {
+ /* newer and IP different - insert */
+ if (i < (ESP_GUESS_SZ - 1)) {
+ /* move entries down the list,
+ * find first entry after this slot
+ * where the IP is 0 (unused) or
+ * IP == candidate (older traffic, same host)
+ * rather than simply going to the end of the list,
+ * for efficiency (don't shift zeros) and
+ * duplicate IP suppression (don't keep older entries
+ * having the same IP)
+ */
+ for (ii = i + 1; ii < (ESP_GUESS_SZ - 1); ii++) {
+ if (guess_ip[ii] == 0 || guess_ip[ii] == cand_ip)
+ break;
+ }
+ for (ii-- ; ii >= i; ii--) {
+ guess_ip[ii+1] = guess_ip[ii];
+ guess_tm[ii+1] = guess_tm[ii];
+ }
+ }
+ }
+ guess_ip[i] = cand_ip;
+ guess_tm[i] = cand_tm;
+ break;
+ }
+ if (cand_ip == guess_ip[i]) {
+ /* fresher entry already there */


+ break;
+ }
+ }
+ }
+ }
+ }

+
+ if (guess_ip[0]) {
+ /* had guesses - send */
+ if (guess_ip[1]) {
+ /* multiple guesses, send a copy to all */
+ for (i = 0; guess_ip[i] != 0; i++) {
+ nguess++;
+#ifdef DEBUG_IP_MASQUERADE_IPSEC_VERBOSE
+ printk(KERN_DEBUG "ip_fw_demasq_esp(): ");
+ printk("guess %d: IP %s TM %ld\n", nguess, in_ntoa(guess_ip[i]), guess_tm[i]);
+#endif /* DEBUG_IP_MASQUERADE_IPSEC_VERBOSE */
+ /* duplicate and send the skb */
+ if ((skb_cl = skb_copy(skb, GFP_ATOMIC)) == NULL) {
+ printk(KERN_INFO "ip_fw_demasq_esp(): ");
+ printk("guessing: cannot copy skb\n");
+ } else {
+ iph_cl = skb_cl->h.iph;
+ iph_cl->daddr = guess_ip[i];
+ ip_send_check(iph_cl);
+ ip_forward(skb_cl, dev, IPFWD_MASQUERADED, iph_cl->daddr);
+ kfree_skb(skb_cl, FREE_WRITE);
+ }
+ }
+#ifdef DEBUG_IP_MASQUERADE_IPSEC
+ printk(KERN_INFO "ip_fw_demasq_esp(): ");
+ printk("guessing from %s SPI %lX sent to", in_ntoa(iph->saddr), ntohl(i_spi));
+ printk(" %d hosts (%d cand)\n", nguess, ncand);
+#endif /* DEBUG_IP_MASQUERADE_IPSEC */
+ return -1; /* discard original packet */
+ } else {
+ /* only one guess, send original packet to that host */
+ iph->daddr = guess_ip[0];
+ ip_send_check(iph);
+
+#ifdef DEBUG_IP_MASQUERADE_IPSEC
+ printk(KERN_INFO "ip_fw_demasq_esp(): ");
+ printk("guessing from %s SPI %lX sent to", in_ntoa(iph->saddr), ntohl(i_spi));
+ printk(" %s (%d cand)\n", in_ntoa(guess_ip[0]), ncand);
+#endif /* DEBUG_IP_MASQUERADE_IPSEC */


+ return 1;
+ }
+ }

+#endif /* CONFIG_IP_MASQUERADE_IPSEC_NOGUESS */
+
+ /* sorry, all this trouble for a no-hit :) */
+ printk(KERN_INFO "ip_fw_demasq_esp(): ");
+ printk("Inbound from %s SPI %lX has no masq table entry.\n", in_ntoa(iph->saddr), ntohl(i_spi));


+ return 0;
+}
+

+static struct symbol_table ipsec_masq_syms = {
+#include <linux/symtab_begin.h>
+ X(ip_masq_out_get_ipsec),
+ X(ip_masq_in_get_ipsec),
+ X(ip_masq_out_get_isakmp),
+ X(ip_masq_in_get_isakmp),
+ X(ip_fw_masq_esp),
+ X(ip_fw_demasq_esp),
+#include <linux/symtab_end.h>
+};
+
+#endif /* CONFIG_IP_MASQUERADE_IPSEC */
+
+
X int ip_fw_masquerade(struct sk_buff **skb_ptr, struct device *dev)
X {
X struct sk_buff *skb=*skb_ptr;
@@ -742,6 +2384,14 @@
X
X if (iph->protocol==IPPROTO_ICMP)
X return (ip_fw_masq_icmp(skb_ptr,dev));
+#ifdef CONFIG_IP_MASQUERADE_PPTP
+ if (iph->protocol==IPPROTO_GRE)
+ return (ip_fw_masq_gre(skb_ptr,dev));
+#endif /* CONFIG_IP_MASQUERADE_PPTP */
+#ifdef CONFIG_IP_MASQUERADE_IPSEC
+ if (iph->protocol==IPPROTO_ESP)
+ return (ip_fw_masq_esp(skb_ptr,dev));
+#endif /* CONFIG_IP_MASQUERADE_IPSEC */
X if (iph->protocol!=IPPROTO_UDP && iph->protocol!=IPPROTO_TCP)
X return -1;
X
@@ -758,6 +2408,7 @@
X #endif
X
X ms = ip_masq_out_get(iph);
+
X if (ms!=NULL) {
X ip_masq_set_expire(ms,0);
X
@@ -835,8 +2486,29 @@
X 0);
X if (ms == NULL)
X return -1;
+
+#ifdef CONFIG_IP_MASQUERADE_IPSEC
+ if (iph->protocol == IPPROTO_UDP && ntohs(portptr[0]) == UDP_PORT_ISAKMP && ntohs(portptr[1]) == UDP_PORT_ISAKMP) {
+ /* save the initiator cookie */
+ ms->ospi = *((__u32 *)&portptr[4]);
+ }
+#endif /* CONFIG_IP_MASQUERADE_IPSEC */
X }
X
+#ifdef CONFIG_IP_MASQUERADE_PPTP
+#ifdef CONFIG_IP_MASQUERADE_PPTP_MULTICLIENT
+ if (iph->protocol == IPPROTO_TCP && ntohs(portptr[1]) == PPTP_CONTROL_PORT)
+ {
+ /*
+ * Packet sent to PPTP control port. Process it.
+ * May change call ID word in request, but
+ * packet length will not change.
+ */
+ ip_masq_pptp(skb, ms, dev);
+ }
+#endif /* CONFIG_IP_MASQUERADE_PPTP_MULTICLIENT */
+#endif /* CONFIG_IP_MASQUERADE_PPTP */
+
X /*
X * Change the fragments origin
X */
@@ -869,6 +2541,13 @@
X
X if (masq_proto_num(iph->protocol)==0)
X {
+#ifdef CONFIG_IP_MASQUERADE_IPSEC
+ if (iph->protocol == IPPROTO_UDP && ntohs(portptr[0]) == UDP_PORT_ISAKMP && ntohs(portptr[1]) == UDP_PORT_ISAKMP) {
+ /* ISAKMP timeout should be same as ESP timeout to allow for rekeying */
+ timeout = MASQUERADE_EXPIRE_IPSEC;
+ } else
+#endif /* CONFIG_IP_MASQUERADE_IPSEC */
+
X timeout = ip_masq_expire->udp_timeout;
X recalc_check((struct udphdr *)portptr,iph->saddr,iph->daddr,size);
X }
@@ -1360,20 +3039,32 @@
X __u16 *portptr;
X struct ip_masq *ms;
X unsigned short len;
- unsigned long timeout;
+ unsigned long timeout = MASQUERADE_EXPIRE_TCP;
X #ifdef CONFIG_IP_MASQUERADE_IPAUTOFW
X struct ip_autofw *af;
X #endif /* CONFIG_IP_MASQUERADE_IPAUTOFW */
X
+
X switch (iph->protocol) {
X case IPPROTO_ICMP:
X return(ip_fw_demasq_icmp(skb_p, dev));
+#ifdef CONFIG_IP_MASQUERADE_PPTP
+ case IPPROTO_GRE:
+ return(ip_fw_demasq_gre(skb_p, dev));
+#endif /* CONFIG_IP_MASQUERADE_PPTP */
+#ifdef CONFIG_IP_MASQUERADE_IPSEC
+ case IPPROTO_ESP:
+ return(ip_fw_demasq_esp(skb_p, dev));
+#endif /* CONFIG_IP_MASQUERADE_IPSEC */
X case IPPROTO_TCP:
X case IPPROTO_UDP:
X /* Make sure packet is in the masq range */
X portptr = (__u16 *)&(((char *)iph)[iph->ihl*4]);
X if ((ntohs(portptr[1]) < PORT_MASQ_BEGIN ||
X ntohs(portptr[1]) > PORT_MASQ_END)
+#ifdef CONFIG_IP_MASQUERADE_IPSEC
+ && ((iph->protocol != IPPROTO_UDP) || (ntohs(portptr[0]) != UDP_PORT_ISAKMP) || (ntohs(portptr[1]) != UDP_PORT_ISAKMP))
+#endif /* CONFIG_IP_MASQUERADE_IPSEC */
X #ifdef CONFIG_IP_MASQUERADE_IPAUTOFW
X && !ip_autofw_check_range(iph->saddr, portptr[1],
X iph->protocol, 0)
@@ -1502,6 +3193,20 @@
X len = ntohs(iph->tot_len) - (iph->ihl * 4);
X }
X
+#ifdef CONFIG_IP_MASQUERADE_PPTP
+#ifdef CONFIG_IP_MASQUERADE_PPTP_MULTICLIENT
+ if (iph->protocol == IPPROTO_TCP && ntohs(portptr[0]) == PPTP_CONTROL_PORT)
+ {
+ /*
+ * Packet received from PPTP control port. Process it.
+ * May change call ID word in request, but
+ * packet length will not change.
+ */
+ ip_masq_pptp(skb, ms, dev);
+ }
+#endif /* CONFIG_IP_MASQUERADE_PPTP_MULTICLIENT */
+#endif /* CONFIG_IP_MASQUERADE_PPTP */
+
X /*
X * Yug! adjust UDP/TCP and IP checksums, also update
X * timeouts.
@@ -1510,6 +3215,14 @@
X if (masq_proto_num(iph->protocol)==0)
X {
X recalc_check((struct udphdr *)portptr,iph->saddr,iph->daddr,len);
+
+#ifdef CONFIG_IP_MASQUERADE_IPSEC
+ if (iph->protocol == IPPROTO_UDP && ntohs(portptr[0]) == UDP_PORT_ISAKMP && ntohs(portptr[1]) == UDP_PORT_ISAKMP) {
+ /* ISAKMP timeout should be same as ESP timeout to allow for rekeying */
+ timeout = MASQUERADE_EXPIRE_IPSEC;
+ } else
+#endif /* CONFIG_IP_MASQUERADE_IPSEC */
+
X timeout = ip_masq_expire->udp_timeout;
X }
X else
@@ -1675,6 +3388,12 @@
X int ip_masq_init(void)
X {
X register_symtab (&ip_masq_syms);
+#ifdef CONFIG_IP_MASQUERADE_PPTP
+ register_symtab (&pptp_masq_syms);
+#endif /* CONFIG_IP_MASQUERADE_PPTP */
+#ifdef CONFIG_IP_MASQUERADE_IPSEC
+ register_symtab (&ipsec_masq_syms);
+#endif /* CONFIG_IP_MASQUERADE_IPSEC */
X #ifdef CONFIG_PROC_FS
X proc_net_register(&(struct proc_dir_entry) {
X PROC_NET_IPMSQHST, 13, "ip_masquerade",
diff -u --recursive --new-file v2.0.36/linux/net/ipv4/ip_sockglue.c linux/net/ipv4/ip_sockglue.c
--- v2.0.36/linux/net/ipv4/ip_sockglue.c Tue Aug 12 11:30:35 1997
+++ linux/net/ipv4/ip_sockglue.c Sun Jun 13 10:21:04 1999
@@ -455,9 +455,6 @@
X int ip_getsockopt(struct sock *sk, int level, int optname, char *optval, int *optlen)
X {
X int val,err;
-#ifdef CONFIG_IP_MULTICAST
- int len;
-#endif
X
X if(level!=SOL_IP)
X return -EOPNOTSUPP;
@@ -541,16 +538,33 @@
X val=sk->ip_mc_loop;
X break;
X case IP_MULTICAST_IF:
+ {
+ struct device *dev;
+ struct in_addr ia;
+
X err=verify_area(VERIFY_WRITE, optlen, sizeof(int));
X if(err)
X return err;
- len=strlen(sk->ip_mc_name);
- err=verify_area(VERIFY_WRITE, optval, len);
+ err=verify_area(VERIFY_WRITE, optval, sizeof(ia));
X if(err)
X return err;
- put_user(len,(int *) optlen);
- memcpy_tofs((void *)optval,sk->ip_mc_name, len);
+
+ if(*sk->ip_mc_name)
+ {
+ dev=dev_get(sk->ip_mc_name);
+ /* Someone ran off with the interface, its probably
+ been downed. */
+ if(dev==NULL)
+ return -ENODEV;
+ ia.s_addr = dev->pa_addr;
+ }
+ else
+ ia.s_addr = 0L;
+
+ put_user(sizeof(ia),(int *) optlen);
+ memcpy_tofs((void *)optval, &ia, sizeof(ia));
X return 0;
+ }
X #endif
X default:
X return(-ENOPROTOOPT);
diff -u --recursive --new-file v2.0.36/linux/net/ipv4/rarp.c linux/net/ipv4/rarp.c
--- v2.0.36/linux/net/ipv4/rarp.c Sun Nov 15 10:49:59 1998
+++ linux/net/ipv4/rarp.c Sun Jun 13 10:21:04 1999
@@ -189,6 +189,8 @@
X rarp_pkt_inited=1;
X }
X
+#ifdef MODULE
+
X static void rarp_end_pkt(void)
X {
X if(!rarp_pkt_inited)
@@ -197,6 +199,8 @@
X unregister_netdevice_notifier(&rarp_dev_notifier);
X rarp_pkt_inited=0;
X }
+
+#endif
X
X
X /*
diff -u --recursive --new-file v2.0.36/linux/net/netlink.c linux/net/netlink.c
--- v2.0.36/linux/net/netlink.c Wed Oct 15 14:47:26 1997
+++ linux/net/netlink.c Sun Jun 13 10:21:04 1999
@@ -198,6 +198,7 @@
X if(active_map&(1<<unit))
X return -EBUSY;
X active_map|=(1<<unit);
+ open_map&=~(1<<unit);
X netlink_handler[unit]=function;
X return 0;
X }
@@ -206,6 +207,7 @@
X {
X active_map&=~(1<<unit);
X netlink_handler[unit]=netlink_err;
+ open_map&=~(1<<unit);
X }
X
X int netlink_post(int unit, struct sk_buff *skb)
diff -u --recursive --new-file v2.0.36/linux/net/netrom/af_netrom.c linux/net/netrom/af_netrom.c
--- v2.0.36/linux/net/netrom/af_netrom.c Sun Nov 15 21:51:47 1998
+++ linux/net/netrom/af_netrom.c Sun Jun 13 10:21:04 1999
@@ -960,10 +960,18 @@
X */
X if (frametype != NR_CONNREQ) {
X /*
+ * Here it would be nice to be able to send a reset but
+ * NET/ROM doesn't have one. The following hack would
+ * have been a way to extend the protocol but apparently
+ * it kills BPQ boxes... :-(
+ */
+#if 0
+ /*
X * Never reply to a CONNACK/CHOKE.
X */
X if (frametype != NR_CONNACK || flags != NR_CHOKE_FLAG)
X nr_transmit_dm(skb, 1);
+#endif
X return 0;
X }
X
diff -u --recursive --new-file v2.0.36/linux/net/netsyms.c linux/net/netsyms.c
--- v2.0.36/linux/net/netsyms.c Sun Nov 15 10:50:01 1998
+++ linux/net/netsyms.c Sun Jun 13 10:21:04 1999
@@ -12,6 +12,7 @@
X #include <linux/net.h>
X #include <linux/netdevice.h>
X #include <linux/trdevice.h>
+#include <linux/fddidevice.h>
X #include <linux/ioport.h>
X #include <net/sock.h>
X
@@ -110,6 +111,8 @@
X X(ip_id_count),
X X(ip_send_check),
X X(ip_forward),
+ X(ip_queue_xmit),
+ X(ip_fragment),
X X(sysctl_ip_forward),
X
X #if defined(CONFIG_ULTRA) || defined(CONFIG_WD80x3) || \
@@ -129,6 +132,11 @@
X #ifdef CONFIG_TR
X X(tr_setup),
X X(tr_type_trans),
+#endif
+
+#ifdef CONFIG_FDDI
+ X(fddi_setup),
+ X(fddi_type_trans),
X #endif
X
X #ifdef CONFIG_NET_ALIAS
diff -u --recursive --new-file v2.0.36/linux/scripts/Menuconfig linux/scripts/Menuconfig
--- v2.0.36/linux/scripts/Menuconfig Mon Jul 13 13:46:44 1998
+++ linux/scripts/Menuconfig Sun Jun 13 10:21:05 1999
@@ -77,6 +77,14 @@
X }
X
X #
+# Define an int to a specific value.
+#
+
+function define_int () {
+ eval $1=$2
+}
+
+#
X # Create a boolean (Yes/No) function for our current menu
X # which calls our local bool function.
X #
@@ -954,6 +962,13 @@
X ;;
X esac
X }
+
+ function define_int () {
+ eval $1="$2"
+ echo "$1=$2" >>$CONFIG
+ echo "#define $1 $2" >>$CONFIG_H
+ }
+
X
X function choice () {
X #
diff -u --recursive --new-file v2.0.36/linux/scripts/tkgen.c linux/scripts/tkgen.c
--- v2.0.36/linux/scripts/tkgen.c Thu Jun 6 03:30:41 1996
+++ linux/scripts/tkgen.c Sun Jun 13 10:21:05 1999
@@ -280,6 +280,7 @@
X */
X switch(item->tok)
X {
+ case tok_define_int:
X case tok_define:
X printf("} then { set %s %s } \n", item->optionname, item->value);
X break;
@@ -464,6 +465,9 @@
X */
X switch(item->tok)
X {
+ case tok_define_int:
+ printf("} then {write_int $cfg $autocfg %s %s $notmod }\n", item->optionname, item->value);
+ break;
X case tok_define:
X printf("} then {write_tristate $cfg $autocfg %s %s $notmod }\n", item->optionname, item->value);
X break;
@@ -572,7 +576,8 @@
X * Skip items not for this menu, or ones having no conditions.
X */
X if (cfg->menu_number != menu_num ) continue;
- if (cfg->tok != tok_define) continue;
+ if (cfg->tok != tok_define && cfg->tok != tok_define_int)
+ continue;
X /*
X * Clear all of the booleans that are defined in this menu.
X */
@@ -717,6 +722,7 @@
X cfg->menu_line = menu_line++;
X break;
X case tok_define:
+ case tok_define_int:
X cfg->menu_number = -1;
X case tok_choice:
X default:
@@ -923,7 +929,7 @@
X /*
X * Skip items not for this menu, or ones having no conditions.
X */
- if( cfg->tok != tok_define) continue;
+ if( cfg->tok != tok_define && cfg->tok != tok_define_int) continue;
X if (cfg->cond != NULL )
X generate_if(cfg, cfg->cond, menu_num, cfg->menu_line);
X else
@@ -988,6 +994,7 @@
X case tok_tristate:
X case tok_dep_tristate:
X case tok_define:
+ case tok_define_int:
X case tok_choose:
X if(!(cfg->flags & GLOBAL_WRITTEN))
X {
@@ -1019,7 +1026,7 @@
X printf("\twrite_comment $cfg $autocfg \"%s\"\n", cfg->label);
X }
X #if 0
- else if(cfg->tok == tok_define)
+ else if(cfg->tok == tok_define || cfg->tok == tok_define_int)
X {
X printf("\twrite_define %s %s\n", cfg->optionname,
X cfg->value);
@@ -1043,6 +1050,12 @@
X cfg->optionname,
X cfg->optionname);
X }
+ else if (cfg->tok == tok_define_int )
+ {
+ printf("\twrite_int $cfg $autocfg %s $%s $notmod\n",
+ cfg->optionname,
+ cfg->optionname);
+ }
X else if (cfg->tok == tok_hex )
X {
X printf("\twrite_hex $cfg $autocfg %s $%s $notmod\n",
@@ -1109,13 +1122,14 @@
X clear_globalflags(config);
X for(cfg = scfg; cfg != NULL; cfg = cfg->next)
X {
- if( cfg->tok != tok_define ) continue;
+ if( cfg->tok != tok_define && cfg->tok != tok_define_int )
+ continue;
X printf("\tglobal %s; set %s 0\n", cfg->optionname, cfg->optionname);
X cfg->flags |= GLOBAL_WRITTEN;
X }
X for(cfg = scfg; cfg != NULL; cfg = cfg->next)
X {
- if( cfg->tok != tok_define ) continue;
+ if( cfg->tok != tok_define && cfg->tok != tok_define_int ) continue;
X if (cfg->cond != NULL )
X generate_if(cfg, cfg->cond, -1, 0);
X else
diff -u --recursive --new-file v2.0.36/linux/scripts/tkparse.c linux/scripts/tkparse.c
--- v2.0.36/linux/scripts/tkparse.c Mon May 6 02:26:18 1996
+++ linux/scripts/tkparse.c Sun Jun 13 10:21:05 1999
@@ -345,6 +345,11 @@
X tok = tok_define;
X pnt += 11;
X }
+ else if (strncmp(pnt, "define_int", 10) == 0)
+ {
+ tok = tok_define_int;
+ pnt += 10;
+ }
X else if (strncmp(pnt, "bool", 4) == 0)
X {
X tok = tok_bool;
@@ -446,6 +451,10 @@
X if(*pnt == 'y' || *pnt == 'Y' ) kcfg->value = "1";
X if(*pnt == 'n' || *pnt == 'N' ) kcfg->value = "0";
X if(*pnt == 'm' || *pnt == 'M' ) kcfg->value = "2";
+ break;
+ case tok_define_int:
+ pnt = get_string(pnt, &kcfg->optionname);
+ pnt = get_string(pnt, &kcfg->value);
X break;
X case tok_menuname:
X pnt = get_qstring(pnt, &kcfg->label);
diff -u --recursive --new-file v2.0.36/linux/scripts/tkparse.h linux/scripts/tkparse.h
--- v2.0.36/linux/scripts/tkparse.h Sat Mar 16 23:58:21 1996
+++ linux/scripts/tkparse.h Sun Jun 13 10:21:05 1999
@@ -14,6 +14,7 @@
X tok_hex,
X tok_make,
X tok_define,
+ tok_define_int,
X tok_choose,
X tok_choice,
X tok_endmenu,


SHAR_EOF
true || echo 'restore of patch-2.0.37 failed'

echo 'File patch-2.0.37 is complete' &&
chmod 644 patch-2.0.37 ||


echo 'restore of patch-2.0.37 failed'

Cksum="`cksum < 'patch-2.0.37'`"
if ! test "3834312391 2577935" = "$Cksum"
then
echo 'patch-2.0.37: original Checksum 3834312391 2577935, current one' "$Cksum"
rm -f _shar_wnt_.tmp
rm -f _shar_seq_.tmp
exit 1
fi
rm -f _shar_wnt_.tmp
fi
rm -f _shar_seq_.tmp
echo 'You have unpacked the last part.'

0 new messages