diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/CREDITS linux/CREDITS
--- linux.vanilla/CREDITS Sun Dec 6 00:14:35 1998
+++ linux/CREDITS Mon Dec 14 18:10:10 1998
@@ -796,11 +796,11 @@
D: for Menuconfig's lxdialog.
N: Volker Lendecke
-E: lendecke@namu01.Num.Math.Uni-Goettingen.de
+E: vl@kki.org
D: Kernel smbfs (to mount WfW, NT and OS/2 network drives.)
D: NCP filesystem support (to mount NetWare volumes)
-S: Innersteweg 11
-S: 37081 Goettingen
+S: Von Ossietzky Str. 12
+S: 37085 Goettingen
S: Germany
N: Kevin Lentin
@@ -1244,6 +1244,11 @@
S: Molenbaan 29
S: B2240 Zandhoven
S: Belgium
+
+N: Henning P. Schmiedehausen
+E: hps@tanstaafl.de
+D: added PCI support to the serial driver
+S: Buckenhof, Germany
N: Martin Schulze
E: joey@linux.de
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/Configure.help linux/Documentation/Configure.help
--- linux.vanilla/Documentation/Configure.help Sun Dec 6 00:14:35 1998
+++ linux/Documentation/Configure.help Tue Mar 2 01:00:33 1999
@@ -79,6 +79,14 @@
arch/i386/math-emu/README. If you are not sure, say Y; apart from
resulting in a 45kB bigger kernel, it won't hurt.
+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!)
+
Normal floppy disk support
CONFIG_BLK_DEV_FD
If you want to use your floppy disk drive(s) under Linux, say Y.
@@ -165,6 +173,15 @@
addresses. Normally, just say N here; you will then use the new
driver for all 4 interfaces.
+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.
+
Include IDE/ATAPI CDROM support
CONFIG_BLK_DEV_IDECD
If you have a CDROM drive using the ATAPI protocol, say Y. ATAPI is
@@ -483,6 +500,16 @@
be called fit3.o. You must also have a high-level driver for the
type of device that you want to support.
+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.
+
FreeCom power protocol
CONFIG_PARIDE_FRPW
This option enables support for the Freecom power parallel port IDE
@@ -828,15 +855,33 @@
certain BIOSes if your computer uses a PCI bus system. This is
recommended; say Y.
-Intel 82371 PIIX (Triton I/II) DMA support
+Generic IDE (U)DMA support
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,
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.
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.
System V IPC
CONFIG_SYSVIPC
@@ -1199,6 +1244,65 @@
IP always defragment.
If you want this, say Y.
+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.
+
IP: ipautofw masquerading (EXPERIMENTAL)
CONFIG_IP_MASQUERADE_IPAUTOFW
Richard Lynch's ipautofw allows masquerading to work with protocols
@@ -1833,43 +1937,50 @@
CONFIG_SCSI_NCR53C8XX
This is the BSD ncr driver adapted to Linux for the NCR53C8XX family
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/.
Please read drivers/scsi/README.ncr53c8xx for more information.
- Linux/i386 and Linux/Alpha are supported by this driver.
-
+
Synchronous data transfers frequency
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.
Use normal IO
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.
Not allow targets to disconnect
CONFIG_SCSI_NCR53C8XX_NO_DISCONNECT
@@ -1877,70 +1988,61 @@
device of yours to not support properly the target-disconnect
feature. In that case, you would say Y here. In general however, to
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.
-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.
Maximum number of queued commands
CONFIG_SCSI_NCR53C8XX_MAX_TAGS
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: dormouse@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.
Assume boards are SYMBIOS compatible
CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT
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
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.
Always IN2000 SCSI support
CONFIG_SCSI_IN2000
@@ -2055,21 +2157,59 @@
and removed from the running kernel whenever you want), say M here
and read Documentation/modules.txt.
-Tekram DC390(T) (AMD PCscsi) SCSI support
+Tekram DC390(T) and Am53/79C974 (PCscsi) SCSI support
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=, [sym53c416_1=,]
+
+ 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.
AM53/79C974 PCI SCSI support
CONFIG_SCSI_AM53C974
This is support for the AM53/79C974 SCSI host adapters. Please read
drivers/scsi/README.AM53C974 for details. Also, the SCSI-HOWTO,
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),
GDT SCSI Disk Array Controller support
CONFIG_SCSI_GDTH
@@ -2106,6 +2246,17 @@
Winbond xxx837
National Semiconductor PC87306 (early revisions)
+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
+
Network device support?
CONFIG_NETDEVICES
You can say N here in case you don't intend to connect to any other
@@ -3840,15 +3991,61 @@
NCP filesystem support (to mount NetWare volumes)
CONFIG_NCP_FS
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
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.
Amiga FFS filesystem support (EXPERIMENTAL)
CONFIG_AFFS_FS
@@ -4693,6 +4890,16 @@
registers in the chips up correctly as the specification and Intel
rules require. If you have a PPro or later SMP and one or more CPU's
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.
# need an empty line after last entry, for sed script in Configure.
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/README.DAC960 linux/Documentation/README.DAC960
--- linux.vanilla/Documentation/README.DAC960 Thu Jan 1 01:00:00 1970
+++ linux/Documentation/README.DAC960 Mon Nov 30 07:59:59 1998
@@ -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
+ lnz@dandelion.com
+
+ Copyright 1998 by Leonard N. Zubkoff
+
+
+ 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 support@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 "lnz@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 (support@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-announce-request@dandelion.com" with the line "subscribe" in the
+message body.
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/ide.txt linux/Documentation/ide.txt
--- linux.vanilla/Documentation/ide.txt Fri Jul 24 17:28:55 1998
+++ linux/Documentation/ide.txt Sun Dec 27 21:19:47 1998
@@ -5,6 +5,9 @@
Gadi Oxman -- tapes, disks, whatever
Scott Snyder -- cdroms, ATAPI, audio
+UDMA support was added for various chipsets, from kernel 2.0.35 on. Check
+the udma.txt file in this directory for details.
+
+-----------------------------------------------------------------+
| The hdparm utility for controlling various IDE features is |
| packaged separately. Look for it on popular linux FTP sites. |
@@ -483,3 +486,135 @@
For really high end systems, go for fast/wide 7200rpm SCSI. But it'll cost ya!
mlord@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 - bon@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: mlord@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 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/isdn/README linux/Documentation/isdn/README
--- linux.vanilla/Documentation/isdn/README Sun Dec 6 00:14:35 1998
+++ linux/Documentation/isdn/README Tue Mar 2 00:39:21 1999
@@ -335,9 +335,9 @@
"manual" is a dial mode created to prevent the unexpected dialouts.
In this mode, the interface will never make any connections on its
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.
"manual" is the default.
j) Setup the interface with ifconfig as usual, and set a route to it.
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/more-than-900MB-RAM.txt linux/Documentation/more-than-900MB-RAM.txt
--- linux.vanilla/Documentation/more-than-900MB-RAM.txt Thu Jan 1 01:00:00 1970
+++ linux/Documentation/more-than-900MB-RAM.txt Fri Dec 11 20:35:53 1998
@@ -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
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/paride.txt linux/Documentation/paride.txt
--- linux.vanilla/Documentation/paride.txt Sun Dec 6 00:14:35 1998
+++ linux/Documentation/paride.txt Sun Dec 27 21:08:29 1998
@@ -64,6 +64,7 @@
SyQuest EZ-135, EZ-230 & SparQ drives
Avatar Shark
Imation Superdisk LS-120
+ Maxell Superdisk LS-120
FreeCom Power CD
Hewlett-Packard 5GB and 8GB tape drives
Hewlett-Packard 7100 and 7200 CD-RW drives
@@ -98,6 +99,7 @@
epia Shuttle EPIA (UK)
fit2 FIT TD-2000 (US)
fit3 FIT TD-3000 (US)
+ friq Freecom IQ cable (DE)
frpw Freecom Power (DE)
kbic KingByte KBIC-951A and KBIC-971A (TW)
ktti KT Technology PHd adapter (SG)
@@ -133,10 +135,12 @@
MicroSolutions 8000t tape pt bpck
SyQuest EZ, SparQ pd epat
Imation Superdisk pf epat
+ Maxell Superdisk pf friq
Avatar Shark pd epat
FreeCom CD-ROM pcd frpw
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
2.1 Configuring built-in drivers
@@ -315,7 +319,6 @@
partitioned. Consequently, the pf driver does not support partitioned
media. This may be changed in a future version of the driver.
-
2.5 Using the pt driver
The pt driver for parallel port ATAPI tape drives is a minimal driver.
@@ -323,27 +326,29 @@
For best performance, a block size of 32KB should be used. You will
probably want to set the parallel port delay to 0, if you can.
-
2.6 Using the pg driver
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
in EPP mode, try to use "bidirectional" or "PS/2" mode and 1x speeds only.
3. Troubleshooting
+3.1 Use EPP mode if you can
+
The most common problems that people report with the PARIDE drivers
concern the parallel port CMOS settings. At this time, none of the
PARIDE protocol modules support ECP mode, or any ECP combination modes.
If you are able to do so, please set your parallel port into EPP mode
using your CMOS setup procedure.
+3.2 Check the port delay
+
Some parallel ports cannot reliably transfer data at full speed. To
offset the errors, the PARIDE protocol modules introduce a "port
delay" between each access to the i/o ports. Each protocol sets
@@ -357,6 +362,25 @@
read the comments at the beginning of the driver source files in
linux/drivers/block/paride.
+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
+
While a lot of testing has gone into these drivers to make them work
as smoothly as possible, problems will arise. If you do have problems,
please check all the obvious things first: does the drive work in
@@ -383,6 +407,8 @@
of two ways. Either send it directly to the author of the PARIDE suite,
by e-mail to grant@torque.net, or join the linux-parport mailing list
and post your report there.
+
+3.5 For more information or help
You can join the linux-parport mailing list by sending a mail message
to
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/udma.txt linux/Documentation/udma.txt
--- linux.vanilla/Documentation/udma.txt Thu Jan 1 01:00:00 1970
+++ linux/Documentation/udma.txt Sun Dec 27 21:22:21 1998
@@ -0,0 +1,663 @@
+UDMA information for kernels 2.0.35+
+
+Version 0.4 - July 98
+by Andrew D. Balsa
+
+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 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/MAINTAINERS linux/MAINTAINERS
--- linux.vanilla/MAINTAINERS Sun Dec 6 00:14:35 1998
+++ linux/MAINTAINERS Tue Mar 2 00:39:21 1999
@@ -165,11 +165,23 @@
S: Maintained
CYCLADES ASYNC MUX DRIVER
-P: Marcio Saito
-M: Marcio Saito
+P: Ivan Passos
+M: Ivan Passos
W: http://www.cyclades.com/
S: Supported
+DC390/AM53C974 SCSI driver
+P: Kurt Garloff
+M: kurt@garloff.de
+W: http://www.garloff.de/kurt/linux/dc390/
+S: Maintained
+
+DAC960 RAID DRIVER
+P: Leonard N. Zubkoff
+M: Leonard N. Zubkoff
+L: linux-raid@vger.rutgers.edu
+S: Maintained
+
EATA ISA/EISA/PCI SCSI DRIVER
P: Dario Ballabio
M: dario@milano.europe.dg.com
@@ -279,9 +291,9 @@
NCP FILESYSTEM:
P: Volker Lendecke
-M: lendecke@namu01.Num.Math.Uni-Goettingen.de
+M: vl@kki.org
L: linware@sh.cvut.cz
-S: Maintained
+S: Odd Fixes
NETROM NETWORK LAYER
P: Jon Naylor
@@ -315,7 +327,7 @@
SMB FILESYSTEM:
P: Volker Lendecke
-M: lendecke@namu01.Num.Math.Uni-Goettingen.de
+M: vl@kki.org
L: samba@listproc.anu.edu.au
S: Odd Fixes
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Makefile linux/Makefile
--- linux.vanilla/Makefile Sun Dec 6 00:14:35 1998
+++ linux/Makefile Sun Dec 27 23:52:14 1998
@@ -1,6 +1,6 @@
VERSION = 2
PATCHLEVEL = 0
-SUBLEVEL = 36
+SUBLEVEL = 37
ARCH = i386
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/boot/setup.S linux/arch/i386/boot/setup.S
--- linux.vanilla/arch/i386/boot/setup.S Sun Dec 6 00:14:35 1998
+++ linux/arch/i386/boot/setup.S Sun Dec 6 03:30:21 1998
@@ -482,6 +482,29 @@
out #0x60,al
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
+
! make sure any possible coprocessor is properly reset..
xor ax,ax
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/config.in linux/arch/i386/config.in
--- linux.vanilla/arch/i386/config.in Sun Dec 6 00:14:35 1998
+++ linux/arch/i386/config.in Sun Jan 31 23:35:34 1999
@@ -22,6 +22,20 @@
comment 'General setup'
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
bool 'Networking support' CONFIG_NET
bool 'Limit memory to low 16MB' CONFIG_MAX_16M
bool 'PCI bios support' CONFIG_PCI
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/defconfig linux/arch/i386/defconfig
--- linux.vanilla/arch/i386/defconfig Fri Jul 24 17:28:56 1998
+++ linux/arch/i386/defconfig Fri Dec 11 20:35:53 1998
@@ -55,7 +55,12 @@
# Additional Block Devices
#
# 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
# CONFIG_BLK_DEV_RAM is not set
# CONFIG_BLK_DEV_XD is not set
# CONFIG_PARIDE is not set
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/kernel/head.S linux/arch/i386/kernel/head.S
--- linux.vanilla/arch/i386/kernel/head.S Sun Dec 6 00:14:35 1998
+++ linux/arch/i386/kernel/head.S Mon Dec 14 18:07:26 1998
@@ -9,10 +9,14 @@
*/
.text
+#include
#include
#include
#include
#include
+#include
+#include
+
#define CL_MAGIC_ADDR 0x90020
#define CL_MAGIC 0xA33F
@@ -329,7 +333,7 @@
* sets up a idt with 256 entries pointing to
* ignore_int, interrupt gates. It doesn't actually load
* idt - that can be done only after paging has been enabled
- * and the kernel moved to 0xC0000000. Interrupts
+ * and the kernel moved to PAGE_OFFSET. Interrupts
* are enabled elsewhere, when we can be relatively
* sure everything is ok.
*/
@@ -370,9 +374,9 @@
/* Identity-map the kernel in low 4MB memory for ease of transition */
/* set present bit/user r/w */
movl $ SYMBOL_NAME(pg0)+7,SYMBOL_NAME(swapper_pg_dir)
-/* But the real place is at 0xC0000000 */
+/* But the real place is at PAGE_OFFSET */
/* set present bit/user r/w */
- movl $ SYMBOL_NAME(pg0)+7,SYMBOL_NAME(swapper_pg_dir)+3072
+ movl $ SYMBOL_NAME(pg0)+7,SYMBOL_NAME(swapper_pg_dir)+__USER_PGD_PTRS*4
movl $ SYMBOL_NAME(pg0)+4092,%edi
movl $0x03ff007,%eax /* 4Mb - 4096 + 7 (r/w user,p) */
std
@@ -460,7 +464,7 @@
.word 0
idt_descr:
.word 256*8-1 # idt contains 256 entries
- .long 0xc0000000+SYMBOL_NAME(idt)
+ .long __PAGE_OFFSET+SYMBOL_NAME(idt)
ALIGN
.word 0
@@ -470,19 +474,45 @@
#else
.word (8+2*NR_TASKS)*8-1
#endif
- .long 0xc0000000+SYMBOL_NAME(gdt)
+ .long __PAGE_OFFSET+SYMBOL_NAME(gdt)
/*
* This gdt setup gives the kernel a 1GB address space at virtual
- * address 0xC0000000 - space enough for expansion, I hope.
+ * address PAGE_OFFSET - space enough for expansion, I hope.
*/
+
+#define upper_seg(type,dpl,base,limit) \
+ ((base) & 0xff000000) | \
+ (((base) & 0x00ff0000)>>16) | \
+ (((limit)>>12) & 0xf0000) | \
+ ((dpl)<<13) | \
+ (0x00c09000) | \
+ ((type)<<8)
+
+#define lower_seg(type,dpl,base,limit) \
+ (((base) & 0x0000ffff)<<16) | \
+ ((limit) & 0x0ffff)
+
+#define x86_seg(type,dpl,base,limit) \
+ .long lower_seg(type,dpl,base,limit); \
+ .long upper_seg(type,dpl,base,limit)
+
ENTRY(gdt)
.quad 0x0000000000000000 /* NULL descriptor */
.quad 0x0000000000000000 /* not used */
- .quad 0xc0c39a000000ffff /* 0x10 kernel 1GB code at 0xC0000000 */
- .quad 0xc0c392000000ffff /* 0x18 kernel 1GB data at 0xC0000000 */
- .quad 0x00cbfa000000ffff /* 0x23 user 3GB code at 0x00000000 */
- .quad 0x00cbf2000000ffff /* 0x2b user 3GB data at 0x00000000 */
+
+ /* 0x10 kernel 1GB code at 0xC0000000: */
+ x86_seg(0xa,0,__PAGE_OFFSET,0xffffffff-__PAGE_OFFSET)
+
+ /* 0x18 kernel 1GB data at 0xC0000000: */
+ x86_seg(0x2,0,__PAGE_OFFSET,0xffffffff-__PAGE_OFFSET)
+
+ /* 0x23 user 3GB code at 0x00000000: */
+ x86_seg(0xa,3,0,__PAGE_OFFSET-1)
+
+ /* 0x2b user 3GB data at 0x00000000: */
+ x86_seg(0x2,3,0,__PAGE_OFFSET-1)
+
.quad 0x0000000000000000 /* not used */
.quad 0x0000000000000000 /* not used */
.fill 2*NR_TASKS,8,0 /* space for LDT's and TSS's etc */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/kernel/hexify.c linux/arch/i386/kernel/hexify.c
--- linux.vanilla/arch/i386/kernel/hexify.c Sun Jun 21 18:41:24 1998
+++ linux/arch/i386/kernel/hexify.c Mon Dec 14 18:32:08 1998
@@ -1,7 +1,7 @@
#include
-void main()
+int main()
{
int c;
int comma=0;
@@ -25,7 +25,5 @@
}
if(count)
printf("\n");
- exit(0);
+ return 0;
}
-
-
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/kernel/process.c linux/arch/i386/kernel/process.c
--- linux.vanilla/arch/i386/kernel/process.c Sun Jun 21 18:41:24 1998
+++ linux/arch/i386/kernel/process.c Fri Dec 11 20:35:53 1998
@@ -314,10 +314,10 @@
/* Remap the kernel at virtual address zero, as well as offset zero
from the kernel segment. This assumes the kernel segment starts at
- virtual address 0xc0000000. */
+ virtual address PAGE_OFFSET. */
- memcpy (swapper_pg_dir, swapper_pg_dir + 768,
- sizeof (swapper_pg_dir [0]) * 256);
+ memcpy (swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS,
+ sizeof (swapper_pg_dir [0]) * KERNEL_PGD_PTRS);
/* Make sure the first page is mapped to the start of physical memory.
It is normally not mapped, to trap kernel NULL pointer dereferences. */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c
--- linux.vanilla/arch/i386/kernel/setup.c Sun Dec 6 00:14:36 1998
+++ linux/arch/i386/kernel/setup.c Fri Dec 11 20:35:53 1998
@@ -167,13 +167,14 @@
#endif
/*
- * The 1Gig sanity checker.
+ * The CONFIG_MAX_MEMSIZE sanity checker.
*/
- if (memory_end > 980*1024*1024)
+ if (memory_end > (CONFIG_MAX_MEMSIZE-128)*1024*1024)
{
- printk(KERN_WARNING "Warning only 980Mb will be used.\n");
- memory_end = 980 * 1024 * 1024;
+ memory_end = (CONFIG_MAX_MEMSIZE-128)*1024*1024;
+ printk(KERN_WARNING "ONLY %dMB RAM will be used, see Documentation/more-than-900MB-RAM.txt!.\n", CONFIG_MAX_MEMSIZE-128);
+ udelay(3*1000*1000);
}
if (!MOUNT_ROOT_RDONLY)
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/mm/init.c linux/arch/i386/mm/init.c
--- linux.vanilla/arch/i386/mm/init.c Sun Dec 6 00:14:36 1998
+++ linux/arch/i386/mm/init.c Tue Mar 2 01:47:09 1999
@@ -139,18 +139,22 @@
* the error...
*/
if (!smp_scan_config(639*0x400,0x400)) /* Scan the top 1K of base RAM */
- smp_scan_config(0xF0000,0x10000); /* Scan the 64K of bios */
- /*
- * If it is an SMP machine we should know now, unless the
- * configuration is in an EISA/MCA bus machine with an
- * extended bios data area.
- *
- * there is a real-mode segmented pointer pointing to the
- * 4K EBDA area at 0x40E, calculate and scan it here:
- */
- address = *(unsigned short *)phys_to_virt(0x40E);
- address<<=4;
- smp_scan_config(address, 0x1000);
+ {
+ if(!(smp_scan_config(0xF0000,0x10000)) /* Scan the 64K of bios */
+ {
+ /*
+ * If it is an SMP machine we should know now, unless the
+ * configuration is in an EISA/MCA bus machine with an
+ * extended bios data area.
+ *
+ * there is a real-mode segmented pointer pointing to the
+ * 4K EBDA area at 0x40E, calculate and scan it here:
+ */
+ address = *(unsigned short *)phys_to_virt(0x40E);
+ address<<=4;
+ smp_scan_config(address, 0x1000);
+ }
+ }
}
/*
* If it is an SMP machine we should know now, unless the configuration
@@ -188,14 +192,14 @@
#endif
wp_works_ok = 1;
pgd_val(pg_dir[0]) = _PAGE_TABLE | _PAGE_4M | address;
- pgd_val(pg_dir[768]) = _PAGE_TABLE | _PAGE_4M | address;
+ pgd_val(pg_dir[USER_PGD_PTRS]) = _PAGE_TABLE | _PAGE_4M | address;
pg_dir++;
address += 4*1024*1024;
continue;
}
#endif
- /* map the memory at virtual addr 0xC0000000 */
- pg_table = (pte_t *) (PAGE_MASK & pgd_val(pg_dir[768]));
+ /* map the memory at virtual addr PAGE_OFFSET */
+ pg_table = (pte_t *) (PAGE_MASK & pgd_val(pg_dir[USER_PGD_PTRS]));
if (!pg_table) {
pg_table = (pte_t *) start_mem;
start_mem += PAGE_SIZE;
@@ -203,7 +207,7 @@
/* also map it temporarily at 0x0000000 for init */
pgd_val(pg_dir[0]) = _PAGE_TABLE | (unsigned long) pg_table;
- pgd_val(pg_dir[768]) = _PAGE_TABLE | (unsigned long) pg_table;
+ pgd_val(pg_dir[USER_PGD_PTRS]) = _PAGE_TABLE | (unsigned long) pg_table;
pg_dir++;
for (tmp = 0 ; tmp < PTRS_PER_PTE ; tmp++,pg_table++) {
if (address < end_mem)
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/Config.in linux/drivers/block/Config.in
--- linux.vanilla/drivers/block/Config.in Fri Jul 24 17:28:56 1998
+++ linux/drivers/block/Config.in Tue Mar 2 00:39:42 1999
@@ -11,6 +11,9 @@
bool 'Old harddisk (MFM/RLL/IDE) driver' CONFIG_BLK_DEV_HD_ONLY
else
bool ' Use old disk-only driver on primary interface' CONFIG_BLK_DEV_HD_IDE
+ if [ "$CONFIG_BLK_DEV_HD_IDE" != "n" ]; then
+ bool ' Use multi-mode by default' CONFIG_IDEDISK_MULTI_MODE
+ fi
bool ' Include IDE/ATAPI CDROM support' CONFIG_BLK_DEV_IDECD
bool ' Include IDE/ATAPI TAPE support' CONFIG_BLK_DEV_IDETAPE
bool ' Include IDE/ATAPI FLOPPY support (new)' CONFIG_BLK_DEV_IDEFLOPPY
@@ -23,6 +26,9 @@
if [ "$CONFIG_PCI" = "y" ]; then
bool ' RZ1000 chipset bugfix/support' CONFIG_BLK_DEV_RZ1000
bool ' Intel 82371 PIIX (Triton I/II) DMA support' CONFIG_BLK_DEV_TRITON
+ if [ "$CONFIG_BLK_DEV_TRITON" = "y" ]; then
+ bool ' Boot off-board chipsets first support' CONFIG_BLK_DEV_OFFBOARD
+ fi
fi
bool ' Other IDE chipset support' CONFIG_IDE_CHIPSETS
if [ "$CONFIG_IDE_CHIPSETS" = "y" ]; then
@@ -53,6 +59,15 @@
bool ' Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD
fi
tristate 'XT harddisk support' CONFIG_BLK_DEV_XD
+if [ "$CONFIG_PCI" = "y" ]; then
+ bool 'Mylex DAC960 PCI RAID Controller support' CONFIG_BLK_DEV_DAC960
+fi
+
+tristate 'Compaq SMART2 support' CONFIG_BLK_CPQ_DA
+if [ "$CONFIG_BLK_CPQ_DA" = "y" -o "$CONFIG_BLK_CPQ_DA" = "m" ]; then
+ bool ' Support for PCI SMART-2 Controllers' CONFIG_BLK_CPQ_DA_PCI
+ bool ' Support for EISA SMART-2 Controllers' CONFIG_BLK_CPQ_DA_EISA
+fi
tristate 'Parallel port IDE device support' CONFIG_PARIDE
if [ "$CONFIG_PARIDE" = "y" -o "$CONFIG_PARIDE" = "m" ]; then
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/DAC960.c linux/drivers/block/DAC960.c
--- linux.vanilla/drivers/block/DAC960.c Thu Jan 1 01:00:00 1970
+++ linux/drivers/block/DAC960.c Fri Jan 29 14:27:56 1999
@@ -0,0 +1,1980 @@
+/*
+
+ Linux Driver for Mylex DAC960 PCI RAID Controllers
+
+ Copyright 1998 by Leonard N. Zubkoff
+
+ This program is free software; you may redistribute and/or modify it under
+ the terms of the GNU General Public License Version 2 as published by the
+ Free Software Foundation.
+
+ 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 complete details.
+
+ The author respectfully requests that any modifications to this software be
+ sent directly to him for evaluation and testing.
+
+*/
+
+
+#define DAC960_DriverVersion "2.0.0 Beta3"
+#define DAC960_DriverDate "29 November 1998"
+
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "DAC960.h"
+
+
+/*
+ DAC960_ControllerCount is the number of DAC960 Controllers.
+*/
+
+static int
+ DAC960_ControllerCount = 0;
+
+
+/*
+ DAC960_Controllers is an array of pointers to the DAC960 Controller
+ structures.
+*/
+
+static DAC960_Controller_T
+ *DAC960_Controllers[DAC960_MaxControllers] = { NULL };
+
+
+/*
+ DAC960_FileOperations is the File Operations structure for DAC960 Logical
+ Disk Devices.
+*/
+
+static FileOperations_T
+ DAC960_FileOperations =
+ { lseek: NULL,
+ read: block_read,
+ write: block_write,
+ readdir: NULL,
+ select: NULL,
+ ioctl: DAC960_Ioctl,
+ mmap: NULL,
+ open: DAC960_Open,
+ release: DAC960_Release,
+ fsync: block_fsync,
+ fasync: NULL,
+ check_media_change: NULL,
+ revalidate: NULL };
+
+
+/*
+ DAC960_AnnounceDriver announces the Driver Version and Date, Author's Name,
+ Copyright Notice, and Electronic Mail Address.
+*/
+
+static void DAC960_AnnounceDriver(DAC960_Controller_T *Controller)
+{
+ DAC960_Announce("***** DAC960 RAID Driver Version "
+ DAC960_DriverVersion " of "
+ DAC960_DriverDate " *****\n", Controller);
+ DAC960_Announce("Copyright 1998 by Leonard N. Zubkoff "
+ "\n", Controller);
+}
+
+
+/*
+ DAC960_Failure prints a standardized error message, and then returns false.
+*/
+
+static boolean DAC960_Failure(DAC960_Controller_T *Controller,
+ char *ErrorMessage)
+{
+ DAC960_Error("While configuring DAC960 PCI RAID Controller at\n",
+ Controller);
+ if (Controller->IO_Address == 0)
+ DAC960_Error("PCI Bus %d Device %d Function %d I/O Address N/A "
+ "PCI Address 0x%X\n", Controller,
+ Controller->Bus, Controller->Device,
+ Controller->Function, Controller->PCI_Address);
+ else DAC960_Error("PCI Bus %d Device %d Function %d I/O Address "
+ "0x%X PCI Address 0x%X\n", Controller,
+ Controller->Bus, Controller->Device,
+ Controller->Function, Controller->IO_Address,
+ Controller->PCI_Address);
+ DAC960_Error("%s FAILED - DETACHING\n", Controller, ErrorMessage);
+ return false;
+}
+
+
+/*
+ DAC960_ClearCommand clears critical fields of Command.
+*/
+
+static inline void DAC960_ClearCommand(DAC960_Command_T *Command)
+{
+ DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox;
+ CommandMailbox->Words[0] = 0;
+ CommandMailbox->Words[1] = 0;
+ CommandMailbox->Words[2] = 0;
+ CommandMailbox->Words[3] = 0;
+ Command->CommandStatus = 0;
+}
+
+
+/*
+ DAC960_AllocateCommand allocates a Command structure from Controller's
+ free list.
+*/
+
+static inline DAC960_Command_T *DAC960_AllocateCommand(DAC960_Controller_T
+ *Controller)
+{
+ DAC960_Command_T *Command = Controller->FreeCommands;
+ if (Command == NULL) return NULL;
+ Controller->FreeCommands = Command->Next;
+ Command->Next = NULL;
+ return Command;
+}
+
+
+/*
+ DAC960_DeallocateCommand deallocates Command, returning it to Controller's
+ free list.
+*/
+
+static inline void DAC960_DeallocateCommand(DAC960_Command_T *Command)
+{
+ DAC960_Controller_T *Controller = Command->Controller;
+ Command->Next = Controller->FreeCommands;
+ Controller->FreeCommands = Command;
+}
+
+
+/*
+ DAC960_QueueCommand queues Command.
+*/
+
+static void DAC960_QueueCommand(DAC960_Command_T *Command)
+{
+ DAC960_Controller_T *Controller = Command->Controller;
+ void *ControllerBaseAddress = Controller->BaseAddress;
+ DAC960_V4_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox;
+ DAC960_V4_CommandMailbox_T *NextCommandMailbox;
+ CommandMailbox->Common.CommandIdentifier = Command - Controller->Commands;
+ switch (Controller->ControllerType)
+ {
+ case DAC960_V4_Controller:
+ NextCommandMailbox = Controller->NextCommandMailbox;
+ DAC960_V4_WriteCommandMailbox(NextCommandMailbox, CommandMailbox);
+ if (Controller->PreviousCommandMailbox->Words[0] == 0)
+ DAC960_V4_NewCommand(ControllerBaseAddress);
+ Controller->PreviousCommandMailbox = NextCommandMailbox;
+ if (++NextCommandMailbox > Controller->LastCommandMailbox)
+ NextCommandMailbox = Controller->FirstCommandMailbox;
+ Controller->NextCommandMailbox = NextCommandMailbox;
+ break;
+ case DAC960_V3_Controller:
+ while (DAC960_V3_MailboxFullP(ControllerBaseAddress))
+ udelay(1);
+ DAC960_V3_WriteCommandMailbox(ControllerBaseAddress, CommandMailbox);
+ DAC960_V3_NewCommand(ControllerBaseAddress);
+ break;
+ }
+}
+
+
+/*
+ DAC960_ExecuteCommand executes Command and waits for completion. It
+ returns true on success and false on failure.
+*/
+
+static boolean DAC960_ExecuteCommand(DAC960_Command_T *Command)
+{
+ Semaphore_T Semaphore = MUTEX_LOCKED;
+ Command->Semaphore = &Semaphore;
+ DAC960_QueueCommand(Command);
+ down(&Semaphore);
+ return Command->CommandStatus == DAC960_NormalCompletion;
+}
+
+
+/*
+ DAC960_ExecuteType3 executes a DAC960 Type 3 Command and waits for
+ completion. It returns true on success and false on failure.
+*/
+
+static boolean DAC960_ExecuteType3(DAC960_Controller_T *Controller,
+ DAC960_CommandOpcode_T CommandOpcode,
+ void *DataPointer)
+{
+ DAC960_Command_T *Command = DAC960_AllocateCommand(Controller);
+ DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox;
+ boolean Result;
+ DAC960_ClearCommand(Command);
+ Command->CommandType = DAC960_ImmediateCommand;
+ CommandMailbox->Type3.CommandOpcode = CommandOpcode;
+ CommandMailbox->Type3.BusAddress = Virtual_to_Bus(DataPointer);
+ Result = DAC960_ExecuteCommand(Command);
+ DAC960_DeallocateCommand(Command);
+ return Result;
+}
+
+
+/*
+ DAC960_ExecuteType3D executes a DAC960 Type 3D Command and waits for
+ completion. It returns true on success and false on failure.
+*/
+
+static boolean DAC960_ExecuteType3D(DAC960_Controller_T *Controller,
+ DAC960_CommandOpcode_T CommandOpcode,
+ unsigned char Channel,
+ unsigned char TargetID,
+ void *DataPointer)
+{
+ DAC960_Command_T *Command = DAC960_AllocateCommand(Controller);
+ DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox;
+ boolean Result;
+ DAC960_ClearCommand(Command);
+ Command->CommandType = DAC960_ImmediateCommand;
+ CommandMailbox->Type3D.CommandOpcode = CommandOpcode;
+ CommandMailbox->Type3D.Channel = Channel;
+ CommandMailbox->Type3D.TargetID = TargetID;
+ CommandMailbox->Type3D.BusAddress = Virtual_to_Bus(DataPointer);
+ Result = DAC960_ExecuteCommand(Command);
+ DAC960_DeallocateCommand(Command);
+ return Result;
+}
+
+
+/*
+ DAC960_V4_EnableMemoryMailboxInterface enables the V4 Memory Mailbox
+ Interface.
+*/
+
+static boolean DAC960_V4_EnableMemoryMailboxInterface(DAC960_Controller_T
+ *Controller)
+{
+ void *ControllerBaseAddress = Controller->BaseAddress;
+ DAC960_V4_CommandMailbox_T *CommandMailboxesMemory;
+ DAC960_V4_StatusMailbox_T *StatusMailboxesMemory;
+ DAC960_CommandMailbox_T CommandMailbox;
+ DAC960_CommandStatus_T CommandStatus;
+ CommandMailboxesMemory =
+ (DAC960_V4_CommandMailbox_T *) __get_free_pages(GFP_KERNEL, 1, 0);
+ memset(CommandMailboxesMemory, 0, PAGE_SIZE << 1);
+ Controller->FirstCommandMailbox = CommandMailboxesMemory;
+ CommandMailboxesMemory += DAC960_CommandMailboxCount - 1;
+ Controller->LastCommandMailbox = CommandMailboxesMemory;
+ Controller->NextCommandMailbox = Controller->FirstCommandMailbox;
+ Controller->PreviousCommandMailbox = Controller->LastCommandMailbox;
+ StatusMailboxesMemory =
+ (DAC960_V4_StatusMailbox_T *) (CommandMailboxesMemory + 1);
+ Controller->FirstStatusMailbox = StatusMailboxesMemory;
+ StatusMailboxesMemory += DAC960_StatusMailboxCount - 1;
+ Controller->LastStatusMailbox = StatusMailboxesMemory;
+ Controller->NextStatusMailbox = Controller->FirstStatusMailbox;
+ /* Enable the Memory Mailbox Interface. */
+ CommandMailbox.TypeX.CommandOpcode = 0x2B;
+ CommandMailbox.TypeX.CommandIdentifier = 0;
+ CommandMailbox.TypeX.CommandOpcode2 = 0x10;
+ CommandMailbox.TypeX.CommandMailboxesBusAddress =
+ Virtual_to_Bus(Controller->FirstCommandMailbox);
+ CommandMailbox.TypeX.StatusMailboxesBusAddress =
+ Virtual_to_Bus(Controller->FirstStatusMailbox);
+ while (DAC960_V4_MailboxFullP(ControllerBaseAddress))
+ udelay(1);
+ DAC960_V4_WriteLegacyCommand(ControllerBaseAddress, &CommandMailbox);
+ DAC960_V4_NewCommand(ControllerBaseAddress);
+ while (!DAC960_V4_StatusAvailableP(ControllerBaseAddress))
+ udelay(1);
+ CommandStatus = DAC960_V4_ReadStatusRegister(ControllerBaseAddress);
+ DAC960_V4_AcknowledgeInterrupt(ControllerBaseAddress);
+ DAC960_V4_AcknowledgeStatus(ControllerBaseAddress);
+ return CommandStatus == DAC960_NormalCompletion;
+}
+
+
+/*
+ DAC960_DetectControllers detects DAC960 PCI RAID Controllers by interrogating
+ the PCI Configuration Space for DeviceID.
+*/
+
+static void DAC960_DetectControllers(unsigned short DeviceID)
+{
+ unsigned char Bus, DeviceFunction, IRQ_Channel;
+ unsigned int BaseAddress0, BaseAddress1;
+ unsigned int MemoryWindowSize = 0;
+ unsigned short Index = 0;
+ while (pcibios_find_device(PCI_VENDOR_ID_MYLEX, DeviceID,
+ Index++, &Bus, &DeviceFunction) == 0)
+ {
+ DAC960_Controller_T *Controller = (DAC960_Controller_T *)
+ kmalloc(sizeof(DAC960_Controller_T), GFP_ATOMIC);
+ DAC960_ControllerType_T ControllerType = 0;
+ DAC960_IO_Address_T IO_Address = 0;
+ DAC960_PCI_Address_T PCI_Address = 0;
+ unsigned char Device = DeviceFunction >> 3;
+ unsigned char Function = DeviceFunction & 0x7;
+ pcibios_read_config_dword(Bus, DeviceFunction,
+ PCI_BASE_ADDRESS_0, &BaseAddress0);
+ pcibios_read_config_dword(Bus, DeviceFunction,
+ PCI_BASE_ADDRESS_1, &BaseAddress1);
+ pcibios_read_config_byte(Bus, DeviceFunction,
+ PCI_INTERRUPT_LINE, &IRQ_Channel);
+ switch (DeviceID)
+ {
+ case PCI_DEVICE_ID_MYLEX_DAC960P_V4:
+ ControllerType = DAC960_V4_Controller;
+ PCI_Address = BaseAddress0 & PCI_BASE_ADDRESS_MEM_MASK;
+ MemoryWindowSize = DAC960_V4_RegisterWindowSize;
+ break;
+ case PCI_DEVICE_ID_MYLEX_DAC960P_V3:
+ ControllerType = DAC960_V3_Controller;
+ IO_Address = BaseAddress0 & PCI_BASE_ADDRESS_IO_MASK;
+ PCI_Address = BaseAddress1 & PCI_BASE_ADDRESS_MEM_MASK;
+ MemoryWindowSize = DAC960_V3_RegisterWindowSize;
+ break;
+ }
+ if (DAC960_ControllerCount == DAC960_MaxControllers)
+ {
+ DAC960_Error("More than %d DAC960 Controllers detected - "
+ "ignoring from Controller at\n",
+ NULL, DAC960_MaxControllers);
+ goto Failure;
+ }
+ if (Controller == NULL)
+ {
+ DAC960_Error("Unable to allocate Controller structure for "
+ "Controller at\n", NULL);
+ goto Failure;
+ }
+ memset(Controller, 0, sizeof(DAC960_Controller_T));
+ Controller->ControllerNumber = DAC960_ControllerCount;
+ DAC960_Controllers[DAC960_ControllerCount++] = Controller;
+ if (IRQ_Channel == 0 || IRQ_Channel >= NR_IRQS)
+ {
+ DAC960_Error("IRQ Channel %d illegal for Controller at\n",
+ NULL, IRQ_Channel);
+ goto Failure;
+ }
+ Controller->ControllerType = ControllerType;
+ Controller->IO_Address = IO_Address;
+ Controller->PCI_Address = PCI_Address;
+ Controller->Bus = Bus;
+ Controller->Device = Device;
+ Controller->Function = Function;
+ /*
+ Acquire shared access to the IRQ Channel.
+ */
+ strcpy(Controller->FullModelName, "DAC960");
+ if (request_irq(IRQ_Channel, DAC960_InterruptHandler,
+ SA_INTERRUPT | SA_SHIRQ, Controller->FullModelName,
+ Controller) < 0)
+ {
+ DAC960_Error("Unable to acquire IRQ Channel %d for Controller at\n",
+ NULL, IRQ_Channel);
+ goto Failure;
+ }
+ Controller->IRQ_Channel = IRQ_Channel;
+ /*
+ Map the Controller Register Window.
+ */
+ if (MemoryWindowSize < PAGE_SIZE)
+ MemoryWindowSize = PAGE_SIZE;
+ Controller->MemoryMappedAddress =
+ ioremap_nocache(PCI_Address & PAGE_MASK, MemoryWindowSize);
+ Controller->BaseAddress =
+ Controller->MemoryMappedAddress + (PCI_Address & ~PAGE_MASK);
+ if (Controller->MemoryMappedAddress == NULL)
+ {
+ DAC960_Error("Unable to map Controller Register Window for "
+ "Controller at\n", NULL);
+ goto Failure;
+ }
+ switch (DeviceID)
+ {
+ case PCI_DEVICE_ID_MYLEX_DAC960P_V4:
+ DAC960_V4_DisableInterrupts(Controller->BaseAddress);
+ if (!DAC960_V4_EnableMemoryMailboxInterface(Controller))
+ {
+ DAC960_Error("Unable to Enable V4 Memory Mailbox Interface "
+ "for Controller at\n", NULL);
+ goto Failure;
+ }
+ DAC960_V4_EnableInterrupts(Controller->BaseAddress);
+ break;
+ case PCI_DEVICE_ID_MYLEX_DAC960P_V3:
+ request_region(Controller->IO_Address, 0x80,
+ Controller->FullModelName);
+ DAC960_V3_EnableInterrupts(Controller->BaseAddress);
+ break;
+ }
+ Controller->Commands[0].Controller = Controller;
+ Controller->Commands[0].Next = NULL;
+ Controller->FreeCommands = &Controller->Commands[0];
+ continue;
+ Failure:
+ if (IO_Address == 0)
+ DAC960_Error("PCI Bus %d Device %d Function %d I/O Address N/A "
+ "PCI Address 0x%X\n", NULL,
+ Bus, Device, Function, PCI_Address);
+ else DAC960_Error("PCI Bus %d Device %d Function %d I/O Address "
+ "0x%X PCI Address 0x%X\n", NULL,
+ Bus, Device, Function, IO_Address, PCI_Address);
+ if (Controller == NULL) break;
+ if (Controller->IRQ_Channel > 0)
+ free_irq(IRQ_Channel, Controller);
+ if (Controller->MemoryMappedAddress != NULL)
+ iounmap(Controller->MemoryMappedAddress);
+ kfree(Controller);
+ break;
+ }
+}
+
+
+/*
+ DAC960_ReadControllerConfiguration reads the Configuration Information
+ from Controller and initializes the Controller structure.
+*/
+
+static boolean DAC960_ReadControllerConfiguration(DAC960_Controller_T
+ *Controller)
+{
+ DAC960_Enquiry2_T Enquiry2;
+ DAC960_Config2_T Config2;
+ int Channel, TargetID;
+ if (!DAC960_ExecuteType3(Controller, DAC960_Enquiry,
+ &Controller->Enquiry[0]))
+ return DAC960_Failure(Controller, "ENQUIRY");
+ if (!DAC960_ExecuteType3(Controller, DAC960_Enquiry2, &Enquiry2))
+ return DAC960_Failure(Controller, "ENQUIRY2");
+ if (!DAC960_ExecuteType3(Controller, DAC960_ReadConfig2, &Config2))
+ return DAC960_Failure(Controller, "READ CONFIG2");
+ if (!DAC960_ExecuteType3(Controller, DAC960_GetLogicalDriveInformation,
+ &Controller->LogicalDriveInformation[0]))
+ return DAC960_Failure(Controller, "GET LOGICAL DRIVE INFORMATION");
+ for (Channel = 0; Channel < Enquiry2.ActualChannels; Channel++)
+ for (TargetID = 0; TargetID < DAC960_MaxTargets; TargetID++)
+ if (!DAC960_ExecuteType3D(Controller, DAC960_GetDeviceState,
+ Channel, TargetID,
+ &Controller->DeviceState[0][Channel][TargetID]))
+ return DAC960_Failure(Controller, "GET DEVICE STATE");
+ /*
+ Initialize the Controller Model Name and Full Model Name fields.
+ */
+ switch (Enquiry2.HardwareID.SubModel)
+ {
+ case DAC960_P_PD_PU:
+ if (Enquiry2.SCSICapability.BusSpeed == DAC960_Ultra)
+ strcpy(Controller->ModelName, "DAC960PU");
+ else strcpy(Controller->ModelName, "DAC960PD");
+ break;
+ case DAC960_PL:
+ strcpy(Controller->ModelName, "DAC960PL");
+ break;
+ case DAC960_PG:
+ strcpy(Controller->ModelName, "DAC960PG");
+ break;
+ case DAC960_PJ:
+ strcpy(Controller->ModelName, "DAC960PJ");
+ break;
+ case DAC960_PTL_0:
+ strcpy(Controller->ModelName, "DAC960PTL-0");
+ break;
+ case DAC960_PTL_1:
+ strcpy(Controller->ModelName, "DAC960PTL-1");
+ break;
+ default:
+ return DAC960_Failure(Controller, "MODEL VERIFICATION");
+ }
+ strcpy(Controller->FullModelName, "Mylex ");
+ strcat(Controller->FullModelName, Controller->ModelName);
+ /*
+ Initialize the Controller Firmware Version field and verify that it
+ is a supported firmware version. The supported firmware versions are:
+
+ DAC960PTL/PJ/PG 4.06 and above
+ DAC960PU/PD/PL 3.51 and above
+ */
+ sprintf(Controller->FirmwareVersion, "%d.%02d-%c-%02d",
+ Enquiry2.FirmwareID.MajorVersion, Enquiry2.FirmwareID.MinorVersion,
+ Enquiry2.FirmwareID.FirmwareType, Enquiry2.FirmwareID.TurnID);
+ if (!((Controller->FirmwareVersion[0] == '4' &&
+ strcmp(Controller->FirmwareVersion, "4.06") >= 0) ||
+ (Controller->FirmwareVersion[0] == '3' &&
+ strcmp(Controller->FirmwareVersion, "3.51") >= 0)))
+ {
+ DAC960_Failure(Controller, "FIRMWARE VERSION VERIFICATION");
+ DAC960_Error("Firmware Version = '%s'\n", Controller,
+ Controller->FirmwareVersion);
+ return false;
+ }
+ /*
+ Initialize the Controller Channels, Memory Size, and SAF-TE Fault
+ Management Enabled fields.
+ */
+ Controller->Channels = Enquiry2.ActualChannels;
+ Controller->MemorySize = Enquiry2.MemorySize >> 20;
+ Controller->SAFTE_FaultManagementEnabled =
+ Enquiry2.FaultManagementType == DAC960_SAFTE;
+ /*
+ Initialize the Controller Queue Depth, Driver Queue Depth, Logical Drive
+ Count, Maximum Blocks per Command, and Maximum Scatter/Gather Segments.
+ The Driver Queue Depth must be at most one less than the Controller Queue
+ Depth to allow for an automatic drive rebuild operation.
+ */
+ Controller->ControllerQueueDepth = Controller->Enquiry[0].MaxCommands;
+ Controller->DriverQueueDepth = Controller->ControllerQueueDepth - 1;
+ Controller->LogicalDriveCount = Controller->Enquiry[0].NumberOfLogicalDrives;
+ Controller->MaxBlocksPerCommand = Enquiry2.MaxBlocksPerCommand;
+ Controller->MaxScatterGatherSegments = Enquiry2.MaxScatterGatherEntries;
+ /*
+ Initialize the Stripe Size, Segment Size, and Geometry Translation.
+ */
+ Controller->StripeSize = Config2.BlocksPerStripe * Config2.BlockFactor
+ >> (10 - DAC960_BlockSizeBits);
+ Controller->SegmentSize = Config2.BlocksPerCacheLine * Config2.BlockFactor
+ >> (10 - DAC960_BlockSizeBits);
+ switch (Config2.DriveGeometry)
+ {
+ case DAC960_Geometry_128_32:
+ Controller->GeometryTranslationHeads = 128;
+ Controller->GeometryTranslationSectors = 32;
+ break;
+ case DAC960_Geometry_255_63:
+ Controller->GeometryTranslationHeads = 255;
+ Controller->GeometryTranslationSectors = 63;
+ break;
+ default:
+ return DAC960_Failure(Controller, "CONFIG2 DRIVE GEOMETRY");
+ }
+ return true;
+}
+
+
+/*
+ DAC960_ReportControllerConfiguration reports the configuration of
+ Controller.
+*/
+
+static boolean DAC960_ReportControllerConfiguration(DAC960_Controller_T
+ *Controller)
+{
+ int LogicalDriveNumber, Channel, TargetID;
+ DAC960_Info("Configuring Mylex %s PCI RAID Controller\n",
+ Controller, Controller->ModelName);
+ DAC960_Info(" Firmware Version: %s, Channels: %d, Memory Size: %dMB\n",
+ Controller, Controller->FirmwareVersion,
+ Controller->Channels, Controller->MemorySize);
+ DAC960_Info(" PCI Bus: %d, Device: %d, Function: %d, I/O Address: ",
+ Controller, Controller->Bus,
+ Controller->Device, Controller->Function);
+ if (Controller->IO_Address == 0)
+ DAC960_Info("Unassigned\n", Controller);
+ else DAC960_Info("0x%X\n", Controller, Controller->IO_Address);
+ DAC960_Info(" PCI Address: 0x%X mapped at 0x%lX, IRQ Channel: %d\n",
+ Controller, Controller->PCI_Address,
+ (unsigned long) Controller->BaseAddress,
+ Controller->IRQ_Channel);
+ DAC960_Info(" Controller Queue Depth: %d, "
+ "Maximum Blocks per Command: %d\n",
+ Controller, Controller->ControllerQueueDepth,
+ Controller->MaxBlocksPerCommand);
+ DAC960_Info(" Driver Queue Depth: %d, "
+ "Maximum Scatter/Gather Segments: %d\n",
+ Controller, Controller->DriverQueueDepth,
+ Controller->MaxScatterGatherSegments);
+ DAC960_Info(" Stripe Size: %dKB, Segment Size: %dKB, "
+ "BIOS Geometry: %d/%d\n", Controller,
+ Controller->StripeSize,
+ Controller->SegmentSize,
+ Controller->GeometryTranslationHeads,
+ Controller->GeometryTranslationSectors);
+ if (Controller->SAFTE_FaultManagementEnabled)
+ DAC960_Info(" SAF-TE Fault Management Enabled\n", Controller);
+ DAC960_Info(" Physical Devices:\n", Controller);
+ for (Channel = 0; Channel < Controller->Channels; Channel++)
+ for (TargetID = 0; TargetID < DAC960_MaxTargets; TargetID++)
+ {
+ DAC960_DeviceState_T *DeviceState =
+ &Controller->DeviceState[0][Channel][TargetID];
+ if (!DeviceState->Present) continue;
+ switch (DeviceState->DeviceType)
+ {
+ case DAC960_OtherType:
+ DAC960_Info(" %d:%d - Other\n", Controller, Channel, TargetID);
+ break;
+ case DAC960_DiskType:
+ DAC960_Info(" %d:%d - Disk: %s, %d blocks\n", Controller,
+ Channel, TargetID,
+ (DeviceState->DeviceState == DAC960_Device_Dead
+ ? "Dead"
+ : DeviceState->DeviceState == DAC960_Device_WriteOnly
+ ? "Write-Only"
+ : DeviceState->DeviceState == DAC960_Device_Online
+ ? "Online" : "Standby"),
+ DeviceState->DiskSize);
+ break;
+ case DAC960_SequentialType:
+ DAC960_Info(" %d:%d - Sequential\n", Controller,
+ Channel, TargetID);
+ break;
+ case DAC960_CDROM_or_WORM_Type:
+ DAC960_Info(" %d:%d - CD-ROM or WORM\n", Controller,
+ Channel, TargetID);
+ break;
+ }
+
+ }
+ DAC960_Info(" Logical Drives:\n", Controller);
+ for (LogicalDriveNumber = 0;
+ LogicalDriveNumber < Controller->LogicalDriveCount;
+ LogicalDriveNumber++)
+ {
+ DAC960_LogicalDriveInformation_T *LogicalDriveInformation =
+ &Controller->LogicalDriveInformation[0][LogicalDriveNumber];
+ DAC960_Info(" /dev/rd/c%dd%d: RAID-%d, %s, %d blocks, %s\n",
+ Controller, Controller->ControllerNumber, LogicalDriveNumber,
+ LogicalDriveInformation->RAIDLevel,
+ (LogicalDriveInformation->LogicalDriveState ==
+ DAC960_LogicalDrive_Online
+ ? "Online"
+ : LogicalDriveInformation->LogicalDriveState ==
+ DAC960_LogicalDrive_Critical
+ ? "Critical" : "Offline"),
+ LogicalDriveInformation->LogicalDriveSize,
+ (LogicalDriveInformation->WriteBack
+ ? "Write Back" : "Write Thru"));
+ }
+ DAC960_Info("\n", Controller);
+ return true;
+}
+
+
+/*
+ DAC960_RegisterBlockDevice registers the Block Device structures
+ associated with Controller.
+*/
+
+static boolean DAC960_RegisterBlockDevice(DAC960_Controller_T *Controller)
+{
+ static void (*RequestFunctions[DAC960_MaxControllers])(void) =
+ { DAC960_RequestFunction0, DAC960_RequestFunction1,
+ DAC960_RequestFunction2, DAC960_RequestFunction3,
+ DAC960_RequestFunction4, DAC960_RequestFunction5,
+ DAC960_RequestFunction6, DAC960_RequestFunction7 };
+ int MajorNumber = DAC960_MAJOR + Controller->ControllerNumber;
+ GenericDiskInfo_T *GenericDiskInfo;
+ int MinorNumber;
+ /*
+ Register the Block Device Major Number for this DAC960 Controller.
+ */
+ if (register_blkdev(MajorNumber, "rd", &DAC960_FileOperations) < 0)
+ {
+ DAC960_Error("UNABLE TO ACQUIRE MAJOR NUMBER %d - DETACHING\n",
+ Controller, MajorNumber);
+ return false;
+ }
+ /*
+ Initialize the I/O Request Function.
+ */
+ blk_dev[MajorNumber].request_fn =
+ RequestFunctions[Controller->ControllerNumber];
+ /*
+ Initialize the Disk Partitions array, Partition Sizes array, Block Sizes
+ array, Max Sectors per Request array, and Max Segments per Request array.
+ */
+ for (MinorNumber = 0; MinorNumber < DAC960_MinorCount; MinorNumber++)
+ {
+ Controller->BlockSizes[MinorNumber] = BLOCK_SIZE;
+ Controller->MaxSectorsPerRequest[MinorNumber] =
+ Controller->MaxBlocksPerCommand;
+ Controller->MaxSegmentsPerRequest[MinorNumber] =
+ Controller->MaxScatterGatherSegments;
+ }
+ Controller->GenericDiskInfo.part = Controller->DiskPartitions;
+ Controller->GenericDiskInfo.sizes = Controller->PartitionSizes;
+ blksize_size[MajorNumber] = Controller->BlockSizes;
+ max_sectors[MajorNumber] = Controller->MaxSectorsPerRequest;
+ max_segments[MajorNumber] = Controller->MaxSegmentsPerRequest;
+ /*
+ Initialize Read Ahead to 128 sectors.
+ */
+ read_ahead[MajorNumber] = 128;
+ /*
+ Complete initialization of the Generic Disk Information structure.
+ */
+ Controller->GenericDiskInfo.major = MajorNumber;
+ Controller->GenericDiskInfo.major_name = "rd";
+ Controller->GenericDiskInfo.minor_shift = DAC960_MaxPartitionsBits;
+ Controller->GenericDiskInfo.max_p = DAC960_MaxPartitions;
+ Controller->GenericDiskInfo.max_nr = DAC960_MaxLogicalDrives;
+ Controller->GenericDiskInfo.init = DAC960_InitializeGenericDiskInfo;
+ Controller->GenericDiskInfo.nr_real = Controller->LogicalDriveCount;
+ Controller->GenericDiskInfo.real_devices = Controller;
+ Controller->GenericDiskInfo.next = NULL;
+ /*
+ Install the Generic Disk Information structure at the end of the list.
+ */
+ if ((GenericDiskInfo = gendisk_head) != NULL)
+ {
+ while (GenericDiskInfo->next != NULL)
+ GenericDiskInfo = GenericDiskInfo->next;
+ GenericDiskInfo->next = &Controller->GenericDiskInfo;
+ }
+ else gendisk_head = &Controller->GenericDiskInfo;
+ /*
+ Indicate the Block Device Registration completed successfully,
+ */
+ return true;
+}
+
+
+/*
+ DAC960_UnregisterBlockDevice unregisters the Block Device structures
+ associated with Controller.
+*/
+
+static void DAC960_UnregisterBlockDevice(DAC960_Controller_T *Controller)
+{
+ int MajorNumber = DAC960_MAJOR + Controller->ControllerNumber;
+ /*
+ Unregister the Block Device Major Number for this DAC960 Controller.
+ */
+ unregister_blkdev(MajorNumber, "rd");
+ /*
+ Remove the I/O Request Function.
+ */
+ blk_dev[MajorNumber].request_fn = NULL;
+ /*
+ Remove the Disk Partitions array, Partition Sizes array, Block Sizes
+ array, Max Sectors per Request array, and Max Segments per Request array.
+ */
+ Controller->GenericDiskInfo.part = NULL;
+ Controller->GenericDiskInfo.sizes = NULL;
+ blk_size[MajorNumber] = NULL;
+ blksize_size[MajorNumber] = NULL;
+ max_sectors[MajorNumber] = NULL;
+ max_segments[MajorNumber] = NULL;
+ /*
+ Remove the Generic Disk Information structure from the list.
+ */
+ if (gendisk_head != &Controller->GenericDiskInfo)
+ {
+ GenericDiskInfo_T *GenericDiskInfo = gendisk_head;
+ while (GenericDiskInfo != NULL &&
+ GenericDiskInfo->next != &Controller->GenericDiskInfo)
+ GenericDiskInfo = GenericDiskInfo->next;
+ if (GenericDiskInfo != NULL)
+ GenericDiskInfo->next = GenericDiskInfo->next->next;
+ }
+ else gendisk_head = Controller->GenericDiskInfo.next;
+}
+
+
+/*
+ DAC960_InitializeController initializes Controller.
+*/
+
+static void DAC960_InitializeController(DAC960_Controller_T *Controller)
+{
+ DAC960_AnnounceDriver(Controller);
+ if (DAC960_ReadControllerConfiguration(Controller) &&
+ DAC960_ReportControllerConfiguration(Controller) &&
+ DAC960_RegisterBlockDevice(Controller))
+ {
+ /*
+ Initialize the Command structures.
+ */
+ DAC960_Command_T *Commands = Controller->Commands;
+ int CommandIdentifier;
+ Controller->FreeCommands = NULL;
+ for (CommandIdentifier = 0;
+ CommandIdentifier < Controller->DriverQueueDepth;
+ CommandIdentifier++)
+ {
+ Commands[CommandIdentifier].Controller = Controller;
+ Commands[CommandIdentifier].Next = Controller->FreeCommands;
+ Controller->FreeCommands = &Commands[CommandIdentifier];
+ }
+ /*
+ Initialize the Monitoring Timer.
+ */
+ init_timer(&Controller->MonitoringTimer);
+ Controller->MonitoringTimer.expires =
+ jiffies + DAC960_MonitoringTimerInterval;
+ Controller->MonitoringTimer.data = (unsigned long) Controller;
+ Controller->MonitoringTimer.function = DAC960_MonitoringTimerFunction;
+ add_timer(&Controller->MonitoringTimer);
+ }
+ else
+ {
+ free_irq(Controller->IRQ_Channel, Controller);
+ iounmap(Controller->MemoryMappedAddress);
+ DAC960_UnregisterBlockDevice(Controller);
+ DAC960_Controllers[Controller->ControllerNumber] = NULL;
+ kfree(Controller);
+ }
+}
+
+
+/*
+ DAC960_Initialize initializes the DAC960 Driver.
+*/
+
+void DAC960_Initialize(void)
+{
+ int ControllerNumber;
+ DAC960_DetectControllers(PCI_DEVICE_ID_MYLEX_DAC960P_V4);
+ DAC960_DetectControllers(PCI_DEVICE_ID_MYLEX_DAC960P_V3);
+ for (ControllerNumber = 0;
+ ControllerNumber < DAC960_ControllerCount;
+ ControllerNumber++)
+ if (DAC960_Controllers[ControllerNumber] != NULL)
+ DAC960_InitializeController(DAC960_Controllers[ControllerNumber]);
+}
+
+
+/*
+ DAC960_Finalize flushes all DAC960 caches before the system halts.
+*/
+
+void DAC960_Finalize(void)
+{
+ int ControllerNumber;
+ for (ControllerNumber = 0;
+ ControllerNumber < DAC960_ControllerCount;
+ ControllerNumber++)
+ {
+ DAC960_Controller_T *Controller = DAC960_Controllers[ControllerNumber];
+ if (Controller == NULL) continue;
+ DAC960_Notice("Flushing Cache...", Controller);
+ DAC960_ExecuteType3(Controller, DAC960_Flush, NULL);
+ DAC960_Notice("done\n", Controller);
+ }
+}
+
+
+/*
+ DAC960_ProcessRequest attempts to remove one I/O Request from Controller's
+ I/O Request Queue and queues it to the Controller. Command is either a
+ previously allocated Command to be reused, or NULL if a new Command is to
+ be allocated for this I/O Request. It returns true if an I/O Request was
+ queued and false otherwise.
+*/
+
+static boolean DAC960_ProcessRequest(DAC960_Controller_T *Controller,
+ DAC960_Command_T *Command)
+{
+ int MajorNumber = DAC960_MAJOR + Controller->ControllerNumber;
+ IO_Request_T *Request = blk_dev[MajorNumber].current_request;
+ DAC960_CommandMailbox_T *CommandMailbox;
+ char *RequestBuffer;
+ if (Request == NULL || Request->rq_status == RQ_INACTIVE) return false;
+ if (Command == NULL)
+ Command = DAC960_AllocateCommand(Controller);
+ if (Command == NULL) return false;
+ DAC960_ClearCommand(Command);
+ if (Request->cmd == READ)
+ Command->CommandType = DAC960_ReadCommand;
+ else Command->CommandType = DAC960_WriteCommand;
+ Command->Semaphore = Request->sem;
+ Command->LogicalDriveNumber = DAC960_LogicalDriveNumber(Request->rq_dev);
+ Command->BlockNumber =
+ Request->sector
+ + Controller->GenericDiskInfo.part[MINOR(Request->rq_dev)].start_sect;
+ Command->BlockCount = Request->nr_sectors;
+ Command->SegmentCount = Request->nr_segments;
+ Command->BufferHeader = Request->bh;
+ RequestBuffer = Request->buffer;
+ Request->rq_status = RQ_INACTIVE;
+ blk_dev[MajorNumber].current_request = Request->next;
+ wake_up(&wait_for_request);
+ CommandMailbox = &Command->CommandMailbox;
+ if (Command->SegmentCount == 1)
+ {
+ if (Command->CommandType == DAC960_ReadCommand)
+ CommandMailbox->Type5.CommandOpcode = DAC960_Read;
+ else CommandMailbox->Type5.CommandOpcode = DAC960_Write;
+ CommandMailbox->Type5.LD.TransferLength = Command->BlockCount;
+ CommandMailbox->Type5.LD.LogicalDriveNumber = Command->LogicalDriveNumber;
+ CommandMailbox->Type5.LogicalBlockAddress = Command->BlockNumber;
+ CommandMailbox->Type5.BusAddress = Virtual_to_Bus(RequestBuffer);
+ }
+ else
+ {
+ DAC960_ScatterGatherSegment_T
+ *ScatterGatherList = Command->ScatterGatherList;
+ BufferHeader_T *BufferHeader = Command->BufferHeader;
+ char *LastDataEndPointer = NULL;
+ int SegmentNumber = 0;
+ if (Command->CommandType == DAC960_ReadCommand)
+ CommandMailbox->Type5.CommandOpcode = DAC960_ReadWithOldScatterGather;
+ else
+ CommandMailbox->Type5.CommandOpcode = DAC960_WriteWithOldScatterGather;
+ CommandMailbox->Type5.LD.TransferLength = Command->BlockCount;
+ CommandMailbox->Type5.LD.LogicalDriveNumber = Command->LogicalDriveNumber;
+ CommandMailbox->Type5.LogicalBlockAddress = Command->BlockNumber;
+ CommandMailbox->Type5.BusAddress = Virtual_to_Bus(ScatterGatherList);
+ CommandMailbox->Type5.ScatterGatherCount = Command->SegmentCount;
+ while (BufferHeader != NULL)
+ {
+ if (BufferHeader->b_data == LastDataEndPointer)
+ {
+ ScatterGatherList[SegmentNumber-1].SegmentByteCount +=
+ BufferHeader->b_size;
+ LastDataEndPointer += BufferHeader->b_size;
+ }
+ else
+ {
+ ScatterGatherList[SegmentNumber].SegmentDataPointer =
+ Virtual_to_Bus(BufferHeader->b_data);
+ ScatterGatherList[SegmentNumber].SegmentByteCount =
+ BufferHeader->b_size;
+ LastDataEndPointer = BufferHeader->b_data + BufferHeader->b_size;
+ if (SegmentNumber++ > Controller->MaxScatterGatherSegments)
+ panic("DAC960: Scatter/Gather Segment Overflow\n");
+ }
+ BufferHeader = BufferHeader->b_reqnext;
+ }
+ if (SegmentNumber != Command->SegmentCount)
+ panic("DAC960: SegmentNumber != SegmentCount\n");
+ }
+ DAC960_QueueCommand(Command);
+ return true;
+}
+
+
+/*
+ DAC960_ProcessRequests attempts to remove as many I/O Requests as possible
+ from Controller's I/O Request Queue and queue them to the Controller.
+*/
+
+static inline void DAC960_ProcessRequests(DAC960_Controller_T *Controller)
+{
+ while (Controller->FreeCommands != NULL)
+ if (!DAC960_ProcessRequest(Controller, NULL)) break;
+}
+
+
+/*
+ DAC960_RequestFunction0 is the I/O Request Function for DAC960 Controller 0.
+*/
+
+static void DAC960_RequestFunction0(void)
+{
+ DAC960_Controller_T *Controller = DAC960_Controllers[0];
+ ProcessorFlags_T ProcessorFlags;
+ /*
+ Acquire exclusive access to Controller.
+ */
+ DAC960_AcquireControllerLockRF(Controller, &ProcessorFlags);
+ /*
+ Process I/O Requests for Controller.
+ */
+ DAC960_ProcessRequests(Controller);
+ /*
+ Release exclusive access to Controller.
+ */
+ DAC960_ReleaseControllerLockRF(Controller, &ProcessorFlags);
+}
+
+
+/*
+ DAC960_RequestFunction1 is the I/O Request Function for DAC960 Controller 1.
+*/
+
+static void DAC960_RequestFunction1(void)
+{
+ DAC960_Controller_T *Controller = DAC960_Controllers[1];
+ ProcessorFlags_T ProcessorFlags;
+ /*
+ Acquire exclusive access to Controller.
+ */
+ DAC960_AcquireControllerLockRF(Controller, &ProcessorFlags);
+ /*
+ Process I/O Requests for Controller.
+ */
+ DAC960_ProcessRequests(Controller);
+ /*
+ Release exclusive access to Controller.
+ */
+ DAC960_ReleaseControllerLockRF(Controller, &ProcessorFlags);
+}
+
+
+/*
+ DAC960_RequestFunction2 is the I/O Request Function for DAC960 Controller 2.
+*/
+
+static void DAC960_RequestFunction2(void)
+{
+ DAC960_Controller_T *Controller = DAC960_Controllers[2];
+ ProcessorFlags_T ProcessorFlags;
+ /*
+ Acquire exclusive access to Controller.
+ */
+ DAC960_AcquireControllerLockRF(Controller, &ProcessorFlags);
+ /*
+ Process I/O Requests for Controller.
+ */
+ DAC960_ProcessRequests(Controller);
+ /*
+ Release exclusive access to Controller.
+ */
+ DAC960_ReleaseControllerLockRF(Controller, &ProcessorFlags);
+}
+
+
+/*
+ DAC960_RequestFunction3 is the I/O Request Function for DAC960 Controller 3.
+*/
+
+static void DAC960_RequestFunction3(void)
+{
+ DAC960_Controller_T *Controller = DAC960_Controllers[3];
+ ProcessorFlags_T ProcessorFlags;
+ /*
+ Acquire exclusive access to Controller.
+ */
+ DAC960_AcquireControllerLockRF(Controller, &ProcessorFlags);
+ /*
+ Process I/O Requests for Controller.
+ */
+ DAC960_ProcessRequests(Controller);
+ /*
+ Release exclusive access to Controller.
+ */
+ DAC960_ReleaseControllerLockRF(Controller, &ProcessorFlags);
+}
+
+
+/*
+ DAC960_RequestFunction4 is the I/O Request Function for DAC960 Controller 4.
+*/
+
+static void DAC960_RequestFunction4(void)
+{
+ DAC960_Controller_T *Controller = DAC960_Controllers[4];
+ ProcessorFlags_T ProcessorFlags;
+ /*
+ Acquire exclusive access to Controller.
+ */
+ DAC960_AcquireControllerLockRF(Controller, &ProcessorFlags);
+ /*
+ Process I/O Requests for Controller.
+ */
+ DAC960_ProcessRequests(Controller);
+ /*
+ Release exclusive access to Controller.
+ */
+ DAC960_ReleaseControllerLockRF(Controller, &ProcessorFlags);
+}
+
+
+/*
+ DAC960_RequestFunction5 is the I/O Request Function for DAC960 Controller 5.
+*/
+
+static void DAC960_RequestFunction5(void)
+{
+ DAC960_Controller_T *Controller = DAC960_Controllers[5];
+ ProcessorFlags_T ProcessorFlags;
+ /*
+ Acquire exclusive access to Controller.
+ */
+ DAC960_AcquireControllerLockRF(Controller, &ProcessorFlags);
+ /*
+ Process I/O Requests for Controller.
+ */
+ DAC960_ProcessRequests(Controller);
+ /*
+ Release exclusive access to Controller.
+ */
+ DAC960_ReleaseControllerLockRF(Controller, &ProcessorFlags);
+}
+
+
+/*
+ DAC960_RequestFunction6 is the I/O Request Function for DAC960 Controller 6.
+*/
+
+static void DAC960_RequestFunction6(void)
+{
+ DAC960_Controller_T *Controller = DAC960_Controllers[6];
+ ProcessorFlags_T ProcessorFlags;
+ /*
+ Acquire exclusive access to Controller.
+ */
+ DAC960_AcquireControllerLockRF(Controller, &ProcessorFlags);
+ /*
+ Process I/O Requests for Controller.
+ */
+ DAC960_ProcessRequests(Controller);
+ /*
+ Release exclusive access to Controller.
+ */
+ DAC960_ReleaseControllerLockRF(Controller, &ProcessorFlags);
+}
+
+
+/*
+ DAC960_RequestFunction7 is the I/O Request Function for DAC960 Controller 7.
+*/
+
+static void DAC960_RequestFunction7(void)
+{
+ DAC960_Controller_T *Controller = DAC960_Controllers[7];
+ ProcessorFlags_T ProcessorFlags;
+ /*
+ Acquire exclusive access to Controller.
+ */
+ DAC960_AcquireControllerLockRF(Controller, &ProcessorFlags);
+ /*
+ Process I/O Requests for Controller.
+ */
+ DAC960_ProcessRequests(Controller);
+ /*
+ Release exclusive access to Controller.
+ */
+ DAC960_ReleaseControllerLockRF(Controller, &ProcessorFlags);
+}
+
+
+/*
+ DAC960_ReadWriteError prints an appropriate error message for Command when
+ an error occurs on a read or write operation.
+*/
+
+static void DAC960_ReadWriteError(DAC960_Command_T *Command)
+{
+ DAC960_Controller_T *Controller = Command->Controller;
+ char *CommandName = "UNKNOWN";
+ switch (Command->CommandType)
+ {
+ case DAC960_ReadCommand:
+ case DAC960_ReadRetryCommand:
+ CommandName = "READ";
+ break;
+ case DAC960_WriteCommand:
+ case DAC960_WriteRetryCommand:
+ CommandName = "WRITE";
+ break;
+ case DAC960_MonitoringCommand:
+ case DAC960_ImmediateCommand:
+ break;
+ }
+ switch (Command->CommandStatus)
+ {
+ case DAC960_IrrecoverableDataError:
+ DAC960_Error("Irrecoverable Data Error on %s:\n",
+ Controller, CommandName);
+ break;
+ case DAC960_LogicalDriveNonexistentOrOffline:
+ break;
+ case DAC960_AccessBeyondEndOfLogicalDrive:
+ DAC960_Error("Attempt to Access Beyond End of Logical Drive "
+ "on %s:\n", Controller, CommandName);
+ break;
+ case DAC960_BadDataEncountered:
+ DAC960_Error("Bad Data Encountered on %s:\n", Controller, CommandName);
+ break;
+ default:
+ DAC960_Error("Unexpected Error Status %04X on %s:\n",
+ Controller, Command->CommandStatus, CommandName);
+ break;
+ }
+ DAC960_Error(" /dev/rd/c%dd%d: absolute blocks %d..%d\n",
+ Controller, Controller->ControllerNumber,
+ Command->LogicalDriveNumber, Command->BlockNumber,
+ Command->BlockNumber + Command->BlockCount - 1);
+ if (DAC960_PartitionNumber(Command->BufferHeader->b_rdev) > 0)
+ DAC960_Error(" /dev/rd/c%dd%dp%d: relative blocks %d..%d\n",
+ Controller, Controller->ControllerNumber,
+ Command->LogicalDriveNumber,
+ DAC960_PartitionNumber(Command->BufferHeader->b_rdev),
+ Command->BufferHeader->b_rsector,
+ Command->BufferHeader->b_rsector + Command->BlockCount - 1);
+}
+
+
+/*
+ DAC960_ProcessCompletedBuffer performs completion processing for an
+ individual Buffer.
+*/
+
+static inline void DAC960_ProcessCompletedBuffer(BufferHeader_T *BufferHeader,
+ boolean SuccessfulIO)
+{
+ mark_buffer_uptodate(BufferHeader, SuccessfulIO);
+ unlock_buffer(BufferHeader);
+}
+
+
+/*
+ DAC960_ProcessCompletedCommand performs completion processing for Command.
+*/
+
+static void DAC960_ProcessCompletedCommand(DAC960_Command_T *Command)
+{
+ DAC960_Controller_T *Controller = Command->Controller;
+ DAC960_CommandType_T CommandType = Command->CommandType;
+ DAC960_CommandStatus_T CommandStatus = Command->CommandStatus;
+ BufferHeader_T *BufferHeader = Command->BufferHeader;
+ if (CommandType == DAC960_ReadCommand ||
+ CommandType == DAC960_WriteCommand)
+ {
+ if (CommandStatus == DAC960_NormalCompletion)
+ {
+ /*
+ Perform completion processing for all buffers in this I/O Request.
+ */
+ while (BufferHeader != NULL)
+ {
+ BufferHeader_T *NextBufferHeader = BufferHeader->b_reqnext;
+ BufferHeader->b_reqnext = NULL;
+ DAC960_ProcessCompletedBuffer(BufferHeader, true);
+ BufferHeader = NextBufferHeader;
+ }
+ /*
+ Wake up requestor for swap file paging requests.
+ */
+ if (Command->Semaphore != NULL)
+ {
+ up(Command->Semaphore);
+ Command->Semaphore = NULL;
+ }
+ }
+ else if ((CommandStatus == DAC960_IrrecoverableDataError ||
+ CommandStatus == DAC960_BadDataEncountered) &&
+ BufferHeader != NULL &&
+ BufferHeader->b_reqnext != NULL)
+ {
+ DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox;
+ if (CommandType == DAC960_ReadCommand)
+ {
+ Command->CommandType = DAC960_ReadRetryCommand;
+ CommandMailbox->Type5.CommandOpcode = DAC960_Read;
+ }
+ else
+ {
+ Command->CommandType = DAC960_WriteRetryCommand;
+ CommandMailbox->Type5.CommandOpcode = DAC960_Write;
+ }
+ Command->BlockCount = BufferHeader->b_size >> DAC960_BlockSizeBits;
+ CommandMailbox->Type5.LD.TransferLength = Command->BlockCount;
+ CommandMailbox->Type5.BusAddress =
+ Virtual_to_Bus(BufferHeader->b_data);
+ DAC960_QueueCommand(Command);
+ return;
+ }
+ else
+ {
+ DAC960_ReadWriteError(Command);
+ /*
+ Perform completion processing for all buffers in this I/O Request.
+ */
+ while (BufferHeader != NULL)
+ {
+ BufferHeader_T *NextBufferHeader = BufferHeader->b_reqnext;
+ BufferHeader->b_reqnext = NULL;
+ DAC960_ProcessCompletedBuffer(BufferHeader, false);
+ BufferHeader = NextBufferHeader;
+ }
+ /*
+ Wake up requestor for swap file paging requests.
+ */
+ if (Command->Semaphore != NULL)
+ {
+ up(Command->Semaphore);
+ Command->Semaphore = NULL;
+ }
+ }
+ }
+ else if (CommandType == DAC960_ReadRetryCommand ||
+ CommandType == DAC960_WriteRetryCommand)
+ {
+ BufferHeader_T *NextBufferHeader = BufferHeader->b_reqnext;
+ BufferHeader->b_reqnext = NULL;
+ /*
+ Perform completion processing for this single buffer.
+ */
+ if (CommandStatus == DAC960_NormalCompletion)
+ DAC960_ProcessCompletedBuffer(BufferHeader, true);
+ else
+ {
+ DAC960_ReadWriteError(Command);
+ DAC960_ProcessCompletedBuffer(BufferHeader, false);
+ }
+ if (NextBufferHeader != NULL)
+ {
+ DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox;
+ Command->BlockNumber +=
+ BufferHeader->b_size >> DAC960_BlockSizeBits;
+ Command->BlockCount =
+ NextBufferHeader->b_size >> DAC960_BlockSizeBits;
+ Command->BufferHeader = NextBufferHeader;
+ CommandMailbox->Type5.LD.TransferLength = Command->BlockCount;
+ CommandMailbox->Type5.LogicalBlockAddress = Command->BlockNumber;
+ CommandMailbox->Type5.BusAddress =
+ Virtual_to_Bus(NextBufferHeader->b_data);
+ DAC960_QueueCommand(Command);
+ return;
+ }
+ }
+ else if (CommandType == DAC960_MonitoringCommand)
+ {
+ DAC960_CommandOpcode_T CommandOpcode =
+ Command->CommandMailbox.Common.CommandOpcode;
+ unsigned int OldCriticalLogicalDriveCount = 0;
+ unsigned int NewCriticalLogicalDriveCount = 0;
+ if (CommandOpcode == DAC960_Enquiry)
+ {
+ DAC960_Enquiry_T *OldEnquiry =
+ &Controller->Enquiry[Controller->EnquiryIndex];
+ DAC960_Enquiry_T *NewEnquiry =
+ &Controller->Enquiry[Controller->EnquiryIndex ^= 1];
+ OldCriticalLogicalDriveCount = OldEnquiry->CriticalLogicalDriveCount;
+ NewCriticalLogicalDriveCount = NewEnquiry->CriticalLogicalDriveCount;
+ if (NewEnquiry->StatusFlags.DeferredWriteError !=
+ OldEnquiry->StatusFlags.DeferredWriteError)
+ DAC960_Critical("Deferred Write Error Flag is now %s\n", Controller,
+ (NewEnquiry->StatusFlags.DeferredWriteError
+ ? "TRUE" : "FALSE"));
+ if ((NewCriticalLogicalDriveCount > 0 ||
+ NewCriticalLogicalDriveCount != OldCriticalLogicalDriveCount) ||
+ (NewEnquiry->OfflineLogicalDriveCount > 0 ||
+ NewEnquiry->OfflineLogicalDriveCount !=
+ OldEnquiry->OfflineLogicalDriveCount) ||
+ (NewEnquiry->DeadDriveCount > 0 ||
+ NewEnquiry->DeadDriveCount !=
+ OldEnquiry->DeadDriveCount) ||
+ (NewEnquiry->EventLogSequenceNumber !=
+ OldEnquiry->EventLogSequenceNumber) ||
+ (jiffies - Controller->SecondaryMonitoringTime
+ >= DAC960_SecondaryMonitoringInterval))
+ {
+ Controller->NeedLogicalDriveInformation = true;
+ Controller->NewEventLogSequenceNumber =
+ NewEnquiry->EventLogSequenceNumber;
+ Controller->NeedDeviceStateInformation = true;
+ Controller->DeviceStateChannel = 0;
+ Controller->DeviceStateTargetID = 0;
+ Controller->SecondaryMonitoringTime = jiffies;
+ }
+ if ((NewEnquiry->RebuildCount > 0 &&
+ jiffies - Controller->RebuildLastReportTime
+ >= DAC960_RebuildStatusReportingInterval) ||
+ NewEnquiry->RebuildCount != OldEnquiry->RebuildCount)
+ Controller->NeedRebuildProgress = true;
+ }
+ else if (CommandOpcode == DAC960_GetLogicalDriveInformation)
+ {
+ int LogicalDriveNumber;
+ for (LogicalDriveNumber = 0;
+ LogicalDriveNumber < Controller->LogicalDriveCount;
+ LogicalDriveNumber++)
+ {
+ DAC960_LogicalDriveInformation_T *OldLogicalDriveInformation =
+ &Controller->LogicalDriveInformation
+ [Controller->LogicalDriveInformationIndex]
+ [LogicalDriveNumber];
+ DAC960_LogicalDriveInformation_T *NewLogicalDriveInformation =
+ &Controller->LogicalDriveInformation
+ [Controller->LogicalDriveInformationIndex ^ 1]
+ [LogicalDriveNumber];
+ if (NewLogicalDriveInformation->LogicalDriveState !=
+ OldLogicalDriveInformation->LogicalDriveState)
+ DAC960_Critical("Logical Drive %d (/dev/rd/c%dd%d) "
+ "is now %s\n", Controller,
+ LogicalDriveNumber,
+ Controller->ControllerNumber,
+ LogicalDriveNumber,
+ (NewLogicalDriveInformation->LogicalDriveState
+ == DAC960_LogicalDrive_Online
+ ? "ONLINE"
+ : NewLogicalDriveInformation->LogicalDriveState
+ == DAC960_LogicalDrive_Critical
+ ? "CRITICAL" : "OFFLINE"));
+ if (NewLogicalDriveInformation->WriteBack !=
+ OldLogicalDriveInformation->WriteBack)
+ DAC960_Critical("Logical Drive %d (/dev/rd/c%dd%d) "
+ "is now %s\n", Controller,
+ LogicalDriveNumber,
+ Controller->ControllerNumber,
+ LogicalDriveNumber,
+ (NewLogicalDriveInformation->WriteBack
+ ? "WRITE BACK" : "WRITE THRU"));
+ }
+ Controller->LogicalDriveInformationIndex ^= 1;
+ }
+ else if (CommandOpcode == DAC960_PerformEventLogOperation)
+ {
+ DAC960_EventLogEntry_T *EventLogEntry = &Controller->EventLogEntry;
+ if (EventLogEntry->SequenceNumber ==
+ Controller->OldEventLogSequenceNumber)
+ {
+ unsigned char SenseKey = EventLogEntry->SenseKey;
+ unsigned char AdditionalSenseCode =
+ EventLogEntry->AdditionalSenseCode;
+ unsigned char AdditionalSenseCodeQualifier =
+ EventLogEntry->AdditionalSenseCodeQualifier;
+ if (SenseKey == 9 &&
+ AdditionalSenseCode == 0x80 &&
+ AdditionalSenseCodeQualifier < DAC960_EventMessagesCount)
+ DAC960_Critical("Physical Drive %d:%d %s\n", Controller,
+ EventLogEntry->Channel,
+ EventLogEntry->TargetID,
+ DAC960_EventMessages[
+ AdditionalSenseCodeQualifier]);
+ else if (!((SenseKey == 2 &&
+ AdditionalSenseCode == 0x04 &&
+ (AdditionalSenseCodeQualifier == 0x01 ||
+ AdditionalSenseCodeQualifier == 0x02)) ||
+ (SenseKey == 6 && AdditionalSenseCode == 0x29)))
+ DAC960_Critical("Physical Drive %d:%d Error Log: "
+ "Sense Key = %d, ASC = %02X, ASCQ = %02X\n",
+ Controller,
+ EventLogEntry->Channel,
+ EventLogEntry->TargetID,
+ SenseKey,
+ AdditionalSenseCode,
+ AdditionalSenseCodeQualifier);
+ }
+ Controller->OldEventLogSequenceNumber++;
+ }
+ else if (CommandOpcode == DAC960_GetDeviceState)
+ {
+ DAC960_DeviceState_T *OldDeviceState =
+ &Controller->DeviceState[Controller->DeviceStateIndex]
+ [Controller->DeviceStateChannel]
+ [Controller->DeviceStateTargetID];
+ DAC960_DeviceState_T *NewDeviceState =
+ &Controller->DeviceState[Controller->DeviceStateIndex ^ 1]
+ [Controller->DeviceStateChannel]
+ [Controller->DeviceStateTargetID];
+ if (NewDeviceState->DeviceState != OldDeviceState->DeviceState)
+ DAC960_Critical("Physical Drive %d:%d is now %s\n", Controller,
+ Controller->DeviceStateChannel,
+ Controller->DeviceStateTargetID,
+ (NewDeviceState->DeviceState == DAC960_Device_Dead
+ ? "DEAD"
+ : NewDeviceState->DeviceState
+ == DAC960_Device_WriteOnly
+ ? "WRITE-ONLY"
+ : NewDeviceState->DeviceState
+ == DAC960_Device_Online
+ ? "ONLINE" : "STANDBY"));
+ if (++Controller->DeviceStateTargetID == DAC960_MaxTargets)
+ {
+ Controller->DeviceStateChannel++;
+ Controller->DeviceStateTargetID = 0;
+ }
+ }
+ else if (CommandOpcode == DAC960_GetRebuildProgress)
+ {
+ unsigned int LogicalDriveNumber =
+ Controller->RebuildProgress.LogicalDriveNumber;
+ unsigned int LogicalDriveSize =
+ Controller->RebuildProgress.LogicalDriveSize;
+ unsigned int BlocksCompleted =
+ LogicalDriveSize - Controller->RebuildProgress.RemainingBlocks;
+ switch (CommandStatus)
+ {
+ case DAC960_NormalCompletion:
+ DAC960_Critical("REBUILD IN PROGRESS: "
+ "Logical Drive %d (/dev/rd/c%dd%d) "
+ "%d%% completed\n",
+ Controller, LogicalDriveNumber,
+ Controller->ControllerNumber,
+ LogicalDriveNumber,
+ (100 * (BlocksCompleted >> 7))
+ / (LogicalDriveSize >> 7));
+ break;
+ case DAC960_RebuildFailed_LogicalDriveFailure:
+ DAC960_Critical("REBUILD FAILED due to "
+ "LOGICAL DRIVE FAILURE\n", Controller);
+ break;
+ case DAC960_RebuildFailed_BadBlocksOnOther:
+ DAC960_Critical("REBUILD FAILED due to "
+ "BAD BLOCKS ON OTHER DRIVES\n", Controller);
+ break;
+ case DAC960_RebuildFailed_NewDriveFailed:
+ DAC960_Critical("REBUILD FAILED due to "
+ "FAILURE OF DRIVE BEING REBUILT\n", Controller);
+ break;
+ case DAC960_RebuildSuccessful:
+ DAC960_Critical("REBUILD COMPLETED SUCCESSFULLY\n", Controller);
+ break;
+ case DAC960_NoRebuildOrCheckInProgress:
+ break;
+ }
+ Controller->RebuildLastReportTime = jiffies;
+ }
+ if (Controller->NeedLogicalDriveInformation &&
+ NewCriticalLogicalDriveCount >= OldCriticalLogicalDriveCount)
+ {
+ Controller->NeedLogicalDriveInformation = false;
+ Command->CommandMailbox.Type3.CommandOpcode =
+ DAC960_GetLogicalDriveInformation;
+ Command->CommandMailbox.Type3.BusAddress =
+ Virtual_to_Bus(
+ &Controller->LogicalDriveInformation
+ [Controller->LogicalDriveInformationIndex ^ 1]);
+ DAC960_QueueCommand(Command);
+ return;
+ }
+ if (Controller->NewEventLogSequenceNumber
+ - Controller->OldEventLogSequenceNumber > 0)
+ {
+ Command->CommandMailbox.Type3E.CommandOpcode =
+ DAC960_PerformEventLogOperation;
+ Command->CommandMailbox.Type3E.OperationType =
+ DAC960_GetEventLogEntry;
+ Command->CommandMailbox.Type3E.OperationQualifier = 1;
+ Command->CommandMailbox.Type3E.SequenceNumber =
+ Controller->OldEventLogSequenceNumber;
+ Command->CommandMailbox.Type3E.BusAddress =
+ Virtual_to_Bus(&Controller->EventLogEntry);
+ DAC960_QueueCommand(Command);
+ return;
+ }
+ if (Controller->NeedDeviceStateInformation)
+ {
+ while (Controller->DeviceStateChannel < Controller->Channels)
+ {
+ DAC960_DeviceState_T *OldDeviceState =
+ &Controller->DeviceState[Controller->DeviceStateIndex]
+ [Controller->DeviceStateChannel]
+ [Controller->DeviceStateTargetID];
+ if (OldDeviceState->Present &&
+ OldDeviceState->DeviceType == DAC960_DiskType)
+ {
+ Command->CommandMailbox.Type3D.CommandOpcode =
+ DAC960_GetDeviceState;
+ Command->CommandMailbox.Type3D.Channel =
+ Controller->DeviceStateChannel;
+ Command->CommandMailbox.Type3D.TargetID =
+ Controller->DeviceStateTargetID;
+ Command->CommandMailbox.Type3D.BusAddress =
+ Virtual_to_Bus(&Controller->DeviceState
+ [Controller->DeviceStateIndex ^ 1]
+ [Controller->DeviceStateChannel]
+ [Controller->DeviceStateTargetID]);
+ DAC960_QueueCommand(Command);
+ return;
+ }
+ if (++Controller->DeviceStateTargetID == DAC960_MaxTargets)
+ {
+ Controller->DeviceStateChannel++;
+ Controller->DeviceStateTargetID = 0;
+ }
+ }
+ Controller->NeedDeviceStateInformation = false;
+ Controller->DeviceStateIndex ^= 1;
+ }
+ if (Controller->NeedRebuildProgress)
+ {
+ Controller->NeedRebuildProgress = false;
+ Command->CommandMailbox.Type3.CommandOpcode =
+ DAC960_GetRebuildProgress;
+ Command->CommandMailbox.Type3.BusAddress =
+ Virtual_to_Bus(&Controller->RebuildProgress);
+ DAC960_QueueCommand(Command);
+ return;
+ }
+ if (Controller->NeedLogicalDriveInformation &&
+ NewCriticalLogicalDriveCount < OldCriticalLogicalDriveCount)
+ {
+ Controller->NeedLogicalDriveInformation = false;
+ Command->CommandMailbox.Type3.CommandOpcode =
+ DAC960_GetLogicalDriveInformation;
+ Command->CommandMailbox.Type3.BusAddress =
+ Virtual_to_Bus(
+ &Controller->LogicalDriveInformation
+ [Controller->LogicalDriveInformationIndex ^ 1]);
+ DAC960_QueueCommand(Command);
+ return;
+ }
+ Controller->MonitoringTimer.expires =
+ jiffies + DAC960_MonitoringTimerInterval;
+ add_timer(&Controller->MonitoringTimer);
+ }
+ else if (CommandType == DAC960_ImmediateCommand)
+ {
+ up(Command->Semaphore);
+ Command->Semaphore = NULL;
+ return;
+ }
+ else panic("DAC960: Unknown Command Type %d\n", CommandType);
+ /*
+ Queue a Monitoring Command to the Controller using the just completed
+ Command if one was deferred previously due to lack of a free Command when
+ the Monitoring Timer Function was called.
+ */
+ if (Controller->MonitoringCommandDeferred)
+ {
+ Controller->MonitoringCommandDeferred = false;
+ DAC960_QueueMonitoringCommand(Command);
+ return;
+ }
+ /*
+ Attempt to remove a new I/O Request from the Controller's I/O Request
+ Queue and queue it to the Controller using the just completed Command.
+ If there is no I/O Request to be queued, deallocate the Command.
+ */
+ if (!DAC960_ProcessRequest(Controller, Command))
+ DAC960_DeallocateCommand(Command);
+}
+
+
+/*
+ DAC960_InterruptHandler handles hardware interrupts from DAC960 Controllers.
+*/
+
+static void DAC960_InterruptHandler(int IRQ_Channel,
+ void *DeviceIdentifier,
+ Registers_T *InterruptRegisters)
+{
+ DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier;
+ void *ControllerBaseAddress = Controller->BaseAddress;
+ DAC960_V4_StatusMailbox_T *NextStatusMailbox;
+ ProcessorFlags_T ProcessorFlags;
+ /*
+ Acquire exclusive access to Controller.
+ */
+ DAC960_AcquireControllerLockIH(Controller, &ProcessorFlags);
+ /*
+ Process Hardware Interrupts for Controller.
+ */
+ switch (Controller->ControllerType)
+ {
+ case DAC960_V4_Controller:
+ DAC960_V4_AcknowledgeInterrupt(ControllerBaseAddress);
+ NextStatusMailbox = Controller->NextStatusMailbox;
+ while (NextStatusMailbox->Fields.Valid)
+ {
+ DAC960_CommandIdentifier_T CommandIdentifier =
+ NextStatusMailbox->Fields.CommandIdentifier;
+ DAC960_Command_T *Command = &Controller->Commands[CommandIdentifier];
+ Command->CommandStatus = NextStatusMailbox->Fields.CommandStatus;
+ NextStatusMailbox->Word = 0;
+ if (++NextStatusMailbox > Controller->LastStatusMailbox)
+ NextStatusMailbox = Controller->FirstStatusMailbox;
+ DAC960_ProcessCompletedCommand(Command);
+ }
+ Controller->NextStatusMailbox = NextStatusMailbox;
+ break;
+ case DAC960_V3_Controller:
+ while (DAC960_V3_StatusAvailableP(ControllerBaseAddress))
+ {
+ DAC960_CommandIdentifier_T CommandIdentifier =
+ DAC960_V3_ReadStatusCommandIdentifier(ControllerBaseAddress);
+ DAC960_Command_T *Command = &Controller->Commands[CommandIdentifier];
+ Command->CommandStatus =
+ DAC960_V3_ReadStatusRegister(ControllerBaseAddress);
+ DAC960_V3_AcknowledgeInterrupt(ControllerBaseAddress);
+ DAC960_V3_AcknowledgeStatus(ControllerBaseAddress);
+ DAC960_ProcessCompletedCommand(Command);
+ }
+ break;
+ }
+ /*
+ Attempt to remove additional I/O Requests from the Controller's
+ I/O Request Queue and queue them to the Controller.
+ */
+ DAC960_ProcessRequests(Controller);
+ /*
+ Release exclusive access to Controller.
+ */
+ DAC960_ReleaseControllerLockIH(Controller, &ProcessorFlags);
+}
+
+
+/*
+ DAC960_QueueMonitoringCommand queues a Monitoring Command to Controller.
+*/
+
+static void DAC960_QueueMonitoringCommand(DAC960_Command_T *Command)
+{
+ DAC960_Controller_T *Controller = Command->Controller;
+ DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox;
+ DAC960_ClearCommand(Command);
+ Command->CommandType = DAC960_MonitoringCommand;
+ CommandMailbox->Type3.CommandOpcode = DAC960_Enquiry;
+ CommandMailbox->Type3.BusAddress =
+ Virtual_to_Bus(&Controller->Enquiry[Controller->EnquiryIndex ^ 1]);
+ DAC960_QueueCommand(Command);
+}
+
+
+/*
+ DAC960_MonitoringTimerFunction is the timer function for monitoring
+ the status of DAC960 Controllers.
+*/
+
+static void DAC960_MonitoringTimerFunction(unsigned long TimerData)
+{
+ DAC960_Controller_T *Controller = (DAC960_Controller_T *) TimerData;
+ DAC960_Command_T *Command;
+ ProcessorFlags_T ProcessorFlags;
+ /*
+ Acquire exclusive access to Controller.
+ */
+ DAC960_AcquireControllerLock(Controller, &ProcessorFlags);
+ /*
+ Queue a Status Monitoring Command for Controller;
+ */
+ Command = DAC960_AllocateCommand(Controller);
+ if (Command != NULL)
+ DAC960_QueueMonitoringCommand(Command);
+ else Controller->MonitoringCommandDeferred = true;
+ /*
+ Release exclusive access to Controller.
+ */
+ DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
+}
+
+
+/*
+ DAC960_Open is the Device Open Function for the DAC960 Driver.
+*/
+
+static int DAC960_Open(Inode_T *Inode, File_T *File)
+{
+ int ControllerNumber = DAC960_ControllerNumber(Inode->i_rdev);
+ int LogicalDriveNumber = DAC960_LogicalDriveNumber(Inode->i_rdev);
+ DAC960_Controller_T *Controller;
+ if (ControllerNumber < 0 || ControllerNumber > DAC960_ControllerCount - 1)
+ return -ENXIO;
+ Controller = DAC960_Controllers[ControllerNumber];
+ if (Controller == NULL ||
+ LogicalDriveNumber > Controller->LogicalDriveCount - 1)
+ return -ENXIO;
+ if (Controller->LogicalDriveInformation
+ [Controller->LogicalDriveInformationIndex]
+ [LogicalDriveNumber] .LogicalDriveState
+ == DAC960_LogicalDrive_Offline)
+ return -ENXIO;
+ if (Controller->GenericDiskInfo.sizes[MINOR(Inode->i_rdev)] == 0)
+ return -ENXIO;
+ /*
+ Increment Controller and Logical Drive Usage Counts.
+ */
+ Controller->ControllerUsageCount++;
+ Controller->LogicalDriveUsageCount[LogicalDriveNumber]++;
+ return 0;
+}
+
+
+/*
+ DAC960_Release is the Device Release Function for the DAC960 Driver.
+*/
+
+static void DAC960_Release(Inode_T *Inode, File_T *File)
+{
+ int ControllerNumber = DAC960_ControllerNumber(Inode->i_rdev);
+ int LogicalDriveNumber = DAC960_LogicalDriveNumber(Inode->i_rdev);
+ DAC960_Controller_T *Controller = DAC960_Controllers[ControllerNumber];
+ /*
+ Force any buffered data to be written.
+ */
+ fsync_dev(Inode->i_rdev);
+ /*
+ Decrement the Logical Drive and Controller Usage Counts.
+ */
+ Controller->LogicalDriveUsageCount[LogicalDriveNumber]--;
+ Controller->ControllerUsageCount--;
+}
+
+
+/*
+ DAC960_Ioctl is the Device Ioctl Function for the DAC960 Driver.
+*/
+
+static int DAC960_Ioctl(Inode_T *Inode, File_T *File,
+ unsigned int Request, unsigned long Argument)
+{
+ int ControllerNumber = DAC960_ControllerNumber(Inode->i_rdev);
+ int LogicalDriveNumber = DAC960_LogicalDriveNumber(Inode->i_rdev);
+ int PartitionNumber, ErrorCode;
+ unsigned short Cylinders;
+ DiskGeometry_T *Geometry;
+ DAC960_Controller_T *Controller;
+ if (ControllerNumber < 0 || ControllerNumber > DAC960_ControllerCount - 1)
+ return -ENXIO;
+ Controller = DAC960_Controllers[ControllerNumber];
+ if (Controller == NULL ||
+ LogicalDriveNumber > Controller->LogicalDriveCount - 1)
+ return -ENXIO;
+ switch (Request)
+ {
+ case HDIO_GETGEO:
+ /* Get BIOS Disk Geometry. */
+ Geometry = (DiskGeometry_T *) Argument;
+ if (Geometry == NULL) return -EINVAL;
+ ErrorCode = verify_area(VERIFY_WRITE, Geometry, sizeof(DiskGeometry_T));
+ if (ErrorCode != 0) return ErrorCode;
+ Cylinders =
+ Controller->LogicalDriveInformation
+ [Controller->LogicalDriveInformationIndex]
+ [LogicalDriveNumber].LogicalDriveSize
+ / (Controller->GeometryTranslationHeads *
+ Controller->GeometryTranslationSectors);
+ put_user(Controller->GeometryTranslationHeads, &Geometry->heads);
+ put_user(Controller->GeometryTranslationSectors, &Geometry->sectors);
+ put_user(Cylinders, &Geometry->cylinders);
+ put_user(Controller->GenericDiskInfo.part[MINOR(Inode->i_rdev)]
+ .start_sect, &Geometry->start);
+ return 0;
+ case BLKGETSIZE:
+ /* Get Device Size. */
+ if ((long *) Argument == NULL) return -EINVAL;
+ ErrorCode = verify_area(VERIFY_WRITE, (long *) Argument, sizeof(long));
+ if (ErrorCode != 0) return ErrorCode;
+ put_user(Controller->GenericDiskInfo.part[MINOR(Inode->i_rdev)].nr_sects,
+ (long *) Argument);
+ return 0;
+ case BLKRAGET:
+ /* Get Read-Ahead. */
+ if ((int *) Argument == NULL) return -EINVAL;
+ ErrorCode = verify_area(VERIFY_WRITE, (int *) Argument, sizeof(int));
+ if (ErrorCode != 0) return ErrorCode;
+ put_user(read_ahead[MAJOR(Inode->i_rdev)], (int *) Argument);
+ return 0;
+ case BLKRASET:
+ /* Set Read-Ahead. */
+ if (!suser()) return -EACCES;
+ if (Argument > 256) return -EINVAL;
+ read_ahead[MAJOR(Inode->i_rdev)] = Argument;
+ return 0;
+ case BLKFLSBUF:
+ /* Flush Buffers. */
+ if (!suser()) return -EACCES;
+ fsync_dev(Inode->i_rdev);
+ invalidate_buffers(Inode->i_rdev);
+ return 0;
+ case BLKRRPART:
+ /* Re-Read Partition Table. */
+ if (!suser()) return -EACCES;
+ if (Controller->LogicalDriveUsageCount[LogicalDriveNumber] > 1)
+ return -EBUSY;
+ for (PartitionNumber = 0;
+ PartitionNumber < DAC960_MaxPartitions;
+ PartitionNumber++)
+ {
+ KernelDevice_T Device = DAC960_KernelDevice(ControllerNumber,
+ LogicalDriveNumber,
+ PartitionNumber);
+ int MinorNumber = DAC960_MinorNumber(LogicalDriveNumber,
+ PartitionNumber);
+ if (Controller->GenericDiskInfo.part[MinorNumber].nr_sects == 0)
+ continue;
+ /*
+ Flush all changes and invalidate buffered state.
+ */
+ sync_dev(Device);
+ invalidate_inodes(Device);
+ invalidate_buffers(Device);
+ /*
+ Clear existing partition sizes.
+ */
+ if (PartitionNumber > 0)
+ {
+ Controller->GenericDiskInfo.part[MinorNumber].start_sect = 0;
+ Controller->GenericDiskInfo.part[MinorNumber].nr_sects = 0;
+ }
+ /*
+ Reset the Block Size so that the partition table can be read.
+ */
+ set_blocksize(Device, BLOCK_SIZE);
+ }
+ resetup_one_dev(&Controller->GenericDiskInfo, LogicalDriveNumber);
+ return 0;
+ }
+ return -EINVAL;
+}
+
+
+/*
+ DAC960_GenericDiskInit is the Generic Disk Information Initialization
+ Function for the DAC960 Driver.
+*/
+
+static void DAC960_InitializeGenericDiskInfo(GenericDiskInfo_T *GenericDiskInfo)
+{
+ DAC960_Controller_T *Controller =
+ (DAC960_Controller_T *) GenericDiskInfo->real_devices;
+ DAC960_LogicalDriveInformation_T *LogicalDriveInformation =
+ Controller->LogicalDriveInformation
+ [Controller->LogicalDriveInformationIndex];
+ int LogicalDriveNumber;
+ for (LogicalDriveNumber = 0;
+ LogicalDriveNumber < Controller->LogicalDriveCount;
+ LogicalDriveNumber++)
+ GenericDiskInfo->part[DAC960_MinorNumber(LogicalDriveNumber, 0)].nr_sects =
+ LogicalDriveInformation[LogicalDriveNumber].LogicalDriveSize;
+}
+
+
+/*
+ DAC960_Message prints Driver Messages.
+*/
+
+static void DAC960_Message(DAC960_MessageLevel_T MessageLevel,
+ char *Format,
+ DAC960_Controller_T *Controller,
+ ...)
+{
+ static char Buffer[DAC960_LineBufferSize];
+ static boolean BeginningOfLine = true;
+ va_list Arguments;
+ int Length = 0;
+ va_start(Arguments, Controller);
+ Length = vsprintf(Buffer, Format, Arguments);
+ va_end(Arguments);
+ if (MessageLevel == DAC960_AnnounceLevel)
+ {
+ static int AnnouncementLines = 0;
+ strcpy(&Controller->MessageBuffer[Controller->MessageBufferLength],
+ Buffer);
+ Controller->MessageBufferLength += Length;
+ if (++AnnouncementLines <= 2)
+ printk("%sDAC960: %s", DAC960_MessageLevelMap[MessageLevel], Buffer);
+ }
+ else if (MessageLevel == DAC960_InfoLevel)
+ {
+ strcpy(&Controller->MessageBuffer[Controller->MessageBufferLength],
+ Buffer);
+ Controller->MessageBufferLength += Length;
+ if (BeginningOfLine)
+ {
+ if (Buffer[0] != '\n' || Length > 1)
+ printk("%sDAC960#%d: %s", DAC960_MessageLevelMap[MessageLevel],
+ Controller->ControllerNumber, Buffer);
+ }
+ else printk("%s", Buffer);
+ }
+ else
+ {
+ if (BeginningOfLine)
+ printk("%sDAC960#%d: %s", DAC960_MessageLevelMap[MessageLevel],
+ Controller->ControllerNumber, Buffer);
+ else printk("%s", Buffer);
+ }
+ BeginningOfLine = (Buffer[Length-1] == '\n');
+}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/DAC960.h linux/drivers/block/DAC960.h
--- linux.vanilla/drivers/block/DAC960.h Thu Jan 1 01:00:00 1970
+++ linux/drivers/block/DAC960.h Mon Nov 30 07:59:59 1998
@@ -0,0 +1,1565 @@
+/*
+
+ Linux Driver for Mylex DAC960 PCI RAID Controllers
+
+ Copyright 1998 by Leonard N. Zubkoff
+
+ This program is free software; you may redistribute and/or modify it under
+ the terms of the GNU General Public License Version 2 as published by the
+ Free Software Foundation.
+
+ 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 complete details.
+
+ The author respectfully requests that any modifications to this software be
+ sent directly to him for evaluation and testing.
+
+*/
+
+
+/*
+ DAC960_DriverVersion protects the private portion of this file.
+*/
+
+#ifdef DAC960_DriverVersion
+
+
+/*
+ Define the maximum number of DAC960 Controllers supported by this driver.
+*/
+
+#define DAC960_MaxControllers 8
+
+
+/*
+ Define the maximum number of Controller Channels supported by this driver.
+*/
+
+#define DAC960_MaxChannels 3
+
+
+/*
+ Define the maximum number of Targets per Channel supported by this driver.
+*/
+
+#define DAC960_MaxTargets 16
+
+
+/*
+ Define the maximum number of Logical Drives supported by any DAC960 model.
+*/
+
+#define DAC960_MaxLogicalDrives 32
+
+
+/*
+ Define the maximum number of Partitions allowed for each Logical Drive.
+*/
+
+#define DAC960_MaxPartitions 8
+#define DAC960_MaxPartitionsBits 3
+
+
+/*
+ Define the maximum Driver Queue Depth and Controller Queue Depth supported
+ by any DAC960 model.
+*/
+
+#define DAC960_MaxDriverQueueDepth 127
+#define DAC960_MaxControllerQueueDepth 128
+
+
+/*
+ Define the maximum number of Scatter/Gather Segments supported by any
+ DAC960 model.
+*/
+
+#define DAC960_MaxScatterGatherSegments 33
+
+
+/*
+ Define the DAC960 Controller Monitoring Timer Interval.
+*/
+
+#define DAC960_MonitoringTimerInterval (7 * HZ)
+
+
+/*
+ Define the DAC960 Controller Secondary Monitoring Interval.
+*/
+
+#define DAC960_SecondaryMonitoringInterval (60 * HZ)
+
+
+/*
+ Define the DAC960 Controller Rebuild Status Reporting Interval.
+*/
+
+#define DAC960_RebuildStatusReportingInterval (60 * HZ)
+
+
+/*
+ Define the number of Command Mailboxes and Status Mailboxes used by the
+ V4 Memory Mailbox Interface.
+*/
+
+#define DAC960_CommandMailboxCount 256
+#define DAC960_StatusMailboxCount 1024
+
+
+/*
+ Define macros to extract the Controller Number, Logical Drive Number, and
+ Partition Number from a Kernel Device, and to construct a Major Number, Minor
+ Number, and Kernel Device from the Controller Number, Logical Drive Number,
+ and Partition Number. There is one Major Number assigned to each Controller.
+ The associated Minor Number is divided into the Logical Drive Number and
+ Partition Number.
+*/
+
+#define DAC960_ControllerNumber(Device) \
+ (MAJOR(Device) - DAC960_MAJOR)
+
+#define DAC960_LogicalDriveNumber(Device) \
+ (MINOR(Device) >> DAC960_MaxPartitionsBits)
+
+#define DAC960_PartitionNumber(Device) \
+ (MINOR(Device) & (DAC960_MaxPartitions - 1))
+
+#define DAC960_MajorNumber(ControllerNumber) \
+ (DAC960_MAJOR + (ControllerNumber))
+
+#define DAC960_MinorNumber(LogicalDriveNumber, PartitionNumber) \
+ (((LogicalDriveNumber) << DAC960_MaxPartitionsBits) | (PartitionNumber))
+
+#define DAC960_MinorCount (DAC960_MaxLogicalDrives \
+ * DAC960_MaxPartitions)
+
+#define DAC960_KernelDevice(ControllerNumber, \
+ LogicalDriveNumber, \
+ PartitionNumber) \
+ MKDEV(DAC960_MajorNumber(ControllerNumber), \
+ DAC960_MinorNumber(LogicalDriveNumber, PartitionNumber))
+
+
+/*
+ Define the DAC960 Controller fixed Block Size and Block Size Bits.
+*/
+
+#define DAC960_BlockSize 512
+#define DAC960_BlockSizeBits 9
+
+
+/*
+ Define the Controller Line and Message Buffer Sizes.
+*/
+
+#define DAC960_LineBufferSize 100
+#define DAC960_MessageBufferSize 2048
+
+
+/*
+ Define the Driver Message Levels.
+*/
+
+typedef enum DAC960_MessageLevel
+{
+ DAC960_AnnounceLevel = 0,
+ DAC960_InfoLevel = 1,
+ DAC960_NoticeLevel = 2,
+ DAC960_WarningLevel = 3,
+ DAC960_ErrorLevel = 4,
+ DAC960_CriticalLevel = 5
+}
+DAC960_MessageLevel_T;
+
+static char
+ *DAC960_MessageLevelMap[] =
+ { KERN_NOTICE, KERN_NOTICE, KERN_NOTICE,
+ KERN_WARNING, KERN_ERR, KERN_CRIT };
+
+
+/*
+ Define Driver Message macros.
+*/
+
+#define DAC960_Announce(Format, Arguments...) \
+ DAC960_Message(DAC960_AnnounceLevel, Format, ##Arguments)
+
+#define DAC960_Info(Format, Arguments...) \
+ DAC960_Message(DAC960_InfoLevel, Format, ##Arguments)
+
+#define DAC960_Notice(Format, Arguments...) \
+ DAC960_Message(DAC960_NoticeLevel, Format, ##Arguments)
+
+#define DAC960_Warning(Format, Arguments...) \
+ DAC960_Message(DAC960_WarningLevel, Format, ##Arguments)
+
+#define DAC960_Error(Format, Arguments...) \
+ DAC960_Message(DAC960_ErrorLevel, Format, ##Arguments)
+
+#define DAC960_Critical(Format, Arguments...) \
+ DAC960_Message(DAC960_CriticalLevel, Format, ##Arguments)
+
+
+/*
+ Define the types of DAC960 Controllers that are supported.
+*/
+
+typedef enum
+{
+ DAC960_V4_Controller = 1, /* DAC960PTL/PJ/PG */
+ DAC960_V3_Controller = 2 /* DAC960PU/PD/PL */
+}
+DAC960_ControllerType_T;
+
+
+/*
+ Define a Boolean data type.
+*/
+
+typedef enum { false, true } __attribute__ ((packed)) boolean;
+
+
+/*
+ Define a 32 bit I/O Address data type.
+*/
+
+typedef unsigned int DAC960_IO_Address_T;
+
+
+/*
+ Define a 32 bit PCI Bus Address data type.
+*/
+
+typedef unsigned int DAC960_PCI_Address_T;
+
+
+/*
+ Define a 32 bit Bus Address data type.
+*/
+
+typedef unsigned int DAC960_BusAddress_T;
+
+
+/*
+ Define a 32 bit Byte Count data type.
+*/
+
+typedef unsigned int DAC960_ByteCount_T;
+
+
+/*
+ Define types for some of the structures that interface with the rest
+ of the Linux Kernel and I/O Subsystem.
+*/
+
+typedef struct buffer_head BufferHeader_T;
+typedef struct file File_T;
+typedef struct file_operations FileOperations_T;
+typedef struct gendisk GenericDiskInfo_T;
+typedef struct hd_geometry DiskGeometry_T;
+typedef struct hd_struct DiskPartition_T;
+typedef struct inode Inode_T;
+typedef kdev_t KernelDevice_T;
+typedef unsigned long ProcessorFlags_T;
+typedef struct pt_regs Registers_T;
+typedef struct request IO_Request_T;
+typedef struct semaphore Semaphore_T;
+typedef struct timer_list Timer_T;
+
+
+/*
+ Define the DAC960 V4 Controller Interface Register Offsets.
+*/
+
+#define DAC960_V4_RegisterWindowSize 0x2000
+
+typedef enum
+{
+ DAC960_V4_InboundDoorBellRegisterOffset = 0x0020,
+ DAC960_V4_OutboundDoorBellRegisterOffset = 0x002C,
+ DAC960_V4_InterruptMaskRegisterOffset = 0x0034,
+ DAC960_V4_CommandOpcodeRegisterOffset = 0x1000,
+ DAC960_V4_CommandIdentifierRegisterOffset = 0x1001,
+ DAC960_V4_MailboxRegister2Offset = 0x1002,
+ DAC960_V4_MailboxRegister3Offset = 0x1003,
+ DAC960_V4_MailboxRegister4Offset = 0x1004,
+ DAC960_V4_MailboxRegister5Offset = 0x1005,
+ DAC960_V4_MailboxRegister6Offset = 0x1006,
+ DAC960_V4_MailboxRegister7Offset = 0x1007,
+ DAC960_V4_MailboxRegister8Offset = 0x1008,
+ DAC960_V4_MailboxRegister9Offset = 0x1009,
+ DAC960_V4_MailboxRegister10Offset = 0x100A,
+ DAC960_V4_MailboxRegister11Offset = 0x100B,
+ DAC960_V4_MailboxRegister12Offset = 0x100C,
+ DAC960_V4_StatusCommandIdentifierRegOffset = 0x1018,
+ DAC960_V4_StatusRegisterOffset = 0x101A
+}
+DAC960_V4_RegisterOffsets_T;
+
+
+/*
+ Define the structure of the DAC960 V4 Inbound Door Bell Register.
+*/
+
+typedef union DAC960_V4_InboundDoorBellRegister
+{
+ unsigned int All;
+ struct {
+ boolean NewCommand:1; /* Bit 0 */
+ boolean AcknowledgeStatus:1; /* Bit 1 */
+ boolean SoftReset:1; /* Bit 2 */
+ unsigned int :29; /* Bits 3-31 */
+ } Write;
+ struct {
+ boolean MailboxFull:1; /* Bit 0 */
+ unsigned int :31; /* Bits 1-31 */
+ } Read;
+}
+DAC960_V4_InboundDoorBellRegister_T;
+
+
+/*
+ Define the structure of the DAC960 V4 Outbound Door Bell Register.
+*/
+
+typedef union DAC960_V4_OutboundDoorBellRegister
+{
+ unsigned int All;
+ struct {
+ boolean AcknowledgeInterrupt:1; /* Bit 0 */
+ unsigned int :31; /* Bits 1-31 */
+ } Write;
+ struct {
+ boolean StatusAvailable:1; /* Bit 0 */
+ unsigned int :31; /* Bits 1-31 */
+ } Read;
+}
+DAC960_V4_OutboundDoorBellRegister_T;
+
+
+/*
+ Define the structure of the DAC960 V4 Interrupt Mask Register.
+*/
+
+typedef union DAC960_V4_InterruptMaskRegister
+{
+ unsigned int All;
+ struct {
+ unsigned int MessageUnitInterruptMask1:2; /* Bits 0-1 */
+ boolean DisableInterrupts:1; /* Bit 2 */
+ unsigned int MessageUnitInterruptMask2:5; /* Bits 3-7 */
+ unsigned int Reserved0:24; /* Bits 8-31 */
+ } Bits;
+}
+DAC960_V4_InterruptMaskRegister_T;
+
+
+/*
+ Define the DAC960 V3 Controller Interface Register Offsets.
+*/
+
+#define DAC960_V3_RegisterWindowSize 0x80
+
+typedef enum
+{
+ DAC960_V3_CommandOpcodeRegisterOffset = 0x00,
+ DAC960_V3_CommandIdentifierRegisterOffset = 0x01,
+ DAC960_V3_MailboxRegister2Offset = 0x02,
+ DAC960_V3_MailboxRegister3Offset = 0x03,
+ DAC960_V3_MailboxRegister4Offset = 0x04,
+ DAC960_V3_MailboxRegister5Offset = 0x05,
+ DAC960_V3_MailboxRegister6Offset = 0x06,
+ DAC960_V3_MailboxRegister7Offset = 0x07,
+ DAC960_V3_MailboxRegister8Offset = 0x08,
+ DAC960_V3_MailboxRegister9Offset = 0x09,
+ DAC960_V3_MailboxRegister10Offset = 0x0A,
+ DAC960_V3_MailboxRegister11Offset = 0x0B,
+ DAC960_V3_MailboxRegister12Offset = 0x0C,
+ 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/Makefile linux/drivers/block/Makefile
--- linux.vanilla/drivers/block/Makefile Fri Jul 24 17:28:56 1998
+++ linux/drivers/block/Makefile Fri Jan 29 14:21:03 1999
@@ -118,6 +118,10 @@
endif
endif
+ifeq ($(CONFIG_BLK_DEV_DAC960),y)
+L_OBJS += DAC960.o
+endif
+
ifeq ($(CONFIG_BLK_DEV_MD),y)
LX_OBJS += md.o
@@ -152,7 +156,15 @@
M_OBJS += raid5.o
endif
endif
+endif
+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
endif
+
include $(TOPDIR)/Rules.make
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/README.smart2 linux/drivers/block/README.smart2
--- linux.vanilla/drivers/block/README.smart2 Thu Jan 1 01:00:00 1970
+++ linux/drivers/block/README.smart2 Fri Jan 29 14:21:22 1999
@@ -0,0 +1,88 @@
+This driver is for Compaq's SMART2 Intellegent Disk Array Controllers.
+
+WARNING:
+--------
+
+This is still development code. It seems to work fine for me, but I haven't
+done any real hardcore testing against this driver. Also, things are likely
+to change, such as the major number used by the device driver as well as the
+names of the /dev entries.
+
+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
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#ifdef MODULE
+#include
+#include
+#else
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
+#endif
+
+#define DRIVER_NAME "Compaq SMART2 Driver (v 0.9.8)"
+
+#define MAJOR_NR COMPAQ_SMART2_MAJOR
+#include
+#include
+#include
+
+#include "cpqarray.h"
+#include "ida_cmd.h"
+#include "ida_ioctl.h"
+
+#define READ_AHEAD 128
+#define NR_CMDS 64
+
+#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",
+};
+
+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, int intr);
+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
+# warning "SMART2: EISA+PCI"
+# 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
+# warning "SMART2: PCI"
+# 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
+# warning "SMART2: 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; idrv[i];
+ if (!drv->nr_blks)
+ continue;
+ ida[(ctlr<nr_blks;
+
+ for(j=0; j<16; j++) {
+ ida_blocksizes[(ctlr<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 */
+};
+
+
+/*
+ * Place some files in /proc/array/* that contain some information about
+ * each controller. There really isn't much useful in there now.
+ */
+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; ctlrproc == 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; ilog_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; iintr, hba[i]);
+ vfree((void*)hba[i]->vaddr);
+ unregister_blkdev(MAJOR_NR+i, hba[i]->devname);
+ del_timer(&hba[i]->timer);
+ proc_unregister(proc_array,
+ ((struct proc_dir_entry*)hba[i]->proc)->low_ino);
+ kfree(hba[i]->cmd_pool);
+ kfree(hba[i]->cmd_pool_bits);
+
+ if (gendisk_head == &ida_gendisk[i]) {
+ gendisk_head = ida_gendisk[i].next;
+ } else {
+ for(g=gendisk_head; g; g=g->next) {
+ if (g->next == &ida_gendisk[i]) {
+ g->next = ida_gendisk[i].next;
+ break;
+ }
+ }
+ }
+
+ blk_dev[MAJOR_NR+i].request_fn = NULL;
+ blksize_size[MAJOR_NR+i] = NULL;
+ hardsect_size[MAJOR_NR+i] = NULL;
+ max_sectors[MAJOR_NR+i] = NULL;
+ max_segments[MAJOR_NR+i] = NULL;
+ }
+ proc_unregister(&proc_root, proc_array->low_ino);
+ kfree(ida);
+ kfree(ida_sizes);
+ kfree(ida_hardsizes);
+ kfree(ida_blocksizes);
+
+ kfree(ida_maxsectors);
+ kfree(ida_maxsegments);
+
+}
+#endif /* MODULE */
+
+/*
+ * This is it. Find all the controllers and register them. I really hate
+ * stealing all these major device numbers.
+ */
+void cpqarray_init(void)
+{
+ void (*request_fns[MAX_CTLR])(void) = {
+ do_ida_request0, do_ida_request1,
+ do_ida_request2, do_ida_request3,
+ do_ida_request4, do_ida_request5,
+ do_ida_request6, do_ida_request7,
+ };
+ int i;
+
+ /* detect controllers */
+#ifdef CONFIG_BLK_CPQ_DA_PCI
+ cpqarray_pci_detect();
+#endif
+#ifdef CONFIG_BLK_CPQ_DA_EISA
+ cpqarray_eisa_detect();
+#endif
+
+ if (nr_ctlr == 0)
+ return;
+
+ printk(DRIVER_NAME "\n");
+ printk("Found %d controller(s)\n", nr_ctlr);
+
+ /* allocate space for disk structs */
+ ida = kmalloc(sizeof(struct hd_struct)*nr_ctlr*NWD*16, GFP_KERNEL);
+ ida_sizes = kmalloc(sizeof(int)*nr_ctlr*NWD*16, GFP_KERNEL);
+ ida_blocksizes = kmalloc(sizeof(int)*nr_ctlr*NWD*16, GFP_KERNEL);
+ ida_hardsizes = kmalloc(sizeof(int)*nr_ctlr*NWD*16, GFP_KERNEL);
+
+ ida_maxsegments = kmalloc(sizeof(int)*nr_ctlr*NWD*16, GFP_KERNEL);
+ ida_maxsectors = kmalloc(sizeof(int)*nr_ctlr*NWD*16, GFP_KERNEL);
+
+ memset(ida, 0, sizeof(struct hd_struct)*nr_ctlr*NWD*16);
+ memset(ida_sizes, 0, sizeof(int)*nr_ctlr*NWD*16);
+ memset(ida_blocksizes, 0, sizeof(int)*nr_ctlr*NWD*16);
+ memset(ida_hardsizes, 0, sizeof(int)*nr_ctlr*NWD*16);
+ memset(ida_maxsegments, 0, sizeof(int)*nr_ctlr*NWD*16);
+ memset(ida_maxsectors, 0, sizeof(int)*nr_ctlr*NWD*16);
+ memset(ida_gendisk, 0, sizeof(struct gendisk)*MAX_CTLR);
+
+ for(i=0; iintr, do_ida_intr,
+ SA_INTERRUPT | SA_SHIRQ, hba[i]->devname, hba[i])) {
+
+ printk("Unable to get irq %d for %s\n",
+ hba[i]->intr, hba[i]->devname);
+ continue;
+ }
+ if (register_blkdev(MAJOR_NR+i, hba[i]->devname, &ida_fops)) {
+ printk("Unable to get major number %d for %s\n",
+ MAJOR_NR+i, hba[i]->devname);
+ continue;
+ }
+
+ hba[i]->cmd_pool = (cmdlist_t*)kmalloc(
+ NR_CMDS*sizeof(cmdlist_t), GFP_KERNEL);
+ hba[i]->cmd_pool_bits = (__u32*)kmalloc(
+ ((NR_CMDS+31)/32)*sizeof(__u32), GFP_KERNEL);
+ memset(hba[i]->cmd_pool, 0, NR_CMDS*sizeof(cmdlist_t));
+ memset(hba[i]->cmd_pool_bits, 0, ((NR_CMDS+31)/32)*sizeof(__u32));
+
+ printk("Finding drives on %s", hba[i]->devname);
+ getgeometry(i);
+
+ smart2_write(FIFO_NOT_EMPTY, hba[i], INTR_MASK);
+
+ ida_procinit(i);
+
+ ida_gendisk[i].major = MAJOR_NR + i;
+ ida_gendisk[i].major_name = "ida";
+ ida_gendisk[i].minor_shift = NWD_SHIFT;
+ ida_gendisk[i].max_p = 16;
+ ida_gendisk[i].max_nr = 16;
+ ida_gendisk[i].init = ida_geninit;
+ ida_gendisk[i].part = ida + (i*256);
+ ida_gendisk[i].sizes = ida_sizes + (i*256);
+ /* ida_gendisk[i].nr_real is handled by getgeometry */
+
+ blk_dev[MAJOR_NR+i].request_fn = request_fns[i];
+ blksize_size[MAJOR_NR+i] = ida_blocksizes + (i*256);
+ hardsect_size[MAJOR_NR+i] = ida_hardsizes + (i*256);
+ read_ahead[MAJOR_NR+i] = READ_AHEAD;
+ max_sectors[MAJOR_NR+i] = ida_maxsectors + (i*256);
+ max_segments[MAJOR_NR+i] = ida_maxsegments + (i*256);
+
+ /* Get on the disk list */
+ ida_gendisk[i].next = gendisk_head;
+ gendisk_head = &ida_gendisk[i];
+
+ init_timer(&hba[i]->timer);
+ hba[i]->timer.expires = jiffies + IDA_TIMER;
+ hba[i]->timer.data = (unsigned long)hba[i];
+ hba[i]->timer.function = ida_timer;
+ add_timer(&hba[i]->timer);
+
+ }
+ /* done ! */
+}
+
+#ifdef CONFIG_BLK_CPQ_DA_PCI
+/*
+ * Find the controller and initialize it
+ */
+static int cpqarray_pci_detect(void)
+{
+ int index;
+ unchar bus=0, dev_fn=0;
+
+ for(index=0; ; index++) {
+ if (pcibios_find_device(PCI_VENDOR_ID_COMPAQ,
+ PCI_DEVICE_ID_COMPAQ_SMART2P, index, &bus, &dev_fn))
+ break;
+
+ if (index == 1000000) break;
+ if (nr_ctlr == 8) {
+ printk("This driver supports a maximum of "
+ "8 controllers.\n");
+ break;
+ }
+
+ hba[nr_ctlr] = kmalloc(sizeof(ctlr_info_t), GFP_KERNEL);
+ memset(hba[nr_ctlr], 0, sizeof(ctlr_info_t));
+ cpqarray_pci_init(hba[nr_ctlr], bus, dev_fn);
+ sprintf(hba[nr_ctlr]->devname, "ida%d", nr_ctlr);
+ hba[nr_ctlr]->ctlr = nr_ctlr;
+ nr_ctlr++;
+ }
+
+ return nr_ctlr;
+}
+
+/*
+ * Find the IO address of the controller, its IRQ and so forth. Fill
+ * in some basic stuff into the ctlr_info_t structure.
+ */
+static void cpqarray_pci_init(ctlr_info_t *c, unchar bus, unchar device_fn)
+{
+ ushort vendor_id, device_id, command;
+ unchar cache_line_size, latency_timer;
+ unchar irq, revision;
+ uint addr[6];
+
+ int i;
+
+ (void) pcibios_read_config_word(bus, device_fn,
+ PCI_VENDOR_ID, &vendor_id);
+ (void) pcibios_read_config_word(bus, device_fn,
+ PCI_DEVICE_ID, &device_id);
+ (void) pcibios_read_config_word(bus, device_fn,
+ PCI_COMMAND, &command);
+ for(i=0; i<6; i++)
+ (void) pcibios_read_config_dword(bus, device_fn,
+ PCI_BASE_ADDRESS_0 + i*4, addr+i);
+
+ (void) pcibios_read_config_byte(bus, device_fn,
+ PCI_CLASS_REVISION,&revision);
+ (void) pcibios_read_config_byte(bus, device_fn,
+ PCI_INTERRUPT_LINE, &irq);
+ (void) pcibios_read_config_byte(bus, device_fn,
+ PCI_CACHE_LINE_SIZE, &cache_line_size);
+ (void) pcibios_read_config_byte(bus, device_fn,
+ PCI_LATENCY_TIMER, &latency_timer);
+
+DBGINFO(
+ printk("vendor_id = %x\n", vendor_id);
+ printk("device_id = %x\n", device_id);
+ printk("command = %x\n", command);
+ for(i=0; i<6; i++)
+ printk("addr[%d] = %x\n", i, addr[i]);
+ printk("revision = %x\n", revision);
+ printk("irq = %x\n", irq);
+ printk("cache_line_size = %x\n", cache_line_size);
+ printk("latency_timer = %x\n", latency_timer);
+);
+
+ c->intr = irq;
+ c->ioaddr = addr[0] & ~0x1;
+
+ /*
+ * Memory base addr is first addr with the first bit _not_ set
+ */
+ for(i=0; i<6; i++)
+ if (!(addr[i] & 0x1)) {
+ c->paddr = addr[i];
+ break;
+ }
+ c->vaddr = remap_pci_mem(c->paddr, 128);
+}
+
+/*
+ * Map (physical) PCI mem into (virtual) kernel space
+ */
+static ulong remap_pci_mem(ulong base, ulong size)
+{
+ ulong page_base = ((ulong) base) & PAGE_MASK;
+ ulong page_offs = ((ulong) base) - page_base;
+ ulong page_remapped = (ulong) vremap(page_base, page_offs+size);
+
+ return (ulong) (page_remapped ? (page_remapped + page_offs) : 0UL);
+}
+#endif /* CONFIG_BLK_CPQ_DA_PCI */
+
+#ifdef CONFIG_BLK_CPQ_DA_EISA
+/*
+ * Copy the contents of the ints[] array passed to us by init.
+ */
+void cpqarray_setup(char *str, int *ints)
+{
+ int i;
+ if (ints[0] & 1) {
+ printk( "SMART2 Parameter Usage:\n"
+ " smart2=io,irq,io,irq,...\n");
+ return;
+ }
+ for(i=0; iioaddr = eisa[i];
+ hba[nr_ctlr]->intr = eisa[i+1];
+ sprintf(hba[nr_ctlr]->devname, "ida%d", nr_ctlr);
+ hba[nr_ctlr]->ctlr = nr_ctlr;
+ nr_ctlr++;
+ } else {
+ printk("SMART2: Could not find a controller at io=0x%04x irq=0x%x\n", eisa[i], eisa[i+1]);
+ }
+ i+=2;
+ }
+ return nr_ctlr;
+}
+#endif /* CONFIG_BLK_CPQ_DA_EISA */
+
+/*
+ * Open. Make sure the device is really there.
+ */
+static int ida_open(struct inode *inode, struct file *filep)
+{
+ int ctlr = MAJOR(inode->i_rdev) - MAJOR_NR;
+ int dsk = MINOR(inode->i_rdev) >> NWD_SHIFT;
+
+ DBGINFO(printk("ida_open %x (%x:%x)\n", inode->i_rdev, ctlr, dsk) );
+ if (ctlr > MAX_CTLR || hba[ctlr] == NULL)
+ return -ENXIO;
+
+ if (!suser() && ida_sizes[(ctlr << CTLR_SHIFT) +
+ MINOR(inode->i_rdev)] == 0)
+ return -ENXIO;
+
+ /*
+ * Root is allowed to open raw volume zero even if its not configured
+ * so array config can still work. I don't think I really like this,
+ * but I'm already using way to many device nodes to claim another one
+ * for "raw controller".
+ */
+ if (suser()
+ && ida_sizes[(ctlr << CTLR_SHIFT) + MINOR(inode->i_rdev)] == 0
+ && MINOR(inode->i_rdev) != 0)
+ return -ENXIO;
+
+ hba[ctlr]->drv[dsk].usage_count++;
+ hba[ctlr]->usage_count++;
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+/*
+ * Close. Sync first.
+ */
+void ida_release(struct inode *inode, struct file *filep)
+{
+ int ctlr = MAJOR(inode->i_rdev) - MAJOR_NR;
+ int dsk = MINOR(inode->i_rdev) >> NWD_SHIFT;
+
+ DBGINFO(printk("ida_release %x (%x:%x)\n", inode->i_rdev, ctlr, dsk) );
+ fsync_dev(inode->i_rdev);
+
+ hba[ctlr]->drv[dsk].usage_count--;
+ hba[ctlr]->usage_count--;
+ MOD_DEC_USE_COUNT;
+}
+
+/*
+ * Enqueuing and dequeuing functions for cmdlists.
+ */
+static inline void addQ(cmdlist_t **Qptr, cmdlist_t *c)
+{
+ if (*Qptr == NULL) {
+ *Qptr = c;
+ c->next = c->prev = c;
+ } else {
+ c->prev = (*Qptr)->prev;
+ c->next = (*Qptr);
+ (*Qptr)->prev->next = c;
+ (*Qptr)->prev = c;
+ }
+}
+
+static inline cmdlist_t *removeQ(cmdlist_t **Qptr, cmdlist_t *c)
+{
+ if (c && c->next != c) {
+ if (*Qptr == c) *Qptr = c->next;
+ c->prev->next = c->next;
+ c->next->prev = c->prev;
+ } else {
+ *Qptr = NULL;
+ }
+ return c;
+}
+
+/*
+ * Get a request and submit it to the controller.
+ * This routine needs to grab all the requests it possibly can from the
+ * req Q and submit them. Interrupts are off (and need to be off) when you
+ * are in here (either via the dummy do_ida_request functions or by being
+ * called from the interrupt handler
+ */
+void do_ida_request(int ctlr)
+{
+ ctlr_info_t *h = hba[ctlr];
+ cmdlist_t *c;
+ int seg;
+ char *lastdataend;
+ struct buffer_head *bh;
+ struct request *creq;
+
+ creq = blk_dev[MAJOR_NR+ctlr].current_request;
+ if (creq == NULL || creq->rq_status == RQ_INACTIVE)
+ goto doreq_done;
+
+ if (ctlr != MAJOR(creq->rq_dev)-MAJOR_NR ||
+ ctlr > nr_ctlr || h == NULL) {
+ printk("doreq cmd for %d, %x at %p\n",
+ ctlr, creq->rq_dev, creq);
+ complete_buffers(creq->bh, 0);
+ goto doreq_done;
+ }
+
+ if ((c = cmd_alloc(h, 1)) == NULL)
+ goto doreq_done;
+
+ blk_dev[MAJOR_NR+ctlr].current_request = creq->next;
+ creq->rq_status = RQ_INACTIVE;
+
+ bh = creq->bh;
+
+ c->ctlr = ctlr;
+ c->hdr.unit = MINOR(creq->rq_dev) >> NWD_SHIFT;
+ c->hdr.prio = 0;
+ c->hdr.size = sizeof(rblk_t) >> 2;
+ c->size += sizeof(rblk_t);
+
+ c->req.hdr.next = 0;
+ c->req.hdr.rcode = 0;
+ c->req.bp = 0;
+ c->req.hdr.sg_cnt = creq->nr_segments;
+ c->req.hdr.reserved = 0;
+ c->req.hdr.blk = ida[(ctlr<rq_dev)].start_sect + creq->sector;
+ c->req.hdr.blk_cnt = creq->nr_sectors;
+ c->bh = bh;
+
+ seg = 0; lastdataend = NULL;
+ while(bh) {
+ if (bh->b_data == lastdataend) {
+ c->req.sg[seg-1].size += bh->b_size;
+ lastdataend += bh->b_size;
+ } else {
+ c->req.sg[seg].size = bh->b_size;
+ c->req.sg[seg].addr = (__u32) virt_to_bus(bh->b_data);
+ lastdataend = bh->b_data + bh->b_size;
+ if (seg++ > SG_MAX)
+ panic("SG list overflow\n");
+ }
+ bh = bh->b_reqnext;
+ }
+ if (seg != creq->nr_segments)
+ panic("seg != nr_segments\n");
+
+ c->req.hdr.cmd = (creq->cmd == READ) ? IDA_READ : IDA_WRITE;
+ c->type = CMD_RWREQ;
+
+ /* Put the request on the tail of the request queue */
+ addQ(&h->reqQ, c);
+ h->Qdepth++;
+ if (h->Qdepth > h->maxQsinceinit) h->maxQsinceinit = h->Qdepth;
+
+ wake_up(&wait_for_request);
+doreq_done:
+ start_io(h);
+}
+
+/*
+ * start_io submits everything on a controller's request queue
+ * and moves it to the completion queue.
+ *
+ * Interrupts had better be off if you're in here
+ */
+static void start_io(ctlr_info_t *h)
+{
+ cmdlist_t *c;
+
+ while((c = h->reqQ) != NULL) {
+ /* Can't do anything if we're busy */
+ if (smart2_read(h, COMMAND_FIFO) == 0)
+ return;
+
+ /* Get the first entry from the request Q */
+ removeQ(&h->reqQ, c);
+ h->Qdepth--;
+
+ /* Tell the controller to do our bidding */
+ smart2_write(c->busaddr, h, COMMAND_FIFO);
+
+ /* Get onto the completion Q */
+ addQ(&h->cmpQ, c);
+ }
+}
+
+
+static inline void complete_buffers(struct buffer_head *bh, int ok)
+{
+ struct buffer_head *xbh;
+ while(bh) {
+ xbh = bh->b_reqnext;
+ bh->b_reqnext = NULL;
+ mark_buffer_uptodate(bh, ok);
+ unlock_buffer(bh);
+ bh = xbh;
+ }
+}
+
+/*
+ * Mark all buffers that cmd was responsible for
+ */
+static inline void complete_command(cmdlist_t *cmd, int timeout)
+{
+ char buf[80];
+ int ok=1;
+
+ if (cmd->req.hdr.rcode & RCODE_NONFATAL &&
+ (hba[cmd->ctlr]->misc_tflags & MISC_NONFATAL_WARN) == 0) {
+ sprintf(buf, "Non Fatal error on ida/c%dd%d\n",
+ cmd->ctlr, cmd->hdr.unit);
+ console_print(buf);
+ hba[cmd->ctlr]->misc_tflags |= MISC_NONFATAL_WARN;
+ }
+ if (cmd->req.hdr.rcode & RCODE_FATAL) {
+ sprintf(buf, "Fatal error on ida/c%dd%d\n",
+ cmd->ctlr, cmd->hdr.unit);
+ console_print(buf);
+ ok = 0;
+ }
+ if (cmd->req.hdr.rcode & RCODE_INVREQ) {
+sprintf(buf, "Invalid request on ida/c%dd%d = (cmd=%x sect=%d cnt=%d sg=%d ret=%x)\n",
+ cmd->ctlr, cmd->hdr.unit, cmd->req.hdr.cmd,
+ cmd->req.hdr.blk, cmd->req.hdr.blk_cnt,
+ cmd->req.hdr.sg_cnt, cmd->req.hdr.rcode);
+ console_print(buf);
+ ok = 0;
+ }
+ if (timeout) {
+ sprintf(buf, "Request timeout on ida/c%dd%d\n",
+ cmd->ctlr, cmd->hdr.unit);
+ console_print(buf);
+ ok = 0;
+ }
+ complete_buffers(cmd->bh, ok);
+}
+
+/*
+ * The controller will interrupt us upon completion of commands.
+ * Find the command on the completion queue, remove it, tell the OS and
+ * try to queue up more IO
+ */
+void do_ida_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+ ctlr_info_t *h = dev_id;
+ cmdlist_t *c;
+ unsigned long istat;
+ __u32 a,a1;
+
+ istat = smart2_read(h, INTR_PENDING);
+ /* Is this interrupt for us? */
+ if (istat == 0)
+ return;
+
+ /*
+ * If there are completed commands in the completion queue,
+ * we had better do something about it.
+ */
+ if (istat & FIFO_NOT_EMPTY) {
+ while((a = smart2_read(h, COMMAND_COMPLETE_FIFO))) {
+ a1 = a; a &= ~3;
+ if ((c = h->cmpQ) == NULL) goto bad_completion;
+ while(c->busaddr != a) {
+ c = c->next;
+ if (c == h->cmpQ) break;
+ }
+ /*
+ * If we've found the command, take it off the
+ * completion Q and free it
+ */
+ if (c->busaddr == a) {
+ removeQ(&h->cmpQ, c);
+ if (c->type == CMD_RWREQ) {
+ complete_command(c, 0);
+ cmd_free(h, c);
+ } else if (c->type == CMD_IOCTL_PEND) {
+ c->type = CMD_IOCTL_DONE;
+ }
+ continue;
+ }
+bad_completion:
+ printk("Completion of %08lx ignored\n", (unsigned long)a1);
+ }
+ }
+
+ /*
+ * See if we can queue up some more IO (Is this safe?)
+ */
+ do_ida_request(h->ctlr);
+}
+
+/*
+ * This timer is for timing out requests that haven't happened after
+ * IDA_TIMEOUT, or rather it _WAS_ for timing out "dead" requests.
+ * That didn't work quite like I expected and would cause crashes
+ * and other nonsense.
+ */
+static void ida_timer(unsigned long tdata)
+{
+ ctlr_info_t *h = (ctlr_info_t*)tdata;
+
+ h->timer.expires = jiffies + IDA_TIMER;
+ add_timer(&h->timer);
+ h->misc_tflags = 0;
+}
+
+/*
+ * ida_ioctl does some miscellaneous stuff like reporting drive geometry,
+ * setting readahead and submitting commands from userspace to the controller.
+ */
+int ida_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, unsigned long arg)
+{
+ int ctlr = MAJOR(inode->i_rdev) - MAJOR_NR;
+ int dsk = MINOR(inode->i_rdev) >> NWD_SHIFT;
+ int error;
+ int diskinfo[4];
+ struct hd_geometry *geo = (struct hd_geometry *)arg;
+ ida_ioctl_t *io = (ida_ioctl_t*)arg;
+ ida_ioctl_t my_io;
+
+ DBGINFO(printk("ida_ioctl %x %x %x\n", inode->i_rdev, cmd, arg));
+ switch(cmd) {
+ case HDIO_GETGEO:
+ error = verify_area(VERIFY_WRITE, geo, sizeof(*geo));
+ if (error) return error;
+ if (hba[ctlr]->drv[dsk].cylinders) {
+ diskinfo[0] = hba[ctlr]->drv[dsk].heads;
+ diskinfo[1] = hba[ctlr]->drv[dsk].sectors;
+ diskinfo[2] = hba[ctlr]->drv[dsk].cylinders;
+ } else {
+ diskinfo[0] = 0xff;
+ diskinfo[1] = 0x3f;
+ diskinfo[2] = hba[ctlr]->drv[dsk].nr_blks / (0xff*0x3f);
+ }
+ put_user(diskinfo[0], &geo->heads);
+ put_user(diskinfo[1], &geo->sectors);
+ put_user(diskinfo[2], &geo->cylinders);
+ put_user(ida[(ctlr<i_rdev)].start_sect, &geo->start);
+ return 0;
+ case IDAGETDRVINFO:
+ error = verify_area(VERIFY_WRITE, io, sizeof(*io));
+ if (error) return error;
+ memcpy_tofs(&io->c.drv,&hba[ctlr]->drv[dsk],sizeof(drv_info_t));
+ return 0;
+ case BLKGETSIZE:
+ if (!arg) return -EINVAL;
+ error = verify_area(VERIFY_WRITE, (long*)arg, sizeof(long));
+ if (error) return error;
+ put_user(ida[(ctlr<i_rdev)].nr_sects, (long*)arg);
+ return 0;
+ case BLKRASET:
+ if (!suser()) return -EACCES;
+ if (!(inode->i_rdev)) return -EINVAL;
+ if (arg>0xff) return -EINVAL;
+ read_ahead[MAJOR(inode->i_rdev)] = arg;
+ return 0;
+ case BLKRAGET:
+ if (!arg) return -EINVAL;
+ error=verify_area(VERIFY_WRITE, (int*)arg, sizeof(int));
+ if (error) return error;
+ put_user(read_ahead[MAJOR(inode->i_rdev)], (int*)arg);
+ return 0;
+ case BLKRRPART:
+ return revalidate_logvol(inode->i_rdev, 1);
+ case IDAPASSTHRU:
+ if (!suser()) return -EPERM;
+ error = verify_area(VERIFY_READ|VERIFY_WRITE, io, sizeof(*io));
+ if (error) return error;
+ memcpy_fromfs(&my_io, io, sizeof(my_io));
+ error = ida_ctlr_ioctl(ctlr, dsk, &my_io);
+ if (error) return error;
+ memcpy_tofs(io, &my_io, sizeof(my_io));
+ return 0;
+ case IDAGETCTLRSIG:
+ if (!arg) return -EINVAL;
+ error=verify_area(VERIFY_WRITE, (int*)arg, sizeof(int));
+ if (error) return error;
+ put_user(hba[ctlr]->ctlr_sig, (int*)arg);
+ return 0;
+ case IDAREVALIDATEVOLS:
+ return revalidate_allvol(inode->i_rdev);
+
+ RO_IOCTLS(inode->i_rdev, arg);
+
+ default:
+ return -EBADRQC;
+ }
+
+}
+/*
+ * ida_ctlr_ioctl is for passing commands to the controller from userspace.
+ * The command block (io) has already been copied to kernel space for us,
+ * however, any elements in the sglist need to be copied to kernel space
+ * or copied back to userspace.
+ *
+ * Only root may perform a controller passthru command, however I'm not doing
+ * any serious sanity checking on the arguments. Doing an IDA_WRITE_MEDIA and
+ * putting a 64M buffer in the sglist is probably a *bad* idea.
+ */
+int ida_ctlr_ioctl(int ctlr, int dsk, ida_ioctl_t *io)
+{
+ ctlr_info_t *h = hba[ctlr];
+ cmdlist_t *c;
+ void *p = NULL;
+ unsigned long flags;
+ int error;
+
+ DBGINFO(printk("ida_ctlr_ioctl %d %x %p\n", ctlr, dsk, io));
+ if ((c = cmd_alloc(h, 0)) == NULL)
+ return -ENOMEM;
+ c->ctlr = ctlr;
+ c->hdr.unit = (io->unit & UNITVALID) ? io->unit &0x7f : dsk;
+ c->hdr.prio = 0;
+ c->hdr.size = sizeof(rblk_t) >> 2;
+ c->size += sizeof(rblk_t);
+
+ c->req.hdr.next = 0;
+ c->req.hdr.rcode = 0;
+ c->req.bp = 0;
+ c->req.hdr.reserved = 0;
+
+ c->req.hdr.blk = 0;
+ c->req.hdr.blk_cnt = 0;
+ c->req.hdr.cmd = io->cmd;
+ c->type = CMD_IOCTL_PEND;
+
+ /* Pre submit processing */
+ switch(io->cmd) {
+ case PASSTHRU_A:
+ error = verify_area(VERIFY_READ|VERIFY_WRITE,
+ (void*)io->sg[0].addr, io->sg[0].size);
+ if (error) goto ioctl_err_exit;
+
+ p = kmalloc(io->sg[0].size, GFP_KERNEL);
+ if (!p) { error = -ENOMEM; goto ioctl_err_exit; }
+ memcpy_fromfs(p, (void*)io->sg[0].addr, io->sg[0].size);
+ c->req.bp = virt_to_bus(&(io->c));
+ c->req.sg[0].size = io->sg[0].size;
+ c->req.sg[0].addr = virt_to_bus(p);
+ c->req.hdr.sg_cnt = 1;
+ break;
+ case IDA_READ:
+ error = verify_area(VERIFY_WRITE,
+ (void*)io->sg[0].addr, io->sg[0].size);
+ if (error) goto ioctl_err_exit;
+ p = kmalloc(io->sg[0].size, GFP_KERNEL);
+ if (!p) { error = -ENOMEM; goto ioctl_err_exit; }
+ c->req.sg[0].size = io->sg[0].size;
+ c->req.sg[0].addr = virt_to_bus(p);
+ c->req.hdr.sg_cnt = 1;
+ break;
+ case IDA_WRITE:
+ case IDA_WRITE_MEDIA:
+ error = verify_area(VERIFY_READ,
+ (void*)io->sg[0].addr, io->sg[0].size);
+ if (error) goto ioctl_err_exit;
+ p = kmalloc(io->sg[0].size, GFP_KERNEL);
+ if (!p) { error = -ENOMEM; goto ioctl_err_exit; }
+ memcpy_fromfs(p, (void*)io->sg[0].addr, io->sg[0].size);
+ c->req.sg[0].size = io->sg[0].size;
+ c->req.sg[0].addr = virt_to_bus(p);
+ c->req.hdr.sg_cnt = 1;
+ break;
+ default:
+ c->req.sg[0].size = sizeof(io->c);
+ c->req.sg[0].addr = virt_to_bus(&io->c);
+ c->req.hdr.sg_cnt = 1;
+ }
+
+ /* Put the request on the tail of the request queue */
+ save_flags(flags);
+ cli();
+ addQ(&h->reqQ, c);
+ h->Qdepth++;
+ start_io(h);
+ restore_flags(flags);
+
+ /* Wait for completion */
+ while(c->type != CMD_IOCTL_DONE)
+ schedule();
+
+ /* Post submit processing */
+ switch(io->cmd) {
+ case PASSTHRU_A:
+ case IDA_READ:
+ memcpy_tofs((void*)io->sg[0].addr, p, io->sg[0].size);
+ /* fall through and free p */
+ case IDA_WRITE:
+ case IDA_WRITE_MEDIA:
+ kfree(p);
+ break;
+ default:
+ /* Nothing to do */
+ }
+
+ io->rcode = c->req.hdr.rcode;
+ error = 0;
+ioctl_err_exit:
+ cmd_free(h, c);
+ return error;
+}
+
+/*
+ * Sooner or later we'll want to maintain our own cache of
+ * commands. For now, just use kmalloc to get them
+ */
+cmdlist_t * cmd_alloc(ctlr_info_t *h, int intr)
+{
+ cmdlist_t * c;
+ int i;
+
+ do {
+ i = find_first_zero_bit(h->cmd_pool_bits, NR_CMDS);
+ if (i == NR_CMDS)
+ return NULL;
+ } while(set_bit(i%32, h->cmd_pool_bits+(i/32)) != 0);
+
+ c = h->cmd_pool + i;
+ memset(c, 0, sizeof(cmdlist_t));
+ c->busaddr = virt_to_bus(c);
+ h->nr_allocs++;
+ return c;
+}
+
+void cmd_free(ctlr_info_t *h, cmdlist_t *c)
+{
+ int i = c - h->cmd_pool;
+ clear_bit(i%32, h->cmd_pool_bits+(i/32));
+ h->nr_frees++;
+}
+
+/***********************************************************************
+ name: sendcmd
+ Send a command to an IDA using the memory mapped FIFO interface
+ and wait for it to complete.
+ This routine should only be called at init time.
+***********************************************************************/
+int sendcmd(
+ __u8 cmd,
+ int ctlr,
+ void *buff,
+ size_t size,
+ unsigned int blk,
+ unsigned int blkcnt,
+ unsigned int log_unit )
+{
+ cmdlist_t *c;
+ int complete;
+ __u32 base_ptr;
+ unsigned long temp;
+ unsigned long i;
+ ctlr_info_t *info_p = hba[ctlr];
+
+ c = cmd_alloc(info_p, 0);
+ c->ctlr = ctlr;
+ c->hdr.unit = log_unit;
+ c->hdr.prio = 0;
+ c->hdr.size = sizeof(rblk_t) >> 2;
+ c->size += sizeof(rblk_t);
+
+ /* The request information. */
+ c->req.hdr.next = 0;
+ c->req.hdr.rcode = 0;
+ c->req.bp = 0;
+ c->req.hdr.sg_cnt = 1;
+ c->req.hdr.reserved = 0;
+
+ if (size == 0)
+ c->req.sg[0].size = 512;
+ else
+ c->req.sg[0].size = size;
+
+ c->req.hdr.blk = blk;
+ c->req.hdr.blk_cnt = blkcnt;
+ c->req.hdr.cmd = (unsigned char) cmd;
+ c->req.sg[0].addr = (__u32) virt_to_bus(buff);
+ flushcomplete(ctlr);
+ /*
+ * Disable interrupt
+ */
+ base_ptr = info_p->vaddr;
+ smart2_write(0, info_p, INTR_MASK);
+ /* Make sure there is room in the command FIFO */
+ /* Actually it should be completely empty at this time. */
+ for (i = 200000; i > 0; i--) {
+ temp = smart2_read(info_p, COMMAND_FIFO);
+ if (temp != 0) {
+ break;
+ }
+ udelay(10);
+DBG(
+ printk("ida%d: idaSendPciCmd FIFO full, waiting!\n",
+ ctlr);
+);
+ }
+ /*
+ * Send the cmd
+ */
+ smart2_write(c->busaddr, info_p, COMMAND_FIFO);
+ complete = pollcomplete(ctlr);
+ if (complete != 1) {
+ if (complete != c->busaddr) {
+ printk(
+ "ida%d: idaSendPciCmd "
+ "Invalid command list address returned! (%08lx)\n",
+ ctlr, (unsigned long)complete);
+ cmd_free(info_p, c);
+ return (IO_ERROR);
+ }
+ } else {
+ printk(
+ "ida%d: idaSendPciCmd Timeout out, "
+ "No command list address returned!\n",
+ ctlr);
+ cmd_free(info_p, c);
+ return (IO_ERROR);
+ }
+
+ if (c->req.hdr.rcode & 0x00FE) {
+ if (!(c->req.hdr.rcode & BIG_PROBLEM)) {
+ printk(
+ "ida%d: idaSendPciCmd, error: Controller failed "
+ "at init time "
+ "cmd: 0x%x, return code = 0x%x\n",
+ ctlr, c->req.hdr.cmd, c->req.hdr.rcode);
+
+ cmd_free(info_p, c);
+ return (IO_ERROR);
+ }
+ }
+ cmd_free(info_p, c);
+ return (IO_OK);
+}
+
+int frevalidate_logvol(kdev_t dev)
+{
+ return revalidate_logvol(dev, 0);
+}
+
+/*
+ * revalidate_allvol is for online array config utilities. After a
+ * utility reconfigures the drives in the array, it can use this function
+ * (through an ioctl) to make the driver zap any previous disk structs for
+ * that controller and get new ones.
+ *
+ * Right now I'm using the getgeometry() function to do this, but this
+ * function should probably be finer grained and allow you to revalidate one
+ * particualar logical volume (instead of all of them on a particular
+ * controller).
+ */
+static int revalidate_allvol(kdev_t dev)
+{
+ int ctlr, i;
+ unsigned long flags;
+
+ ctlr = MAJOR(dev) - MAJOR_NR;
+ if (MINOR(dev) != 0)
+ return -ENXIO;
+
+ save_flags(flags);
+ cli();
+ if (hba[ctlr]->usage_count > 1) {
+ restore_flags(flags);
+ printk("Device busy for volume revalidation (usage=%d)\n",
+ hba[ctlr]->usage_count);
+ return -EBUSY;
+ }
+
+ hba[ctlr]->usage_count++;
+ restore_flags(flags);
+
+ /*
+ * Set the partition and block size structures for all volumes
+ * on this controller to zero. We will reread all of this data
+ */
+ memset(ida+(ctlr*256), 0, sizeof(struct hd_struct)*NWD*16);
+ memset(ida_sizes+(ctlr*256), 0, sizeof(int)*NWD*16);
+ memset(ida_blocksizes+(ctlr*256), 0, sizeof(int)*NWD*16);
+ memset(ida_hardsizes+(ctlr*256), 0, sizeof(int)*NWD*16);
+ ida_gendisk[ctlr].nr_real = 0;
+
+ /*
+ * Tell the array controller not to give us any interupts while
+ * we check the new geometry. Then turn interrupts back on when
+ * we're done.
+ */
+ smart2_write(0, hba[ctlr], INTR_MASK);
+ getgeometry(ctlr);
+ smart2_write(FIFO_NOT_EMPTY, hba[ctlr], INTR_MASK);
+
+ ida_geninit(&ida_gendisk[ctlr]);
+ for(i=0; iusage_count--;
+ return 0;
+}
+
+/* Borrowed and adapted from sd.c */
+int revalidate_logvol(kdev_t dev, int maxusage)
+{
+ int ctlr, target;
+ struct gendisk *gdev;
+ unsigned long flags;
+ int max_p;
+ int start;
+ int i;
+
+ target = DEVICE_NR(dev);
+ ctlr = MAJOR(dev) - MAJOR_NR;
+ gdev = &ida_gendisk[ctlr];
+
+ save_flags(flags);
+ cli();
+ if (hba[ctlr]->drv[target].usage_count > maxusage) {
+ restore_flags(flags);
+ printk("Device busy for revalidation (usage=%d)\n",
+ hba[ctlr]->drv[target].usage_count);
+ return -EBUSY;
+ }
+
+ hba[ctlr]->drv[target].usage_count++;
+ restore_flags(flags);
+
+ max_p = gdev->max_p;
+ start = target << gdev->minor_shift;
+
+ for(i=max_p; i>=0; i--) {
+ int minor = start+i;
+ kdev_t devi = MKDEV(MAJOR_NR + ctlr, minor);
+ sync_dev(devi);
+ invalidate_inodes(devi);
+ invalidate_buffers(devi);
+ gdev->part[minor].start_sect = 0;
+ gdev->part[minor].nr_sects = 0;
+
+ /* reset the blocksize so we can read the partition table */
+ blksize_size[MAJOR_NR+ctlr][minor] = 1024;
+ }
+
+ gdev->part[start].nr_sects = hba[ctlr]->drv[target].nr_blks;
+ resetup_one_dev(gdev, target);
+ hba[ctlr]->drv[target].usage_count--;
+ return 0;
+}
+
+
+/********************************************************************
+ name: pollcomplete
+ Wait polling for a command to complete.
+ The memory mapped FIFO is polled for the completion.
+ Used only at init time, interrupts disabled.
+ ********************************************************************/
+int pollcomplete(int ctlr)
+{
+ int done;
+ int i;
+
+ /* Wait (up to 2 seconds) for a command to complete */
+
+ for (i = 200000; i > 0; i--) {
+ done = smart2_read(hba[ctlr], COMMAND_COMPLETE_FIFO);
+ if (done == 0) {
+ udelay(10); /* a short fixed delay */
+ } else
+ return (done);
+ }
+ /* Invalid address to tell caller we ran out of time */
+ return 1;
+}
+
+/*
+ * Clear the complete FIFO
+
+ Polling routine.
+ This should only be used at init time.
+ Any commands unexpectedly found in the completed command fifo
+ will be discarded. There should be none.
+ Called in only one place.
+ Note this reads and discards any completed commands but does not
+ wait for any uncompleted commands.
+ This is kinda goofy.
+
+ */
+void flushcomplete(int ctlr)
+{
+ unsigned long ret_addr;
+ unsigned int i;
+
+ for (i = 200000; i > 0; i--) {
+ ret_addr = smart2_read(hba[ctlr], COMMAND_COMPLETE_FIFO);
+ if (ret_addr == 0) {
+ break;
+ }
+ udelay(10);
+DBG(
+ printk("ida%d: flushcomplete "
+ "Discarding completion %x!\n",
+ ctlr, (unsigned int)ret_addr);
+);
+ }
+}
+
+
+
+/*****************************************************************
+ idaGetGeometry
+ Get ida logical volume geometry from the controller
+ This is a large bit of code which once existed in two flavors,
+ for EISA and PCI. It is used only at init time.
+****************************************************************
+*/
+void getgeometry(int ctlr)
+{
+ id_log_drv_t *id_ldrive;
+ id_ctlr_t *id_ctlr_buf;
+ sense_log_drv_stat_t *id_lstatus_buf;
+ config_t *sense_config_buf;
+ unsigned int log_unit, log_index;
+ int ret_code, size;
+ drv_info_t *drv;
+ ctlr_info_t *info_p = hba[ctlr];
+
+ id_ldrive = (id_log_drv_t *)kmalloc(sizeof(id_log_drv_t), GFP_KERNEL);
+ id_ctlr_buf = (id_ctlr_t *)kmalloc(sizeof(id_ctlr_t), GFP_KERNEL);
+ id_lstatus_buf = (sense_log_drv_stat_t *)kmalloc(sizeof(sense_log_drv_stat_t), GFP_KERNEL);
+ sense_config_buf = (config_t *)kmalloc(sizeof(config_t), GFP_KERNEL);
+
+ memset(id_ldrive, 0, sizeof(id_log_drv_t));
+ memset(id_ctlr_buf, 0, sizeof(id_ctlr_t));
+ memset(id_lstatus_buf, 0, sizeof(sense_log_drv_stat_t));
+ memset(sense_config_buf, 0, sizeof(config_t));
+
+ info_p->phys_drives = 0;
+ info_p->log_drv_map = 0;
+ info_p->drv_assign_map = 0;
+ info_p->drv_spare_map = 0;
+ info_p->mp_failed_drv_map = 0; /* only initialized here */
+ /* Get controllers info for this logical drive */
+ ret_code = sendcmd(ID_CTLR, ctlr, id_ctlr_buf, 0, 0, 0, 0);
+ if (ret_code == IO_ERROR) {
+ /*
+ * If can't get controller info, set the logical drive map to 0,
+ * so the idastubopen will fail on all logical drives
+ * on the controller.
+ */
+ goto geo_ret; /* release the buf and return */
+ }
+ info_p->log_drives = id_ctlr_buf->nr_drvs;;
+ *(__u32*)(info_p->firm_rev) = *(__u32*)(id_ctlr_buf->firm_rev);
+ info_p->ctlr_sig = id_ctlr_buf->cfg_sig;
+ info_p->board_id = id_ctlr_buf->board_id;
+
+ switch(info_p->board_id) {
+ case 0x0E114030: /* SMART-2/E */
+ info_p->product = 1;
+ break;
+ case 0x40300E11: /* SMART-2/P or SMART-2DH */
+ info_p->product = 2;
+ break;
+ case 0x40310E11: /* SMART-2SL */
+ info_p->product = 3;
+ break;
+ case 0x40320E11: /* SMART-3200 */
+ info_p->product = 4;
+ break;
+ case 0x40330E11: /* SMART-3100ES */
+ info_p->product = 5;
+ break;
+ default:
+ /*
+ * Well, its a SMART-2 or better, don't know which
+ * kind.
+ */
+ info_p->product = 0;
+ }
+ printk(" (%s)\n", product_names[info_p->product]);
+ /*
+ * Initialize logical drive map to zero
+ */
+#ifdef REDUNDANT
+ info_p->log_drive_map = 0;
+#endif /* #ifdef REDUNDANT */
+ log_index = 0;
+ /*
+ * Get drive geometry for all logical drives
+ */
+ if (id_ctlr_buf->nr_drvs > 16)
+ printk("ida%d: This driver supports 16 logical drives "
+ "per controller. Additional drives will not be "
+ "detected.\n", ctlr);
+
+ for (log_unit = 0;
+ (log_index < id_ctlr_buf->nr_drvs)
+ && (log_unit < NWD);
+ log_unit++) {
+
+ size = sizeof(sense_log_drv_stat_t);
+
+ /*
+ Send "Identify logical drive status" cmd
+ */
+ ret_code = sendcmd(SENSE_LOG_DRV_STAT,
+ ctlr, id_lstatus_buf, size, 0, 0, log_unit);
+ if (ret_code == IO_ERROR) {
+ /*
+ If can't get logical drive status, set
+ the logical drive map to 0, so the
+ idastubopen will fail for all logical drives
+ on the controller.
+ */
+ info_p->log_drv_map = 0;
+ printk(
+ "ida%d: idaGetGeometry - Controller failed "
+ "to report status of logical drive %d\n"
+ "Access to this controller has been disabled\n",
+ ctlr, log_unit);
+ goto geo_ret; /* release the buf and return */
+
+ }
+ /*
+ Make sure the logical drive is configured
+ */
+ if (id_lstatus_buf->status != LOG_NOT_CONF) {
+ ret_code = sendcmd(ID_LOG_DRV, ctlr, id_ldrive,
+ sizeof(id_log_drv_t), 0, 0, log_unit);
+ /*
+ If error, the bit for this
+ logical drive won't be set and
+ idastubopen will return error.
+ */
+ if (ret_code != IO_ERROR) {
+ drv = &info_p->drv[log_unit];
+ drv->blk_size = id_ldrive->blk_size;
+ drv->nr_blks = id_ldrive->nr_blks;
+ drv->cylinders = id_ldrive->drv.cyl;
+ drv->heads = id_ldrive->drv.heads;
+ drv->sectors = id_ldrive->drv.sect_per_track;
+ info_p->log_drv_map |= (1 << log_unit);
+
+ printk("ida/c%dd%d: blksz=%d nr_blks=%d\n",
+ ctlr, log_unit, drv->blk_size,
+ drv->nr_blks);
+ ret_code = sendcmd(SENSE_CONFIG,
+ ctlr, sense_config_buf,
+ sizeof(config_t), 0, 0, log_unit);
+ if (ret_code == IO_ERROR) {
+ info_p->log_drv_map = 0;
+ goto geo_ret; /* release the buf and return */
+ }
+ info_p->phys_drives =
+ sense_config_buf->ctlr_phys_drv;
+ info_p->drv_assign_map
+ |= sense_config_buf->drv_asgn_map;
+ info_p->drv_assign_map
+ |= sense_config_buf->spare_asgn_map;
+ info_p->drv_spare_map
+ |= sense_config_buf->spare_asgn_map;
+ } /* end of if no error on id_ldrive */
+ log_index = log_index + 1;
+ } /* end of if logical drive configured */
+ } /* end of for log_unit */
+ geo_ret:
+ kfree(id_ctlr_buf);
+ kfree(id_ldrive);
+ kfree(id_lstatus_buf);
+ kfree(sense_config_buf);
+}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/cpqarray.h linux/drivers/block/cpqarray.h
--- linux.vanilla/drivers/block/cpqarray.h Thu Jan 1 01:00:00 1970
+++ linux/drivers/block/cpqarray.h Tue Mar 2 00:39:51 1999
@@ -0,0 +1,96 @@
+/*
+ * 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 arrays@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 CPQARRAY_H
+#define CPQARRAY_H
+
+#ifdef __KERNEL__
+#include
+#include
+#include
+#include
+#include
+#include
+#endif
+
+#include "ida_cmd.h"
+
+#define IO_OK 0
+#define IO_ERROR 1
+#define NWD 16
+#define NWD_SHIFT 4
+
+#define IDA_TIMER (5*HZ)
+#define IDA_TIMEOUT (10*HZ)
+
+#define MISC_NONFATAL_WARN 0x01
+
+typedef struct {
+ unsigned blk_size;
+ unsigned nr_blks;
+ unsigned cylinders;
+ unsigned heads;
+ unsigned sectors;
+ int usage_count;
+} drv_info_t;
+
+typedef struct {
+ int ctlr;
+ char devname[8];
+ __u32 log_drv_map;
+ __u32 drv_assign_map;
+ __u32 drv_spare_map;
+ __u32 mp_failed_drv_map;
+
+ char firm_rev[4];
+ int product;
+ int ctlr_sig;
+
+ int log_drives;
+ int phys_drives;
+
+ __u32 board_id;
+ __u32 vaddr;
+ __u32 paddr;
+ __u32 ioaddr;
+ int intr;
+ int usage_count;
+ drv_info_t drv[NWD];
+ int proc;
+
+ cmdlist_t *reqQ;
+ cmdlist_t *cmpQ;
+ cmdlist_t *cmd_pool;
+ __u32 *cmd_pool_bits;
+ unsigned int Qdepth;
+ unsigned int maxQsinceinit;
+
+ unsigned int nr_requests;
+ unsigned int nr_allocs;
+ unsigned int nr_frees;
+ struct timer_list timer;
+ unsigned int misc_tflags;
+} ctlr_info_t;
+
+#endif /* CPQARRAY_H */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/floppy.c linux/drivers/block/floppy.c
--- linux.vanilla/drivers/block/floppy.c Sun Dec 6 00:14:36 1998
+++ linux/drivers/block/floppy.c Mon Mar 1 21:24:52 1999
@@ -96,6 +96,11 @@
* features to asm/floppy.h.
*/
+/*
+ * 1999/02/23 -- Paul Slootman -- floppy stopped working on Alpha after 24
+ * days, 6 hours, 32 minutes and 32 seconds (i.e. MAXINT jiffies; ints were
+ * being used to store jiffies, which are unsigned longs).
+ */
#define FLOPPY_SANITY_CHECK
#undef FLOPPY_SILENT_DCL_CLEAR
@@ -521,6 +526,8 @@
static unsigned char current_drive = 0;
static long current_count_sectors = 0;
static unsigned char sector_t; /* sector in track */
+static unsigned char in_sector_offset; /* offset within physical sector,
+ * expressed in units of 512 bytes */
#ifndef fd_eject
#define fd_eject(x) -EINVAL
@@ -571,10 +578,10 @@
#define OLOGSIZE 20
static void (*lasthandler)(void) = NULL;
-static int interruptjiffies=0;
-static int resultjiffies=0;
+static unsigned long interruptjiffies=0;
+static unsigned long resultjiffies=0;
static int resultsize=0;
-static int lastredo=0;
+static unsigned long lastredo=0;
static struct output_log {
unsigned char data;
@@ -677,7 +684,7 @@
#ifdef DCL_DEBUG
if (UDP->flags & FD_DEBUG){
DPRINT("checking disk change line for drive %d\n",drive);
- DPRINT("jiffies=%ld\n", jiffies);
+ DPRINT("jiffies=%lu\n", jiffies);
DPRINT("disk change line=%x\n",fd_inb(FD_DIR)&0x80);
DPRINT("flags=%x\n",UDRS->flags);
}
@@ -1224,7 +1231,7 @@
static void fdc_specify(void)
{
unsigned char spec1, spec2;
- int srt, hlt, hut;
+ unsigned long srt, hlt, hut;
unsigned long dtr = NOMINAL_DTR;
unsigned long scale_dtr = NOMINAL_DTR;
int hlt_max_code = 0x7f;
@@ -1407,7 +1414,8 @@
*/
static void setup_rw_floppy(void)
{
- int i,ready_date,r, flags,dflags;
+ int i,r, flags,dflags;
+ unsigned long ready_date;
timeout_fn function;
flags = raw_cmd->flags;
@@ -1480,7 +1488,7 @@
#ifdef DCL_DEBUG
if (DP->flags & FD_DEBUG){
DPRINT("clearing NEWCHANGE flag because of effective seek\n");
- DPRINT("jiffies=%ld\n", jiffies);
+ DPRINT("jiffies=%lu\n", jiffies);
}
#endif
CLEARF(FD_DISK_NEWCHANGE); /* effective seek */
@@ -1760,20 +1768,20 @@
printk("\n");
printk("floppy driver state\n");
printk("-------------------\n");
- printk("now=%ld last interrupt=%d last called handler=%p\n",
- jiffies, interruptjiffies, lasthandler);
+ printk("now=%lu last interrupt=%lu diff=%lu last called handler=%p\n",
+ jiffies, interruptjiffies, jiffies-interruptjiffies, lasthandler);
#ifdef FLOPPY_SANITY_CHECK
printk("timeout_message=%s\n", timeout_message);
printk("last output bytes:\n");
for (i=0; i < OLOGSIZE; i++)
- printk("%2x %2x %ld\n",
+ printk("%2x %2x %lu\n",
output_log[(i+output_log_pos) % OLOGSIZE].data,
output_log[(i+output_log_pos) % OLOGSIZE].status,
output_log[(i+output_log_pos) % OLOGSIZE].jiffies);
- printk("last result at %d\n", resultjiffies);
- printk("last redo_fd_request at %d\n", lastredo);
+ printk("last result at %lu\n", resultjiffies);
+ printk("last redo_fd_request at %lu\n", lastredo);
for (i=0; i> 2)
#define FM_MODE(x,y) ((y) & ~(((x)->rate & 0x80) >>1))
-#define CT(x) ((x) | 0x40)
+#define CT(x) ((x) | 0xc0)
static void setup_format_params(int track)
{
struct fparm {
@@ -2224,7 +2232,7 @@
/* Interrupt handler evaluating the result of the r/w operation */
static void rw_interrupt(void)
{
- int nr_sectors, ssize, eoc;
+ int nr_sectors, ssize, eoc, heads;
if (!DRS->first_read_date)
DRS->first_read_date = jiffies;
@@ -2236,23 +2244,32 @@
eoc = 1;
else
eoc = 0;
- nr_sectors = ((R_TRACK-TRACK)*_floppy->head+R_HEAD-HEAD) *
- _floppy->sect + ((R_SECTOR-SECTOR+eoc) << SIZECODE >> 2) -
- (sector_t % _floppy->sect) % ssize;
+
+ if(COMMAND & 0x80)
+ heads = 2;
+ else
+ heads = 1;
+
+ nr_sectors = (((R_TRACK-TRACK) * heads +
+ R_HEAD-HEAD) * SECT_PER_TRACK +
+ R_SECTOR-SECTOR + eoc) << SIZECODE >> 2;
#ifdef FLOPPY_SANITY_CHECK
- if (nr_sectors > current_count_sectors + ssize -
- (current_count_sectors + sector_t) % ssize +
- sector_t % ssize){
+ if (nr_sectors / ssize >
+ (in_sector_offset + current_count_sectors + ssize - 1)/ssize) {
DPRINT("long rw: %x instead of %lx\n",
nr_sectors, current_count_sectors);
printk("rs=%d s=%d\n", R_SECTOR, SECTOR);
printk("rh=%d h=%d\n", R_HEAD, HEAD);
printk("rt=%d t=%d\n", R_TRACK, TRACK);
- printk("spt=%d st=%d ss=%d\n", SECT_PER_TRACK,
- sector_t, ssize);
+ printk("heads=%d eoc=%d\n", heads, eoc);
+ printk("spt=%d st=%d ss=%d\n", SECT_PER_TRACK,
+ sector_t, ssize);
+ printk("in_sector_offset=%d\n", in_sector_offset);
}
#endif
+
+ nr_sectors -= in_sector_offset;
INFBOUND(nr_sectors,0);
SUPBOUND(current_count_sectors, nr_sectors);
@@ -2424,6 +2441,32 @@
#endif
}
+/* work around a bug in pseudo DMA
+ * (on some FDCs) pseudo DMA does not stop when the CPU stops
+ * sending data. Hence we need a different way to signal the
+ * transfer length: We use SECT_PER_TRACK. Unfortunately, this
+ * does not work with MT, hence we can only transfer one head at
+ * a time
+ */
+static void virtualdmabug_workaround(void) {
+ int hard_sectors, end_sector;
+ if(CT(COMMAND) == FD_WRITE) {
+ COMMAND &= ~0x80; /* switch off multiple track mode */
+
+ hard_sectors = raw_cmd->length >> (7 + SIZECODE);
+ end_sector = SECTOR + hard_sectors - 1;
+#ifdef FLOPPY_SANITY_CHECK
+ if(end_sector > SECT_PER_TRACK) {
+ printk("too many sectors %d > %d\n",
+ end_sector, SECT_PER_TRACK);
+ return;
+ }
+#endif
+ SECT_PER_TRACK = end_sector; /* make sure SECT_PER_TRACK points
+ * to end of transfer */
+ }
+}
+
/*
* Formulate a read/write request.
* this routine decides where to load the data (directly to buffer, or to
@@ -2495,11 +2538,17 @@
CODE2SIZE;
SECT_PER_TRACK = _floppy->sect << 2 >> SIZECODE;
SECTOR = ((sector_t % _floppy->sect) << 2 >> SIZECODE) + 1;
+
+ /* tracksize describes the size which can be filled up with sectors
+ * of size ssize.
+ */
tracksize = _floppy->sect - _floppy->sect % ssize;
if (tracksize < _floppy->sect){
SECT_PER_TRACK ++;
if (tracksize <= sector_t % _floppy->sect)
SECTOR--;
+
+ /* if we are beyond tracksize, fill up using smaller sectors */
while (tracksize <= sector_t % _floppy->sect){
while(tracksize + ssize > _floppy->sect){
SIZECODE--;
@@ -2509,10 +2558,15 @@
tracksize += ssize;
}
max_sector = HEAD * _floppy->sect + tracksize;
- } else if (!TRACK && !HEAD && !(_floppy->rate & FD_2M) && probing)
+ } else if (!TRACK && !HEAD && !(_floppy->rate & FD_2M) && probing) {
+ max_sector = _floppy->sect;
+ } else if (!HEAD && CT(COMMAND) == FD_WRITE) {
+ /* for virtual DMA bug workaround */
max_sector = _floppy->sect;
+ }
- aligned_sector_t = sector_t - (sector_t % _floppy->sect) % ssize;
+ in_sector_offset = (sector_t % _floppy->sect) % ssize;
+ aligned_sector_t = sector_t - in_sector_offset;
max_size = CURRENT->nr_sectors;
if ((raw_cmd->track == buffer_track) &&
(current_drive == buffer_drive) &&
@@ -2522,7 +2576,7 @@
copy_buffer(1, max_sector, buffer_max);
return 1;
}
- } else if (aligned_sector_t != sector_t || CURRENT->nr_sectors < ssize){
+ } else if (in_sector_offset || CURRENT->nr_sectors < ssize){
if (CT(COMMAND) == FD_WRITE){
if (sector_t + CURRENT->nr_sectors > ssize &&
sector_t + CURRENT->nr_sectors < ssize + ssize)
@@ -2575,6 +2629,7 @@
indirect, direct, sector_t);
return 0;
}
+ virtualdmabug_workaround();
return 2;
}
}
@@ -2588,7 +2643,7 @@
sector_t > buffer_max ||
sector_t < buffer_min ||
((CT(COMMAND) == FD_READ ||
- (aligned_sector_t == sector_t && CURRENT->nr_sectors >= ssize))&&
+ (!in_sector_offset && CURRENT->nr_sectors >= ssize))&&
max_sector > 2 * max_buffer_sectors + buffer_min &&
max_size + sector_t > 2 * max_buffer_sectors + buffer_min)
/* not enough space */){
@@ -2605,7 +2660,7 @@
* is either aligned or the data already in the buffer
* (buffer will be overwritten) */
#ifdef FLOPPY_SANITY_CHECK
- if (sector_t != aligned_sector_t && buffer_track == -1)
+ if (in_sector_offset && buffer_track == -1)
DPRINT("internal error offset !=0 on write\n");
#endif
buffer_track = raw_cmd->track;
@@ -2616,7 +2671,7 @@
2*max_buffer_sectors+buffer_min-aligned_sector_t);
/* round up current_count_sectors to get dma xfer size */
- raw_cmd->length = sector_t+current_count_sectors-aligned_sector_t;
+ raw_cmd->length = in_sector_offset+current_count_sectors;
raw_cmd->length = ((raw_cmd->length -1)|(ssize-1))+1;
raw_cmd->length <<= 9;
#ifdef FLOPPY_SANITY_CHECK
@@ -2678,6 +2733,8 @@
return 0;
}
#endif
+
+ virtualdmabug_workaround();
return 2;
}
@@ -3663,7 +3720,7 @@
if (UTESTF(FD_DISK_CHANGED) || UTESTF(FD_VERIFY))
return 1;
- if (UDP->checkfreq < jiffies - UDRS->last_checked){
+ if (UDP->checkfreq < (int)(jiffies - UDRS->last_checked)) {
lock_fdc(drive,0);
poll_drive(0,0);
process_fd_request();
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/genhd.c linux/drivers/block/genhd.c
--- linux.vanilla/drivers/block/genhd.c Sun Jun 21 18:41:09 1998
+++ linux/drivers/block/genhd.c Fri Jan 29 14:22:09 1999
@@ -51,6 +51,9 @@
extern int chr_dev_init(void);
extern int blk_dev_init(void);
+#ifdef CONFIG_BLK_DEV_DAC960
+extern void DAC960_Initialize(void);
+#endif
extern int scsi_dev_init(void);
extern int net_dev_init(void);
@@ -83,6 +86,31 @@
maj = "hd";
}
#endif
+#ifdef CONFIG_BLK_DEV_DAC960
+ if (hd->major >= DAC960_MAJOR+0 && hd->major <= DAC960_MAJOR+7)
+ {
+ int controller = hd->major - DAC960_MAJOR;
+ int partition = minor & ((1 << hd->minor_shift) - 1);
+ if (partition == 0)
+ sprintf(buf, "%s/c%dd%d",
+ maj, controller, minor >> hd->minor_shift);
+ else sprintf(buf, "%s/c%dd%dp%d",
+ maj, controller, minor >> hd->minor_shift, partition);
+ return buf;
+ }
+#endif
+#if defined(CONFIG_BLK_CPQ_DA) || defined(CONFIG_BLK_CPQ_DA_MODULE)
+ if (hd->major >= COMPAQ_SMART2_MAJOR && hd->major <= COMPAQ_SMART2_MAJOR+7) {
+ int ctlr = hd->major - COMPAQ_SMART2_MAJOR;
+ int disk = minor >> hd->minor_shift;
+ int part = minor & (( 1 << hd->minor_shift) - 1);
+ if (part == 0)
+ sprintf(buf, "%s/c%dd%d", maj, ctlr, disk);
+ else
+ sprintf(buf, "%s/c%dd%dp%d", maj, ctlr, disk, part);
+ return buf;
+ }
+#endif
part = minor & ((1 << hd->minor_shift) - 1);
if (part)
sprintf(buf, "%s%c%d", maj, unit, part);
@@ -93,10 +121,20 @@
static void add_partition (struct gendisk *hd, int minor, int start, int size)
{
- char buf[8];
+ char buf[40];
hd->part[minor].start_sect = start;
hd->part[minor].nr_sects = size;
- printk(" %s", disk_name(hd, minor, buf));
+#ifdef CONFIG_BLK_DEV_DAC960
+ if (hd->major >= DAC960_MAJOR+0 && hd->major <= DAC960_MAJOR+7)
+ printk(" p%d", (minor & ((1 << hd->minor_shift) - 1)));
+ else
+#endif
+#if defined(CONFIG_BLK_CPQ_DA) || defined(CONFIG_BLK_CPQ_DA_MODULE)
+ if (hd->major >= COMPAQ_SMART2_MAJOR && hd->major <= COMPAQ_SMART2_MAJOR+7)
+ printk(" p%d", (minor & ((1 << hd->minor_shift) - 1)));
+ else
+#endif
+ printk(" %s", disk_name(hd, minor, buf));
}
static inline int is_extended_partition(struct partition *p)
@@ -332,7 +370,9 @@
&& (q->sector & 63) == 1
&& (q->end_sector & 63) == 63) {
unsigned int heads = q->end_head + 1;
- if (heads == 32 || heads == 64 || heads == 128 || heads == 255) {
+ if (heads == 32 || heads == 64 ||
+ heads == 128 || heads == 240 ||
+ heads == 255) {
(void) ide_xlate_1024(dev, heads, " [PTBL]");
break;
@@ -641,7 +681,7 @@
{
static int first_time = 1;
unsigned long first_sector;
- char buf[8];
+ char buf[40];
if (first_time)
printk("Partition check:\n");
@@ -733,14 +773,21 @@
void device_setup(void)
{
extern void console_map_init(void);
+ extern void cpqarray_init(void);
struct gendisk *p;
int nr=0;
chr_dev_init();
blk_dev_init();
sti();
+#ifdef CONFIG_BLK_DEV_DAC960
+ DAC960_Initialize();
+#endif
#ifdef CONFIG_SCSI
scsi_dev_init();
+#endif
+#ifdef CONFIG_BLK_CPQ_DA
+ cpqarray_init();
#endif
#ifdef CONFIG_INET
net_dev_init();
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/hd.c linux/drivers/block/hd.c
--- linux.vanilla/drivers/block/hd.c Fri Jul 24 17:28:57 1998
+++ linux/drivers/block/hd.c Sun Dec 27 21:19:47 1998
@@ -871,6 +871,7 @@
restore_flags(flags);
return err;
+ case HDIO_OBSOLETE_IDENTITY:
case HDIO_GET_IDENTITY:
if (!arg) return -EINVAL;
if (MINOR(inode->i_rdev) & 0x3F) return -EINVAL;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/ida_cmd.h linux/drivers/block/ida_cmd.h
--- linux.vanilla/drivers/block/ida_cmd.h Thu Jan 1 01:00:00 1970
+++ linux/drivers/block/ida_cmd.h Tue Mar 2 00:40:03 1999
@@ -0,0 +1,338 @@
+/*
+ * 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 arrays@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 ARRAYCMD_H
+#define ARRAYCMD_H
+
+#include
+#if 0
+#include
+#endif
+
+
+#define COMMAND_FIFO 0x04
+#define COMMAND_COMPLETE_FIFO 0x08
+#define INTR_MASK 0x0C
+#define INTR_STATUS 0x10
+#define INTR_PENDING 0x14
+
+#define FIFO_NOT_EMPTY 0x01
+#define FIFO_NOT_FULL 0x02
+
+#define BIG_PROBLEM 0x40
+#define LOG_NOT_CONF 2
+
+#pragma pack(1)
+typedef struct {
+ __u32 size;
+ __u32 addr;
+} sg_t;
+
+#define RCODE_NONFATAL 0x02
+#define RCODE_FATAL 0x04
+#define RCODE_INVREQ 0x10
+typedef struct {
+ __u16 next;
+ __u8 cmd;
+ __u8 rcode;
+ __u32 blk;
+ __u16 blk_cnt;
+ __u8 sg_cnt;
+ __u8 reserved;
+} rhdr_t;
+
+#define SG_MAX 32
+typedef struct {
+ rhdr_t hdr;
+ sg_t sg[SG_MAX];
+ __u32 bp;
+} rblk_t;
+
+typedef struct {
+ __u8 unit;
+ __u8 prio;
+ __u16 size;
+} chdr_t;
+
+#define CMD_RWREQ 0x00
+#define CMD_IOCTL_PEND 0x01
+#define CMD_IOCTL_DONE 0x02
+
+typedef struct cmdlist {
+ chdr_t hdr;
+ rblk_t req;
+ __u32 size;
+ int retry_cnt;
+ __u32 busaddr;
+ int ctlr;
+ struct cmdlist *prev;
+ struct cmdlist *next;
+ struct buffer_head *bh;
+ int type;
+} cmdlist_t;
+
+#define ID_CTLR 0x11
+typedef struct {
+ __u8 nr_drvs;
+ __u32 cfg_sig;
+ __u8 firm_rev[4];
+ __u8 rom_rev[4];
+ __u8 hw_rev;
+ __u32 bb_rev;
+ __u32 drv_present_map;
+ __u32 ext_drv_map;
+ __u32 board_id;
+ __u8 cfg_error;
+ __u32 non_disk_bits;
+ __u8 bad_ram_addr;
+ __u8 cpu_rev;
+ __u8 pdpi_rev;
+ __u8 epic_rev;
+ __u8 wcxc_rev;
+ __u8 marketing_rev;
+ __u8 ctlr_flags;
+ __u8 host_flags;
+ __u8 expand_dis;
+ __u8 scsi_chips;
+ __u32 max_req_blocks;
+ __u32 ctlr_clock;
+ __u8 drvs_per_bus;
+ __u16 big_drv_present_map[8];
+ __u16 big_ext_drv_map[8];
+ __u16 big_non_disk_map[8];
+ __u16 task_flags;
+ __u8 icl_bus;
+ __u8 red_modes;
+ __u8 cur_red_mode;
+ __u8 red_ctlr_stat;
+ __u8 red_fail_reason;
+ __u8 reserved[403];
+} id_ctlr_t;
+
+typedef struct {
+ __u16 cyl;
+ __u8 heads;
+ __u8 xsig;
+ __u8 psectors;
+ __u16 wpre;
+ __u8 maxecc;
+ __u8 drv_ctrl;
+ __u16 pcyls;
+ __u8 pheads;
+ __u16 landz;
+ __u8 sect_per_track;
+ __u8 cksum;
+} drv_param_t;
+
+#define ID_LOG_DRV 0x10
+typedef struct {
+ __u16 blk_size;
+ __u32 nr_blks;
+ drv_param_t drv;
+ __u8 fault_tol;
+ __u8 reserved;
+ __u8 bios_disable;
+} id_log_drv_t;
+
+#define ID_LOG_DRV_EXT 0x18
+typedef struct {
+ __u32 log_drv_id;
+ __u8 log_drv_label[64];
+ __u8 reserved[418];
+} id_log_drv_ext_t;
+
+#define SENSE_LOG_DRV_STAT 0x12
+typedef struct {
+ __u8 status;
+ __u32 fail_map;
+ __u16 read_err[32];
+ __u16 write_err[32];
+ __u8 drv_err_data[256];
+ __u8 drq_timeout[32];
+ __u32 blks_to_recover;
+ __u8 drv_recovering;
+ __u16 remap_cnt[32];
+ __u32 replace_drv_map;
+ __u32 act_spare_map;
+ __u8 spare_stat;
+ __u8 spare_repl_map[32];
+ __u32 repl_ok_map;
+ __u8 media_exch;
+ __u8 cache_fail;
+ __u8 expn_fail;
+ __u8 unit_flags;
+ __u16 big_fail_map[8];
+ __u16 big_remap_map[8];
+ __u16 big_repl_map[8];
+ __u16 big_act_spare_map[8];
+ __u8 big_spar_repl_map[128];
+ __u16 big_repl_ok_map[8];
+ __u8 big_drv_rebuild;
+ __u8 reserved[36];
+} sense_log_drv_stat_t;
+
+#define START_RECOVER 0x13
+
+#define ID_PHYS_DRV 0x15
+typedef struct {
+ __u8 scsi_bus;
+ __u8 scsi_id;
+ __u16 blk_size;
+ __u32 nr_blks;
+ __u32 rsvd_blks;
+ __u8 drv_model[40];
+ __u8 drv_sn[40];
+ __u8 drv_fw[8];
+ __u8 scsi_iq_bits;
+ __u8 compaq_drv_stmp;
+ __u8 last_fail;
+ __u8 phys_drv_flags;
+ __u8 phys_drv_flags1;
+ __u8 scsi_lun;
+ __u8 phys_drv_flags2;
+ __u8 reserved;
+ __u32 spi_speed_rules;
+ __u8 phys_connector[2];
+ __u8 phys_box_on_bus;
+ __u8 phys_bay_in_box;
+} id_phys_drv_t;
+
+#define BLINK_DRV_LEDS 0x16
+typedef struct {
+ __u32 blink_duration;
+ __u32 reserved;
+ __u8 blink[256];
+ __u8 reserved1[248];
+} blink_drv_leds_t;
+
+#define SENSE_BLINK_LEDS 0x17
+typedef struct {
+ __u32 blink_duration;
+ __u32 btime_elap;
+ __u8 blink[256];
+ __u8 reserved1[248];
+} sense_blink_leds_t;
+
+#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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/ida_ioctl.h linux/drivers/block/ida_ioctl.h
--- linux.vanilla/drivers/block/ida_ioctl.h Thu Jan 1 01:00:00 1970
+++ linux/drivers/block/ida_ioctl.h Fri Jan 29 15:25:34 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 arrays@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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/ide.c linux/drivers/block/ide.c
--- linux.vanilla/drivers/block/ide.c Sun Dec 6 00:14:36 1998
+++ linux/drivers/block/ide.c Tue Mar 2 00:40:03 1999
@@ -277,6 +277,12 @@
* fix MC_ERR handling
* fix mis-detection of NEC cdrom as floppy
* 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.
*
* Some additional driver compile-time options are in ide.h
*
@@ -607,8 +613,12 @@
unsigned long chs_sects = id->cyls * id->heads * id->sectors;
unsigned long _10_percent = chs_sects / 10;
- /* 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)) {
id->cyls = lba_sects / (16 * 63); /* correct cyls */
return 1; /* lba_capacity is our only option */
}
@@ -649,6 +659,15 @@
drive->cyl = id->lba_capacity / (drive->head * drive->sect);
capacity = id->lba_capacity;
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
}
}
return (capacity - drive->sect0);
@@ -2192,17 +2211,18 @@
case HDIO_GET_MULTCOUNT:
return write_fs_long(arg, drive->mult_count);
+ case HDIO_OBSOLETE_IDENTITY:
case HDIO_GET_IDENTITY:
if (!arg || (MINOR(inode->i_rdev) & PARTN_MASK))
return -EINVAL;
if (drive->id == NULL)
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);
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);
return err;
- case HDIO_GET_NOWERR:
+ case HDIO_GET_NOWERR:
return write_fs_long(arg, drive->bad_wstat == BAD_R_STAT);
case HDIO_SET_DMA:
@@ -2545,9 +2565,8 @@
drive->sect = drive->bios_sect = id->sectors;
}
/* 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) {
/*
* Extract the physical drive geometry for our use.
* Note that we purposely do *not* update the bios info.
@@ -2572,19 +2591,38 @@
}
}
/* 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;
}
/* calculate drive capacity, and select LBA if possible */
- (void) current_capacity (drive);
+ capacity = current_capacity (drive);
- /* 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;
}
if (!strncmp(id->model, "BMI ", 4) &&
@@ -2592,27 +2630,54 @@
drive->select.b.lba)
drive->no_geom = 1;
- 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);
-
drive->mult_count = 0;
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 */
drive->mult_req = INITIAL_MULT_COUNT;
if (drive->mult_req > id->max_multsect)
drive->mult_req = id->max_multsect;
if (drive->mult_req || ((id->multsect_valid & 1) && id->multsect))
drive->special.b.set_multmode = 1;
+#endif
}
+
+ drive->no_io_32bit = id->dword_io ? 1 : 0;
+
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");
}
}
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
+ }
+ }
}
/*
@@ -3314,6 +3379,13 @@
* an IDE disk drive, or if a geometry was "forced" on the commandline.
* Returns 1 if the geometry translation was successful.
*/
+
+/*
+ * 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.
+ */
int ide_xlate_1024 (kdev_t i_rdev, int xparm, const char *msg)
{
ide_drive_t *drive;
@@ -3321,14 +3393,42 @@
const byte *heads = head_vals;
unsigned long tracks;
- if ((drive = get_info_ptr(i_rdev)) == NULL || drive->forced_geom)
+ drive = get_info_ptr(i_rdev);
+ if (!drive)
return 0;
- 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;
return 0; /* we already have a translation */
+ }
printk("%s ", msg);
+ 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 */
+ }
+
if (drive->id) {
drive->cyl = drive->id->cyls;
drive->head = drive->id->heads;
@@ -3366,6 +3466,12 @@
}
drive->part[0].nr_sects = current_capacity(drive);
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;
return 1;
}
@@ -3535,43 +3641,6 @@
}
#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 */
-}
-
#endif /* CONFIG_PCI */
/*
@@ -3599,11 +3668,20 @@
* So instead, we search for PCI_DEVICE_ID_INTEL_82371_0,
* and then add 1.
*/
+#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 */
ide_probe_pci (PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371_0, &ide_init_triton, 1);
ide_probe_pci (PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_1, &ide_init_triton, 0);
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 */
#endif /* CONFIG_BLK_DEV_TRITON */
- ide_probe_promise_20246();
}
#endif /* CONFIG_PCI */
#ifdef CONFIG_BLK_DEV_CMD640
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/ide.h linux/drivers/block/ide.h
--- linux.vanilla/drivers/block/ide.h Sun Dec 6 00:14:36 1998
+++ linux/drivers/block/ide.h Tue Mar 2 01:06:13 1999
@@ -429,7 +429,7 @@
typedef enum { ide_unknown, ide_generic, ide_triton,
ide_cmd640, ide_dtc2278, ide_ali14xx,
ide_qd6580, ide_umc8672, ide_ht6560b,
- ide_promise, ide_promise_udma }
+ ide_promise, ide_udma }
hwif_chipset_t;
typedef struct hwif_s {
@@ -743,5 +743,4 @@
#ifdef CONFIG_BLK_DEV_TRITON
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);
#endif /* CONFIG_BLK_DEV_TRITON */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c
--- linux.vanilla/drivers/block/ll_rw_blk.c Fri Jul 24 17:28:57 1998
+++ linux/drivers/block/ll_rw_blk.c Mon Mar 1 21:46:17 1999
@@ -82,6 +82,30 @@
int * hardsect_size[MAX_BLKDEV] = { NULL, NULL, };
/*
+ * 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)];
+}
+
+/*
* remove the plug and let it rip..
*/
void unplug_device(void * data)
@@ -233,22 +257,24 @@
void add_request(struct blk_dev_struct * dev, struct request * req)
{
+ int major = MAJOR(req->rq_dev);
+ int minor = MINOR(req->rq_dev);
struct request * tmp;
short disk_index;
- switch (MAJOR(req->rq_dev)) {
+ switch (major) {
case SCSI_DISK_MAJOR:
- disk_index = (MINOR(req->rq_dev) & 0x0070) >> 4;
+ disk_index = (minor & 0x0070) >> 4;
if (disk_index < 4)
drive_stat_acct(req->cmd, req->nr_sectors, disk_index);
break;
case IDE0_MAJOR: /* same as HD_MAJOR */
case XT_DISK_MAJOR:
- disk_index = (MINOR(req->rq_dev) & 0x0040) >> 6;
+ disk_index = (minor & 0x0040) >> 6;
drive_stat_acct(req->cmd, req->nr_sectors, disk_index);
break;
case IDE1_MAJOR:
- disk_index = ((MINOR(req->rq_dev) & 0x0040) >> 6) + 2;
+ disk_index = ((minor & 0x0040) >> 6) + 2;
drive_stat_acct(req->cmd, req->nr_sectors, disk_index);
default:
break;
@@ -274,30 +300,39 @@
tmp->next = req;
/* for SCSI devices, call request_fn unconditionally */
- if (scsi_blk_major(MAJOR(req->rq_dev)))
+ if (scsi_blk_major(major))
(dev->request_fn)();
+ if ( (major >= DAC960_MAJOR+0 && major <= DAC960_MAJOR+7) ||
+ (major >= COMPAQ_SMART2_MAJOR+0 && major <= COMPAQ_SMART2_MAJOR+7))
+ (dev->request_fn)();
+
sti();
}
-#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)
{
struct request *next = req->next;
+ int total_segments;
if (!next)
return;
if (req->sector + req->nr_sectors != next->sector)
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)
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
req->bhtail->b_reqnext = next->bh;
req->bhtail = next->bhtail;
req->nr_sectors += next->nr_sectors;
+ req->nr_segments = total_segments;
next->rq_status = RQ_INACTIVE;
req->next = next->next;
wake_up (&wait_for_request);
@@ -307,7 +342,7 @@
{
unsigned int sector, count;
struct request * req;
- int rw_ahead, max_req;
+ int rw_ahead, max_req, max_sectors, max_segments;
count = bh->b_size >> 9;
sector = bh->b_rsector;
@@ -324,7 +359,7 @@
lock_buffer(bh);
if (blk_size[major])
- if (blk_size[major][MINOR(bh->b_rdev)] < (sector + count)>>1) {
+ if (((blk_size[major][MINOR(bh->b_rdev)]<<1)+count) < sector) {
bh->b_state &= (1 << BH_Lock) | (1 << BH_FreeOnIO);
/* This may well happen - the kernel calls bread()
without checking the size of the device, e.g.,
@@ -390,6 +425,9 @@
/*
* Try to coalesce the new request with old requests
*/
+ max_sectors = get_max_sectors(bh->b_rdev);
+ max_segments = get_max_segments(bh->b_rdev);
+
cli();
req = blk_dev[major].current_request;
if (!req) {
@@ -418,25 +456,52 @@
case SCSI_DISK_MAJOR:
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:
do {
if (req->sem)
continue;
if (req->cmd != rw)
continue;
- if (req->nr_sectors >= MAX_SECTORS)
+ if (req->nr_sectors + count > max_sectors)
continue;
if (req->rq_dev != bh->b_rdev)
continue;
/* Can we add it to the end of this request? */
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;
+ }
req->bhtail->b_reqnext = bh;
req->bhtail = bh;
req->nr_sectors += count;
/* Can we now merge this req with the next? */
- attempt_merge(req);
+ attempt_merge(req, max_sectors, max_segments);
/* or to the beginning? */
} 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;
+ }
bh->b_reqnext = req->bh;
req->bh = bh;
req->buffer = bh->b_data;
@@ -470,6 +535,7 @@
req->errors = 0;
req->sector = sector;
req->nr_sectors = count;
+ req->nr_segments = 1;
req->current_nr_sectors = count;
req->buffer = bh->b_data;
req->sem = NULL;
@@ -634,6 +700,7 @@
req[j]->errors = 0;
req[j]->sector = rsector;
req[j]->nr_sectors = buffersize >> 9;
+ req[j]->nr_segments = 1;
req[j]->current_nr_sectors = buffersize >> 9;
req[j]->buffer = buf;
req[j]->sem = &sem;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/paride/Config.in linux/drivers/block/paride/Config.in
--- linux.vanilla/drivers/block/paride/Config.in Fri Jul 24 17:28:57 1998
+++ linux/drivers/block/paride/Config.in Sun Dec 27 21:08:29 1998
@@ -16,6 +16,7 @@
dep_tristate ' FIT TD-3000 protocol' CONFIG_PARIDE_FIT3 $CONFIG_PARIDE
dep_tristate ' Shuttle EPAT/EPEZ protocol' CONFIG_PARIDE_EPAT $CONFIG_PARIDE
dep_tristate ' Shuttle EPIA protocol' CONFIG_PARIDE_EPIA $CONFIG_PARIDE
+dep_tristate ' Freecom IQ ASIC-2 protocol' CONFIG_PARIDE_FRIQ $CONFIG_PARIDE
dep_tristate ' FreeCom power protocol' CONFIG_PARIDE_FRPW $CONFIG_PARIDE
dep_tristate ' KingByte KBIC-951A/971A protocols' CONFIG_PARIDE_KBIC $CONFIG_PARIDE
dep_tristate ' KT PHd protocol' CONFIG_PARIDE_KTTI $CONFIG_PARIDE
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/paride/Makefile linux/drivers/block/paride/Makefile
--- linux.vanilla/drivers/block/paride/Makefile Sun Dec 6 00:14:37 1998
+++ linux/drivers/block/paride/Makefile Sun Dec 27 21:08:29 1998
@@ -147,6 +147,15 @@
endif
endif
+
+ifeq ($(CONFIG_PARIDE_FRIQ),y)
+ LX_OBJS += friq.o
+else
+ ifeq ($(CONFIG_PARIDE_FRIQ),m)
+ M_OBJS += friq.o
+ endif
+endif
+
ifeq ($(CONFIG_PARIDE_ON20),y)
LX_OBJS += on20.o
else
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/paride/friq.c linux/drivers/block/paride/friq.c
--- linux.vanilla/drivers/block/paride/friq.c Thu Jan 1 01:00:00 1970
+++ linux/drivers/block/paride/friq.c Fri Jan 29 14:13:09 1999
@@ -0,0 +1,282 @@
+/*
+ friq.c (c) 1998 Grant R. Guenther
+ 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
+#include
+#include
+#include
+#include
+
+#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;kmode) {
+
+ case 0:
+ case 1: CMD(8); w2(5);
+ for (k=0;ksaved_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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/paride/frpw.c linux/drivers/block/paride/frpw.c
--- linux.vanilla/drivers/block/paride/frpw.c Sun Dec 6 00:14:37 1998
+++ linux/drivers/block/paride/frpw.c Sun Dec 27 21:08:29 1998
@@ -5,6 +5,12 @@
frpw.c is a low-level protocol driver for the Freecom "Power"
parallel port IDE adapter.
+ 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.
+
*/
/* Changes:
@@ -13,10 +19,11 @@
fix chip detect
added EPP-16 and EPP-32
1.02 GRG 1998.09.23 added hard reset to initialisation process
+ 1.03 GRG 1998.12.14 made hard reset conditional
*/
-#define FRPW_VERSION "1.02"
+#define FRPW_VERSION "1.03"
#include
#include
@@ -185,8 +192,10 @@
{ int olddelay, a, b;
+#ifdef FRPW_HARD_RESET
w0(0); w2(8); udelay(50); w2(0xc); /* parallel bus reset */
udelay(1500000);
+#endif
olddelay = pi->delay;
pi->delay = 10;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/paride/jumbo linux/drivers/block/paride/jumbo
--- linux.vanilla/drivers/block/paride/jumbo Sun Dec 6 00:14:37 1998
+++ linux/drivers/block/paride/jumbo Sun Dec 27 21:08:29 1998
@@ -53,11 +53,11 @@
FK="-D__KERNEL__ -I ../../../include"
FLCH=-D_LINUX_CONFIG_H
#
-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
#
-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
#
echo cc $FK $FSMP $FMODV -DMODULE -DPARIDE_JUMBO -Wall -O2 -o Jd.o -c $HLD.c
cc $FK $FSMP $FMODV -DMODULE -DPARIDE_JUMBO -Wall -O2 -o Jd.o -c $HLD.c
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/paride/on26.c linux/drivers/block/paride/on26.c
--- linux.vanilla/drivers/block/paride/on26.c Sun Dec 6 00:14:37 1998
+++ linux/drivers/block/paride/on26.c Fri Jan 29 14:13:09 1999
@@ -11,10 +11,12 @@
1.01 GRG 1998.05.06 init_proto, release_proto
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
*/
-#define ON26_VERSION "1.02"
+#define ON26_VERSION "1.04"
#include
#include
@@ -118,9 +120,11 @@
w2(pi->saved_r2);
}
+#define RESET_WAIT 200
+
static int on26_test_port( PIA *pi) /* hard reset */
-{ int i, m, d;
+{ int i, m, d, x, y;
pi->saved_r0 = r0();
pi->saved_r2 = r2();
@@ -151,11 +155,18 @@
on26_write_regr(pi,0,6,0xa0);
- for (i=0;i<100;i++) {
- if (!(on26_read_regr(pi,0,7) & 0x80)) break;
+ for (i=0;i
#include
@@ -449,6 +451,11 @@
pi_register(&frpw);
};
#endif
+#ifdef CONFIG_PARIDE_FRIQ
+ { extern struct pi_protocol friq;
+ pi_register(&friq);
+ };
+#endif
#ifdef CONFIG_PARIDE_FIT2
{ extern struct pi_protocol fit2;
pi_register(&fit2);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/paride/pseudo.h linux/drivers/block/paride/pseudo.h
--- linux.vanilla/drivers/block/paride/pseudo.h Fri Jul 24 17:28:57 1998
+++ linux/drivers/block/paride/pseudo.h Sun Dec 27 21:08:29 1998
@@ -16,19 +16,21 @@
when either it returns true, or timeout jiffies have passed,
continuation() will be invoked.
- If nice is true, the test will done approximately once a
+ If nice is 1, the test will done approximately once a
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.
*/
/* Changes:
1.01 1998.05.03 Switched from cli()/sti() to spinlocks
-
+ 1.02 1998.12.14 Added support for nice > 1
*/
-#define PS_VERSION "1.01"
+#define PS_VERSION "1.02"
#include
#include
@@ -37,13 +39,13 @@
static void ps_timer_int( unsigned long data);
static void ps_tq_int( void *data);
-static int ps_use_tq = 1;
static void (* ps_continuation)(void);
static int (* ps_ready)(void);
static int ps_then;
static int ps_timeout;
static int ps_timer_active = 0;
static int ps_tq_active = 0;
+static int ps_nice = 0;
/* static spinlock_t ps_spinlock = SPIN_LOCK_UNLOCKED; */
@@ -62,9 +64,9 @@
ps_ready = ready;
ps_then = jiffies;
ps_timeout = jiffies + timeout;
- ps_use_tq = !nice;
+ ps_nice = nice;
- if (ps_use_tq && !ps_tq_active) {
+ if (!ps_nice && !ps_tq_active) {
#ifdef HAVE_DISABLE_HLT
disable_hlt();
#endif
@@ -74,7 +76,7 @@
if (!ps_timer_active) {
ps_timer_active = 1;
- ps_timer.expires = jiffies;
+ ps_timer.expires = jiffies + (ps_nice>0)?(ps_nice-1):0;
add_timer(&ps_timer);
}
@@ -136,7 +138,7 @@
return;
}
ps_timer_active = 1;
- ps_timer.expires = jiffies;
+ ps_timer.expires = jiffies + (ps_nice>0)?(ps_nice-1):0;
add_timer(&ps_timer);
spin_unlock_irqrestore(&ps_spinlock,flags);
}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/paride/pt.c linux/drivers/block/paride/pt.c
--- linux.vanilla/drivers/block/paride/pt.c Sun Dec 6 00:14:37 1998
+++ linux/drivers/block/paride/pt.c Sun Dec 27 21:08:29 1998
@@ -464,7 +464,7 @@
{ int k, e, s;
- k = 0;
+ k = 0; e = 0; s = 0;
while (k < tmo) {
pt_sleep(pause);
k++;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/proc_array.c linux/drivers/block/proc_array.c
--- linux.vanilla/drivers/block/proc_array.c Thu Jan 1 01:00:00 1970
+++ linux/drivers/block/proc_array.c Fri Jan 29 14:22:46 1999
@@ -0,0 +1,119 @@
+/*
+ * Taken from linux/fs/proc/net.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ * gjh 3/'93 heim@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 waltje@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 (johnsonm@stolaf.edu) 3/93
+ * Added support from my previous inet.c. Cleaned things up
+ * quite a bit, modularized the code.
+ * fvk 4/'93 waltje@uwalt.nl.mugnet.org (Fred N. van Kempen)
+ * Renamed "route_get_info()" to "rt_get_info()" for consistency.
+ * Alan Cox (gw4pts@gw4pts.ampr.org) 4/94
+ * Dusted off the code and added IPX. Fixed the 4K limit.
+ * Erik Schoenfelder (schoenfr@ibr.cs.tu-bs.de)
+ * /proc/net/snmp.
+ * Alan Cox (gw4pts@gw4pts.ampr.org) 1/95
+ * Added Appletalk slots
+ *
+ * proc diskarray directory handling functions
+ */
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#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 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.
*/
+
#include
#include
#include
@@ -120,6 +31,13 @@
#include "ide.h"
#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
+#include
+#include
+#endif
/*
* good_dma_drives() lists the model names (from "hdparm -i")
@@ -132,6 +50,27 @@
NULL};
/*
+ * 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};
+
+/*
* Our Physical Region Descriptor (PRD) table should be large enough
* to handle the biggest I/O request we are likely to see. Since requests
* can have no more than 256 sectors, and since the typical blocksize is
@@ -150,6 +89,7 @@
#define PRD_BYTES 8
#define PRD_ENTRIES (PAGE_SIZE / (2 * PRD_BYTES))
#define DEFAULT_BMIBA 0xe800 /* in case BIOS did not init it */
+#define DEFAULT_BMCRBA 0xcc00 /* VIA's default value */
/*
* dma_intr() is the handler for disk read/write DMA interrupts
@@ -161,8 +101,8 @@
struct request *rq = HWGROUP(drive)->rq;
unsigned short dma_base = HWIF(drive)->dma_base;
- dma_stat = inb(dma_base+2); /* get DMA status */
outb(inb(dma_base)&~1, dma_base); /* stop DMA operation */
+ dma_stat = inb(dma_base+2); /* get DMA status */
stat = GET_STAT(); /* get drive status */
if (OK_STAT(stat,DRIVE_READY,drive->bad_wstat|DRQ_STAT)) {
if ((dma_stat & 7) == 4) { /* verify good DMA status */
@@ -244,23 +184,37 @@
return 1; /* let the PIO routines handle this weirdness */
}
+/*
+ * 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.
+ */
static int config_drive_for_dma (ide_drive_t *drive)
{
const char **list;
struct hd_driveid *id = drive->id;
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 */
if (id->field_valid & 4) /* UltraDMA */
- if ((id->dma_ultra & (id->dma_ultra >> 8) & 7)) {
+ if ((id->dma_ultra & 0x404) == 0x404) {
drive->using_dma = 1;
- return 0; /* dma enabled */
+ return 0; /* DMA enabled */
}
- /* Enable DMA on any drive that has mode2 DMA (multi or single) enabled */
+ /* Enable DMA on any drive that has mode2 DMA enabled */
if (id->field_valid & 2) /* regular DMA */
- if ((id->dma_mword & 0x404) == 0x404 || (id->dma_1word & 0x404) == 0x404) {
+ if ((id->dma_mword & 0x404) == 0x404) {
drive->using_dma = 1;
- return 0; /* dma enabled */
+ return 0; /* DMA enabled */
}
/* Consult the list of known "good" drives */
list = good_dma_drives;
@@ -387,22 +341,135 @@
}
/*
+ * 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);
+}
+
+/*
* ide_init_triton() prepares the IDE driver for DMA operation.
* 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).
*/
void ide_init_triton (byte bus, byte fn)
{
int rc = 0, h;
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
+ * PCI_BASE_ADDRESS_2 hwif1->io_base
+ * PCI_BASE_ADDRESS_3 hwif1->ctl_port
+ * PCI_BASE_ADDRESS_4 bmiba
+ */
+ memset(io, 0, 6 * sizeof(unsigned short));
+ 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;
+ }
+ break;
+ default:
+ return;
+ }
+
+ printk("\n Controller on PCI bus %d function %d\n", bus, fn);
- printk("ide: i82371 PIIX (Triton) on PCI bus %d function %d\n", bus, fn);
/*
* See if IDE and BM-DMA features are enabled:
*/
- if ((rc = pcibios_read_config_word(bus, fn, 0x04, &pcicmd)))
+ if ((rc = pcibios_read_config_word(bus, fn, PCI_COMMAND, &pcicmd)))
goto quit;
if ((pcicmd & 1) == 0) {
printk("ide: ports are not enabled (BIOS)\n");
@@ -416,21 +483,21 @@
*/
int try_again = 1;
do {
- if ((rc = pcibios_read_config_dword(bus, fn, 0x20, &bmiba)))
+ if ((rc = pcibios_read_config_dword(bus, fn, PCI_BASE_ADDRESS_4, &bmiba)))
goto quit;
bmiba &= 0xfff0; /* extract port base address */
if (bmiba) {
dma_enabled = 1;
break;
} else {
- printk("ide: BM-DMA base register is invalid (0x%04x, PnP BIOS problem)\n", bmiba);
- if (inb(DEFAULT_BMIBA) != 0xff || !try_again)
+ printk("ide: BM-DMA base register is invalid (0x%04x, PnP BIOS problem)\n", bmiba);
+ if (inb(((vendor == PCI_VENDOR_ID_VIA) ? DEFAULT_BMCRBA : DEFAULT_BMIBA)) != 0xff || !try_again)
break;
- printk("ide: setting BM-DMA base register to 0x%04x\n", DEFAULT_BMIBA);
- if ((rc = pcibios_write_config_word(bus, fn, 0x04, pcicmd&~1)))
+ printk("ide: setting BM-DMA base register to 0x%04x\n", ((vendor == PCI_VENDOR_ID_VIA) ? DEFAULT_BMCRBA : DEFAULT_BMIBA));
+ if ((rc = pcibios_write_config_word(bus, fn, PCI_COMMAND, pcicmd&~1)))
goto quit;
- rc = pcibios_write_config_dword(bus, fn, 0x20, DEFAULT_BMIBA|1);
- if (pcibios_write_config_word(bus, fn, 0x04, pcicmd|5) || rc)
+ rc = pcibios_write_config_dword(bus, fn, 0x20, ((vendor == PCI_VENDOR_ID_VIA) ? DEFAULT_BMCRBA : DEFAULT_BMIBA)|1);
+ if (pcibios_write_config_word(bus, fn, PCI_COMMAND, pcicmd|5) || rc)
goto quit;
}
} while (try_again--);
@@ -439,89 +506,218 @@
/*
* See if ide port(s) are enabled
*/
- if ((rc = pcibios_read_config_dword(bus, fn, 0x40, &timings)))
- goto quit;
- if (!(timings & 0x80008000)) {
- printk("ide: neither port is enabled\n");
+ if ((rc = pcibios_read_config_dword(bus, fn,
+ (vendor == PCI_VENDOR_ID_PROMISE) ? 0x50 :
+ (vendor == PCI_VENDOR_ID_ARTOP) ? 0x54 :
+ 0x40, &timings)))
goto quit;
- }
+ /*
+ * We do a vendor check since the Ultra33 and AEC6210
+ * holds their timings in a different location.
+ */
+ printk("ide: timings == %08x\n", timings);
+
+ /*
+ * The switch preserves some stuff that was original.
+ */
+ switch(vendor) {
+ case PCI_VENDOR_ID_INTEL:
+ if (!(timings & 0x80008000)) {
+ printk("ide: INTEL: neither port is enabled\n");
+ goto quit;
+ }
+ break;
+ case PCI_VENDOR_ID_VIA:
+ if(!(timings & 0x03)) {
+ printk("ide: VIA: neither port is enabled\n");
+ goto quit;
+ }
+ break;
+ case PCI_VENDOR_ID_SI:
+ case PCI_VENDOR_ID_PROMISE:
+ case PCI_VENDOR_ID_ARTOP:
+ default:
+ break;
+ }
/*
* Save the dma_base port addr for each interface
*/
for (h = 0; h < MAX_HWIFS; ++h) {
+ ide_hwif_t *hwif = &ide_hwifs[h];
+
+ /*
+ * This prevents the first contoller from accidentally
+ * initalizing the hwif's that it does not use and block
+ * an off-board ide-pci from getting in the game.
+ */
+ if (step_count >= 2) {
+ goto quit;
+ }
+#ifdef CONFIG_BLK_DEV_OFFBOARD
+ /*
+ * This is a forced override for the onboard ide controller
+ * to be enabled, if one chooses to have an offboard ide-pci
+ * card as the primary booting device. This beasty is
+ * for offboard UDMA upgrades with hard disks, but saving
+ * the onboard DMA2 controllers for CDROMS, TAPES, ZIPS, etc...
+ */
+ if ((vendor == PCI_VENDOR_ID_INTEL) ||
+ (vendor == PCI_VENDOR_ID_SI) ||
+ (vendor == PCI_VENDOR_ID_VIA)) {
+ if (h == 2) {
+ hwif->io_base = 0x1f0;
+ hwif->ctl_port = 0x3f6;
+ hwif->irq = 14;
+ hwif->noprobe = 0;
+ }
+ if (h == 3) {
+ hwif->io_base = 0x170;
+ hwif->ctl_port = 0x376;
+ hwif->irq = 15;
+ hwif->noprobe = 0;
+ }
+ }
+#endif /* CONFIG_BLK_DEV_OFFBOARD */
+ /*
+ * If the chipset is listed as "ide_unknown", lets get a
+ * hwif while they last. This does the first check on
+ * the current availability of the ide_hwifs[h] in question.
+ */
+ if (hwif->chipset != ide_unknown) {
+ continue;
+ } else if (vendor == PCI_VENDOR_ID_INTEL) {
+ unsigned short time;
#ifdef DISPLAY_TRITON_TIMINGS
- byte s_clks, r_clks;
- unsigned short devid;
+ byte s_clks, r_clks;
+ unsigned short devid;
#endif /* DISPLAY_TRITON_TIMINGS */
- ide_hwif_t *hwif = &ide_hwifs[h];
- unsigned short time;
- if (hwif->io_base == 0x1f0) {
- time = timings & 0xffff;
- if ((time & 0x8000) == 0) /* interface enabled? */
- continue;
- hwif->chipset = ide_triton;
- if (dma_enabled)
- init_triton_dma(hwif, bmiba);
- } else if (hwif->io_base == 0x170) {
- time = timings >> 16;
- if ((time & 0x8000) == 0) /* interface enabled? */
+ if (hwif->io_base == 0x1f0) {
+ time = timings & 0xffff;
+ if ((time & 0x8000) == 0) /* interface enabled? */
+ continue;
+ hwif->chipset = ide_triton;
+ if (dma_enabled)
+ init_triton_dma(hwif, bmiba);
+ step_count++;
+ } else if (hwif->io_base == 0x170) {
+ time = timings >> 16;
+ if ((time & 0x8000) == 0) /* interface enabled? */
+ continue;
+ hwif->chipset = ide_triton;
+ if (dma_enabled)
+ init_triton_dma(hwif, bmiba + 8);
+ step_count++;
+ } else {
continue;
- hwif->chipset = ide_triton;
- if (dma_enabled)
- init_triton_dma(hwif, bmiba + 8);
- } else
- continue;
+ }
#ifdef DISPLAY_TRITON_TIMINGS
- s_clks = ((~time >> 12) & 3) + 2;
- r_clks = ((~time >> 8) & 3) + 1;
- printk(" %s timing: (0x%04x) sample_CLKs=%d, recovery_CLKs=%d\n",
- hwif->name, time, s_clks, r_clks);
- if ((time & 0x40) && !pcibios_read_config_word(bus, fn, 0x02, &devid)
- && devid == PCI_DEVICE_ID_INTEL_82371SB_1)
- {
- byte stime;
- if (pcibios_read_config_byte(bus, fn, 0x44, &stime)) {
- if (hwif->io_base == 0x1f0) {
- s_clks = ~stime >> 6;
- r_clks = ~stime >> 4;
+ s_clks = ((~time >> 12) & 3) + 2;
+ r_clks = ((~time >> 8) & 3) + 1;
+ printk(" %s timing: (0x%04x) sample_CLKs=%d, recovery_CLKs=%d\n",
+ hwif->name, time, s_clks, r_clks);
+ if ((time & 0x40) && !pcibios_read_config_word(bus, fn, PCI_DEVICE_ID, &devid)
+ && devid == PCI_DEVICE_ID_INTEL_82371SB_1) {
+ byte stime;
+ if (pcibios_read_config_byte(bus, fn, 0x44, &stime)) {
+ if (hwif->io_base == 0x1f0) {
+ s_clks = ~stime >> 6;
+ r_clks = ~stime >> 4;
+ } else {
+ s_clks = ~stime >> 2;
+ r_clks = ~stime;
+ }
+ s_clks = (s_clks & 3) + 2;
+ r_clks = (r_clks & 3) + 1;
+ printk(" slave: sample_CLKs=%d, recovery_CLKs=%d\n",
+ s_clks, r_clks);
+ }
+ }
+ print_triton_drive_flags (0, time & 0xf);
+ print_triton_drive_flags (1, (time >> 4) & 0xf);
+#endif /* DISPLAY_TRITON_TIMINGS */
+ } else if (vendor == PCI_VENDOR_ID_SI) {
+ if (hwif->io_base == 0x1f0) {
+ hwif->chipset = ide_triton;
+ if (dma_enabled)
+ init_triton_dma(hwif, bmiba);
+ step_count++;
+ } else if (hwif->io_base == 0x170) {
+ hwif->chipset = ide_triton;
+ if (dma_enabled)
+ init_triton_dma(hwif, bmiba + 8);
+ step_count++;
+ } else {
+ continue;
+ }
+ } else if(vendor == PCI_VENDOR_ID_VIA) {
+ if (hwif->io_base == 0x1f0) {
+ if((timings & 0x02) == 0)
+ continue;
+ hwif->chipset = ide_triton;
+ if (dma_enabled)
+ init_triton_dma(hwif, bmiba);
+ if (set_via_timings(bus, fn, 0xc0, 0xa0))
+ goto quit;
+#ifdef DISPLAY_APOLLO_TIMINGS
+ proc_register_dynamic(&proc_root, &via_proc_entry);
+#endif /* DISPLAY_APOLLO_TIMINGS */
+ step_count++;
+ } else if (hwif->io_base == 0x170) {
+ if((timings & 0x01) == 0)
+ continue;
+ hwif->chipset = ide_triton;
+ if (dma_enabled)
+ init_triton_dma(hwif, bmiba + 8);
+ if (set_via_timings(bus, fn, 0x30, 0x50))
+ goto quit;
+ step_count++;
+ } else {
+ continue;
+ }
+ } else if ((vendor == PCI_VENDOR_ID_PROMISE) ||
+ (vendor == PCI_VENDOR_ID_ARTOP)) {
+ /*
+ * This silly tmp = h routine allows an off-board ide-pci card to
+ * be booted as primary hwifgroup, provided that the onboard
+ * controllers are disabled. If they are active, then we wait our
+ * turn for hwif assignment.
+ */
+ unsigned char irq = 0;
+ pcibios_read_config_byte (bus, fn, PCI_INTERRUPT_LINE, &irq);
+ if ((h == 0) || (h == 1)) {
+ tmp = h * 2;
+ } else {
+ tmp = (h - 2) * 2;
+ }
+ hwif->io_base = io[tmp];
+ hwif->ctl_port = io[tmp + 1] + 2;
+ hwif->irq = irq;
+ hwif->noprobe = 0;
+
+ if (vendor == PCI_VENDOR_ID_ARTOP) {
+ hwif->serialized = 1;
+ }
+
+ if (dma_enabled) {
+ if (!check_region(bmiba, 8)) {
+ hwif->chipset = ide_udma;
+ init_triton_dma(hwif, bmiba);
+ step_count++;
+ } else if (!check_region((bmiba + 0x08), 8)) {
+ if ((vendor == PCI_VENDOR_ID_PROMISE) &&
+ (!check_region(bmiba+16, 16))) {
+ request_region(bmiba+16, 16, "PDC20246");
+ }
+ hwif->chipset = ide_udma;
+ init_triton_dma(hwif, bmiba + 8);
+ step_count++;
} else {
- s_clks = ~stime >> 2;
- r_clks = ~stime;
+ continue;
}
- s_clks = (s_clks & 3) + 2;
- r_clks = (r_clks & 3) + 1;
- printk(" slave: sample_CLKs=%d, recovery_CLKs=%d\n",
- s_clks, r_clks);
}
}
- print_triton_drive_flags (0, time & 0xf);
- print_triton_drive_flags (1, (time >> 4) & 0xf);
-#endif /* DISPLAY_TRITON_TIMINGS */
}
-quit: if (rc) printk("ide: pcibios access failed - %s\n", pcibios_strerror(rc));
-}
-
-void ide_init_promise (byte bus, byte fn, ide_hwif_t *hwif0, ide_hwif_t *hwif1, unsigned short dma)
-{
- int rc;
- unsigned short pcicmd;
- unsigned int bmiba = 0;
-
- printk("ide: Enabling DMA for Promise Technology IDE Ultra-DMA 33 on PCI bus %d function %d, port 0x%04x\n", bus, fn, dma);
- if ((rc = pcibios_read_config_word(bus, fn, 0x04, &pcicmd)) || (pcicmd & 1) == 0 || (pcicmd & 4) == 0)
- goto abort;
- if ((rc = pcibios_read_config_dword(bus, fn, 0x20, &bmiba)))
- goto abort;
- bmiba &= 0xfff0; /* extract port base address */
- if (bmiba != dma || !bmiba)
- goto abort;
- hwif0->chipset = ide_promise_udma;
- hwif1->chipset = ide_promise_udma;
- init_triton_dma(hwif0, bmiba);
- init_triton_dma(hwif1, bmiba + 0x08);
- return;
-abort:
- printk(KERN_WARNING "ide: Promise/33 not configured correctly (BIOS)\n");
+ quit: if (rc) printk("ide: pcibios access failed - %s\n", pcibios_strerror(rc));
}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/cdrom/sbpcd.c linux/drivers/cdrom/sbpcd.c
--- linux.vanilla/drivers/cdrom/sbpcd.c Sun Jun 21 18:41:20 1998
+++ linux/drivers/cdrom/sbpcd.c Mon Dec 14 18:32:36 1998
@@ -4911,14 +4911,16 @@
msg(DBG_000, "sbp_data: beginning to read.\n");
p = D_S[d].sbp_buf + frame * CD_FRAMESIZE;
if (sbpro_type==1) OUT(CDo_sel_i_d,1);
- if (cmd_type==READ_M2)
+ if (cmd_type==READ_M2) {
if (do_16bit) insw(CDi_data, xa_head_buf, CD_XA_HEAD>>1);
else insb(CDi_data, xa_head_buf, CD_XA_HEAD);
+ }
if (do_16bit) insw(CDi_data, p, CD_FRAMESIZE>>1);
else insb(CDi_data, p, CD_FRAMESIZE);
- if (cmd_type==READ_M2)
+ if (cmd_type==READ_M2) {
if (do_16bit) insw(CDi_data, xa_tail_buf, CD_XA_TAIL>>1);
else insb(CDi_data, xa_tail_buf, CD_XA_TAIL);
+ }
D_S[d].sbp_current++;
if (sbpro_type==1) OUT(CDo_sel_i_d,0);
if (cmd_type==READ_M2)
@@ -5502,9 +5504,10 @@
cc_ReadStatus();
i=ResponseStatus(); /* returns orig. status or p_busy_new */
if (famT_drive) i=ResponseStatus(); /* returns orig. status or p_busy_new */
- if (i<0)
+ if (i<0) {
if (i!=-402)
msg(DBG_INF,"init: ResponseStatus returns %d.\n",i);
+ }
else
{
if (st_check)
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/Config.in linux/drivers/char/Config.in
--- linux.vanilla/drivers/char/Config.in Sun Dec 6 00:14:37 1998
+++ linux/drivers/char/Config.in Sun Dec 6 03:14:36 1998
@@ -5,6 +5,11 @@
comment 'Character devices'
tristate 'Standard/generic serial support' CONFIG_SERIAL
+if [ "$CONFIG_SERIAL" != "n" ]; then
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ bool ' PCI serial support' CONFIG_SERIAL_PCI
+ fi
+fi
bool 'Digiboard PC/Xx Support' CONFIG_DIGI
tristate 'Cyclades async mux support' CONFIG_CYCLADES
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/apm_bios.c linux/drivers/char/apm_bios.c
--- linux.vanilla/drivers/char/apm_bios.c Sun Dec 6 00:14:37 1998
+++ linux/drivers/char/apm_bios.c Fri Dec 11 20:35:53 1998
@@ -1167,11 +1167,11 @@
apm_bios_entry.offset = apm_bios_info.offset;
apm_bios_entry.segment = APM_CS;
set_base(gdt[APM_CS >> 3],
- 0xc0000000 + ((unsigned long)apm_bios_info.cseg << 4));
+ __PAGE_OFFSET + ((unsigned long)apm_bios_info.cseg << 4));
set_base(gdt[APM_CS_16 >> 3],
- 0xc0000000 + ((unsigned long)apm_bios_info.cseg_16 << 4));
+ __PAGE_OFFSET + ((unsigned long)apm_bios_info.cseg_16 << 4));
set_base(gdt[APM_DS >> 3],
- 0xc0000000 + ((unsigned long)apm_bios_info.dseg << 4));
+ __PAGE_OFFSET + ((unsigned long)apm_bios_info.dseg << 4));
if (apm_bios_info.version == 0x100) {
set_limit(gdt[APM_CS >> 3], 64 * 1024);
set_limit(gdt[APM_CS_16 >> 3], 64 * 1024);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/cyclades.c linux/drivers/char/cyclades.c
--- linux.vanilla/drivers/char/cyclades.c Sun Dec 6 00:14:37 1998
+++ linux/drivers/char/cyclades.c Fri Jan 29 14:26:15 1999
@@ -1,7 +1,7 @@
#define BLOCKMOVE
#define Z_WAKE
static char rcsid[] =
-"$Revision: 2.1.1.10 $$Date: 1998/11/12 16:08:23 $";
+"$Revision: 2.1.1.11 $$Date: 1998/12/30 18:58:47 $";
/*
* linux/drivers/char/cyclades.c
@@ -31,7 +31,11 @@
* void cleanup_module(void);
*
* $Log: cyclades.c,v $
- * Revision: 2.1.1.10 1998/11/12 16:08:23 ivan
+ * Revision 2.1.1.11 1998/12/30 18:58:47 ivan
+ * Changed access to PLX PCI bridge registers from I/O to MMIO, in
+ * order to make PLX9050-based boards work with certain motherboards.
+ *
+ * Revision 2.1.1.10 1998/11/12 16:08:23 ivan
* cy_close function now resets (correctly) the tty->closing flag;
* JIFFIES_DIFF macro fixed.
*
@@ -4707,7 +4711,6 @@
{
#ifdef CONFIG_PCI
unsigned char cyy_bus, cyy_dev_fn, cyy_rev_id;
- unsigned long pci_intr_ctrl;
unsigned char cy_pci_irq;
uclong cy_pci_addr0, cy_pci_addr1, cy_pci_addr2;
unsigned short i,j,cy_pci_nchan, plx_ver;
@@ -4761,7 +4764,7 @@
printk("Cyclom-Y/PCI:found winaddr=0x%lx ioaddr=0x%lx\n",
(ulong)cy_pci_addr2, (ulong)cy_pci_addr1);
#endif
- cy_pci_addr1 &= PCI_BASE_ADDRESS_IO_MASK;
+ cy_pci_addr0 &= PCI_BASE_ADDRESS_MEM_MASK;
cy_pci_addr2 &= PCI_BASE_ADDRESS_MEM_MASK;
#if defined(__alpha__)
@@ -4778,6 +4781,7 @@
continue;
}
#else
+ cy_pci_addr0 = (ulong) ioremap(cy_pci_addr0, CyPCI_Yctl);
if ((ulong)cy_pci_addr2 >= 0x100000) /* above 1M? */
cy_pci_addr2 = (ulong) ioremap(cy_pci_addr2, CyPCI_Ywin);
#endif
@@ -4827,7 +4831,7 @@
/* set cy_card */
cy_card[j].base_addr = (ulong)cy_pci_addr2;
- cy_card[j].ctl_addr = 0;
+ cy_card[j].ctl_addr = (ulong)cy_pci_addr0;
cy_card[j].irq = (int) cy_pci_irq;
cy_card[j].bus_index = 1;
cy_card[j].first_line = cy_next_channel;
@@ -4839,20 +4843,16 @@
switch (plx_ver) {
case PLX_9050:
- outw(inw(cy_pci_addr1+0x4c)|0x0040,cy_pci_addr1+0x4c);
- pci_intr_ctrl = (unsigned long)
- (inw(cy_pci_addr1+0x4c)
- | inw(cy_pci_addr1+0x4e)<<16);
+ cy_writew(cy_pci_addr0+0x4c,
+ cy_readw(cy_pci_addr0+0x4c)|0x0040);
break;
case PLX_9060:
case PLX_9080:
default: /* Old boards, use PLX_9060 */
- outw(inw(cy_pci_addr1+0x68)|0x0900,cy_pci_addr1+0x68);
- pci_intr_ctrl = (unsigned long)
- (inw(cy_pci_addr1+0x68)
- | inw(cy_pci_addr1+0x6a)<<16);
+ cy_writew(cy_pci_addr0+0x68,
+ cy_readw(cy_pci_addr0+0x68)|0x0900);
break;
}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/keyboard.c linux/drivers/char/keyboard.c
--- linux.vanilla/drivers/char/keyboard.c Sun Jun 21 18:41:10 1998
+++ linux/drivers/char/keyboard.c Sun Dec 6 03:37:59 1998
@@ -374,8 +374,13 @@
mark_bh(CONSOLE_BH);
add_keyboard_randomness(scancode);
- 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;
if ((raw_mode = (kbd->kbdmode == VC_RAW))) {
put_queue(scancode);
/* we do not return yet, because we want to maintain
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/random.c linux/drivers/char/random.c
--- linux.vanilla/drivers/char/random.c Sun Dec 6 00:14:37 1998
+++ linux/drivers/char/random.c Tue Dec 29 15:06:38 1998
@@ -1004,7 +1004,17 @@
buf += i;
add_timer_randomness(r, &extract_timer_state, nbytes);
if (to_user && need_resched)
+ {
+ if(current->signal & ~current->blocked)
+ {
+ if(nbytes==0)
+ ret = -ERESTARTSYS;
+ else
+ ret -= nbytes;
+ break;
+ }
schedule();
+ }
}
/* Wipe data from memory */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/serial.c linux/drivers/char/serial.c
--- linux.vanilla/drivers/char/serial.c Sun Jun 21 18:41:10 1998
+++ linux/drivers/char/serial.c Sun Dec 27 20:46:14 1998
@@ -19,6 +19,9 @@
* flags INPCK, BRKINT, PARMRK, IGNPAR and IGNBRK.
* Bernd Anhäupl 05/17/96.
*
+ * Added Support for PCI serial boards which contain 16x50 Chips
+ * 31.10.1998 Henning P. Schmiedehausen
+ *
* This module exports the following rs232 io functions:
*
* int rs_init(void);
@@ -43,13 +46,18 @@
#include
#include
+#ifdef CONFIG_SERIAL_PCI
+#include
+#include
+#endif
+
#include
#include
#include
#include
static char *serial_name = "Serial driver";
-static char *serial_version = "4.13";
+static char *serial_version = "4.13p1";
DECLARE_TASK_QUEUE(tq_serial);
@@ -83,6 +91,10 @@
#undef SERIAL_DEBUG_OPEN
#undef SERIAL_DEBUG_FLOW
+#ifdef CONFIG_SERIAL_PCI
+# undef SERIAL_DEBUG_PCI
+#endif
+
#define RS_STROBE_TIME (10*HZ)
#define RS_ISR_PASS_LIMIT 256
@@ -121,6 +133,14 @@
*/
#define BASE_BAUD ( 1843200 / 16 )
+/*
+ * 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 )
+
/* Standard COM flags (except for COM4, because of the 8514 problem) */
#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST )
#define STD_COM4_FLAGS ASYNC_BOOT_AUTOCONF
@@ -130,6 +150,29 @@
#define BOCA_FLAGS 0
#define HUB6_FLAGS 0
+#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 */
+
+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
+
/*
* The following define the access methods for the HUB6 card. All
* access is through two ports for all 24 possible chips. The card is
@@ -202,10 +245,42 @@
{ 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,4) }, /* ttyS42 */
{ 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,5) }, /* ttyS43 */
#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
};
#define NR_PORTS (sizeof(rs_table)/sizeof(struct async_struct))
+#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
+
static struct tty_struct *serial_table[NR_PORTS];
static struct termios *serial_termios[NR_PORTS];
static struct termios *serial_termios_locked[NR_PORTS];
@@ -1731,6 +1806,26 @@
/*
+ * 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);
+}
+
+/*
* This routine sends a break character out the serial port.
*/
static void send_break( struct async_struct * info, int duration)
@@ -1922,6 +2017,20 @@
}
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;
case TCSBRK: /* SVID version: non-zero arg --> no break */
retval = tty_check_change(tty);
if (retval)
@@ -2478,6 +2587,10 @@
static void show_serial_version(void)
{
printk(KERN_INFO "%s version %s with", serial_name, serial_version);
+#ifdef CONFIG_SERIAL_PCI
+ printk(" PCI");
+#define SERIAL_OPT
+#endif
#ifdef CONFIG_HUB6
printk(" HUB-6");
#define SERIAL_OPT
@@ -2712,6 +2825,73 @@
restore_flags(flags);
}
+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);
+}
+
int register_serial(struct serial_struct *req);
void unregister_serial(int line);
@@ -2722,9 +2902,212 @@
#include
};
+#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 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 */
+
/*
* The serial driver boot-time initialization code!
*/
+
int rs_init(void)
{
int i;
@@ -2744,6 +3127,9 @@
}
show_serial_version();
+#ifdef CONFIG_SERIAL_PCI
+ probe_serial_pci();
+#endif
/* Initialize the tty_driver structure */
@@ -2795,67 +3181,15 @@
panic("Couldn't register callout driver\n");
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);
+ };
+
register_symtab(&serial_syms);
return 0;
}
+
+
/*
* register_serial and unregister_serial allows for serial ports to be
* configured at run-time, to support PCMCIA modems.
@@ -2898,20 +3232,9 @@
printk("register_serial(): autoconfig failed\n");
return -1;
}
- printk(KERN_INFO "tty%02d at 0x%04x (irq = %d)", info->line,
+ printk(KERN_INFO "ttyS%02d at 0x%04x (irq = %d)", info->line,
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);
restore_flags(flags);
return info->line;
}
@@ -2926,7 +3249,7 @@
if (info->tty)
tty_hangup(info->tty);
info->type = PORT_UNKNOWN;
- printk(KERN_INFO "tty%02d unloaded\n", info->line);
+ printk(KERN_INFO "ttyS%02d unloaded\n", info->line);
restore_flags(flags);
}
@@ -2960,6 +3283,18 @@
if (rs_table[i].type != PORT_UNKNOWN)
release_region(rs_table[i].port, 8);
}
+
+#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
+
if (tmp_buf) {
free_page((unsigned long) tmp_buf);
tmp_buf = NULL;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/tty_io.c linux/drivers/char/tty_io.c
--- linux.vanilla/drivers/char/tty_io.c Sun Dec 6 00:14:37 1998
+++ linux/drivers/char/tty_io.c Sun Dec 6 03:37:07 1998
@@ -964,7 +964,13 @@
* Failures after this point use release_mem to clean up, so
* there's no need to null out the local pointers.
*/
- 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. */
+
if (!*tp_loc)
*tp_loc = tp;
if (!*ltp_loc)
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/isdn_net.c linux/drivers/isdn/isdn_net.c
--- linux.vanilla/drivers/isdn/isdn_net.c Sun Dec 6 00:14:39 1998
+++ linux/drivers/isdn/isdn_net.c Tue Mar 2 00:40:09 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 $
* Linux ISDN subsystem, network interfaces and related functions (linklevel).
*
@@ -21,6 +21,9 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_net.c,v $
+ * Revision 1.48.2.28 1998/11/27 15:38:12 paul
+ * Also huptimeout with dialmode == manual
+ *
* Revision 1.48.2.27 1998/11/05 22:11:53 fritz
* Changed mail-address.
*
@@ -350,11 +353,11 @@
static int isdn_net_xmit(struct device *, isdn_net_local *, struct sk_buff *);
static void dev_purge_queues(struct device *dev); /* move this to net/core/dev.c */
-char *isdn_net_revision = "$Revision: 1.48.2.27 $";
+char *isdn_net_revision = "$Revision: 1.48.2.28 $";
- /*
- * Code for raw-networking over ISDN
- */
+/*
+ * Code for raw-networking over ISDN
+ */
static void
isdn_net_unreachable(struct device *dev, struct sk_buff *skb, char *reason)
@@ -362,7 +365,6 @@
int i;
if(skb != NULL) {
-
u_short proto = ntohs(skb->protocol);
printk(KERN_DEBUG "isdn_net: %s: %s, send ICMP %s\n",
@@ -538,13 +540,14 @@
if ((l->flags & ISDN_NET_CONNECTED) && (!l->dialstate)) {
anymore = 1;
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))
if (l->hupflags & ISDN_MANCHARGE &&
l->hupflags & ISDN_CHARGEHUP) {
while (jiffies - l->chargetime > l->chargeint)
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/isdn_ppp.c linux/drivers/isdn/isdn_ppp.c
--- linux.vanilla/drivers/isdn/isdn_ppp.c Sun Dec 6 00:14:39 1998
+++ linux/drivers/isdn/isdn_ppp.c Tue Mar 2 00:40:09 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 $
*
* Linux ISDN subsystem, functions for synchronous PPP (linklevel).
*
@@ -19,6 +19,9 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_ppp.c,v $
+ * Revision 1.28.2.3 1998/12/30 17:49:00 paul
+ * fixed syncPPP callback out
+ *
* Revision 1.28.2.2 1998/11/03 14:31:23 fritz
* Reduced stack usage in various functions.
* Adapted statemachine to work with certified HiSax.
@@ -181,7 +184,7 @@
static void isdn_ppp_free_mpqueue(isdn_net_dev *);
#endif
-char *isdn_ppp_revision = "$Revision: 1.28.2.2 $";
+char *isdn_ppp_revision = "$Revision: 1.28.2.3 $";
static struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS];
static struct isdn_ppp_compressor *ipc_head = NULL;
@@ -303,7 +306,8 @@
}
} else {
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)
break;
}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/3c59x.c linux/drivers/net/3c59x.c
--- linux.vanilla/drivers/net/3c59x.c Sun Dec 6 00:14:39 1998
+++ linux/drivers/net/3c59x.c Sun Dec 6 19:28:57 1998
@@ -15,18 +15,19 @@
*/
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";
/* "Knobs" that adjust features and parameters. */
/* Set the copy breakpoint for the copy-only-tiny-frames scheme.
Setting to > 1512 effectively disables this feature. */
-static const rx_copybreak = 200;
+static const int rx_copybreak = 200;
/* Allow setting MTU to a larger size, bypassing the normal ethernet setup. */
-static const mtu = 1500;
+static const int mtu = 1500;
/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
static int max_interrupt_work = 20;
/* Put out somewhat more debugging messages. (0: no msg, 1 minimal .. 6). */
+#define vortex_debug debug
#ifdef VORTEX_DEBUG
static int vortex_debug = VORTEX_DEBUG;
#else
@@ -37,15 +38,6 @@
debugging. */
static int rx_nocopy = 0, rx_copy = 0, queued_packet = 0, rx_csumhits;
-/* 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
-
/* A few values that may be tweaked. */
/* Time in jiffies before concluding the transmitter is hung. */
#define TX_TIMEOUT ((400*HZ)/1000)
@@ -56,12 +48,12 @@
#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/
#include
+#include
#ifdef MODULE
#ifdef MODVERSIONS
#include
#endif
#include
-#include
#else
#define MOD_INC_USE_COUNT
#define MOD_DEC_USE_COUNT
@@ -70,68 +62,61 @@
#include
#include
#include
-#include
+#include
#include
#include
#include
#include
#include
#include
+#include
+#include
+#include
+#if LINUX_VERSION_CODE < 0x20155 || defined(CARDBUS)
#include
-#include
+#endif
#include /* For NR_IRQS only. */
#include
#include
-#include
-#include
-#include
-
-/* Kernel compatibility defines, common to David Hind's PCMCIA package.
+/* Kernel compatibility defines, some common to David Hinds' PCMCIA package.
This is only in the support-all-kernels source code. */
-#ifndef LINUX_VERSION_CODE
-#include /* 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
-#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))
-#if (LINUX_VERSION_CODE >= 0x10344)
-#define NEW_MULTICAST
#include
+
+#if (LINUX_VERSION_CODE >= 0x20100)
+char kernel_version[] = UTS_RELEASE;
#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
#endif
-
#if LINUX_VERSION_CODE < 0x20138
#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);
#endif
-#if defined(MODULE) && (LINUX_VERSION_CODE >= 0x20115)
+
+#if defined(MODULE) && LINUX_VERSION_CODE > 0x20115
MODULE_AUTHOR("Donald Becker ");
MODULE_DESCRIPTION("3Com 3c590/3c900 series Vortex/Boomerang driver");
MODULE_PARM(debug, "i");
@@ -141,7 +126,7 @@
MODULE_PARM(max_interrupt_work, "i");
MODULE_PARM(compaq_ioaddr, "i");
MODULE_PARM(compaq_irq, "i");
-MODULE_PARM(compaq_prod_id, "i");
+MODULE_PARM(compaq_device_id, "i");
#endif
/* Operational parameter that usually are not changed. */
@@ -153,35 +138,11 @@
#define VORTEX_TOTAL_SIZE 0x20
#define BOOMERANG_TOTAL_SIZE 0x40
-#ifdef HAVE_DEVLIST
-struct netdev_entry tc59x_drv =
-{"Vortex", vortex_pci_probe, VORTEX_TOTAL_SIZE, NULL};
-#endif
-
/* Set iff a MII transceiver on any interface requires mdio preamble.
This only set with the original DP83840 on older 3c905 boards, so the extra
code size of a per-interface flag is not worthwhile. */
static char mii_preamble_required = 0;
-/* 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 */
-};
-
/*
Theory of Operation
@@ -192,17 +153,19 @@
versions of the FastEtherLink cards. The supported product IDs are
3c590, 3c592, 3c595, 3c597, 3c900, 3c905
-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
cesdis.gsfc.nasa.gov:/pub/linux/drivers/3c515.html
II. Board-specific settings
PCI bus devices are configured by the system at boot time, so no jumpers
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.
III. Driver operation
@@ -213,7 +176,7 @@
The 3c900 "Boomerang" series uses a full-bus-master interface with separate
lists of transmit and receive descriptors, similar to the AMD LANCE/PCnet,
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
revisions.
One extension that is advertised in a very large font is that the adapters
@@ -231,7 +194,7 @@
single frame.
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
full-sized skbuffs as receive buffers. The value RX_COPYBREAK is used as
the copying breakpoint: it is chosen to trade-off the memory wasted by
passing the full-sized skbuff to the queue layer for all frames vs. the
@@ -257,7 +220,66 @@
limit of 4K.
*/
-#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. */
+};
/* Operational definitions.
These are not used by other compilation units and thus are not
@@ -286,7 +308,7 @@
SetStatusEnb = 15<<11, SetRxFilter = 16<<11, SetRxThreshold = 17<<11,
SetTxThreshold = 18<<11, SetTxStart = 19<<11,
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,};
/* The SetRxFilter command accepts the following classes: */
enum RxFilter {
@@ -326,6 +348,9 @@
NodeAddr01=10, NodeAddr23=11, NodeAddr45=12,
DriverTune=13, Checksum=15};
+enum Window2 { /* Window 2. */
+ Wn2_ResetOptions=12,
+};
enum Window3 { /* Window 3: MAC/config bits. */
Wn3_Config=0, Wn3_MAC_Ctrl=6, Wn3_Options=8,
};
@@ -393,37 +418,37 @@
enum ChipCaps { CapBusMaster=0x20 };
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. */
struct boom_rx_desc rx_ring[RX_RING_SIZE];
struct boom_tx_desc tx_ring[TX_RING_SIZE];
/* The addresses of transmit- and receive-in-place skbuffs. */
struct sk_buff* rx_skbuff[RX_RING_SIZE];
struct sk_buff* tx_skbuff[TX_RING_SIZE];
+ struct device *next_module;
+ void *priv_addr;
unsigned int cur_rx, cur_tx; /* The next free ring entry */
unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */
- struct enet_statistics stats;
+ struct net_device_stats stats;
struct sk_buff *tx_skb; /* Packet being eaten by bus master ctrl. */
/* 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;
/* The remainder are related to chip state, mostly media selection. */
- int in_interrupt;
+ unsigned long in_interrupt;
struct timer_list timer; /* Media selection timer. */
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;
u16 status_enable;
+ u16 intr_enable;
u16 available_media; /* From Wn3_Options. */
u16 capabilities, info1, info2; /* Various, from EEPROM. */
u16 advertising; /* NWay media advertisement */
@@ -458,61 +483,39 @@
{ "Default", 0, 0xFF, XCVR_10baseT, 10000},
};
-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[]);
#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);
static void vortex_timer(unsigned long arg);
static int vortex_start_xmit(struct sk_buff *skb, struct device *dev);
static int boomerang_start_xmit(struct sk_buff *skb, struct device *dev);
static int vortex_rx(struct device *dev);
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);
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);
static void set_rx_mode(struct device *dev);
-#ifdef HAVE_PRIVATE_IOCTL
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
-/* 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.
-*/
/* 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};
/* A list of all installed Vortex devices, for removing the driver module. */
static struct device *root_vortex_dev = NULL;
#ifdef MODULE
+#ifndef CARDBUS
/* Variables to work-around the Compaq PCI BIOS32 problem. */
static int compaq_ioaddr = 0, compaq_irq = 0, compaq_device_id = 0x5900;
-
-static int debug = -1;
+#endif
#ifdef CARDBUS
@@ -520,19 +523,38 @@
static dev_node_t *vortex_attach(dev_locator_t *loc)
{
- u16 dev_id;
+ u16 dev_id, vendor_id;
u32 io;
u8 bus, devfn, irq;
struct device *dev;
+ int chip_idx;
if (loc->bus != LOC_PCI) return NULL;
bus = loc->b.pci.bus; devfn = loc->b.pci.devfn;
- printk(KERN_INFO "vortex_attach(bus %d, function %d)\n", bus, devfn);
pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, &io);
pcibios_read_config_byte(bus, devfn, PCI_INTERRUPT_LINE, &irq);
+ pcibios_read_config_word(bus, devfn, PCI_VENDOR_ID, &vendor_id);
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);
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);
if (dev) {
dev_node_t *node = kmalloc(sizeof(dev_node_t), GFP_KERNEL);
strcpy(node->dev_name, dev->name);
@@ -554,61 +576,49 @@
}
if (*devp) {
struct device *dev = *devp;
+ struct vortex_private *vp = dev->priv;
if (dev->flags & IFF_UP)
vortex_close(dev);
dev->flags &= ~(IFF_UP|IFF_RUNNING);
unregister_netdev(dev);
+ if (vp->cb_fn_base) iounmap(vp->cb_fn_base);
kfree(dev);
*devp = *next;
+ kfree(vp);
kfree(node);
MOD_DEC_USE_COUNT;
}
}
struct driver_operations vortex_ops = {
- "3c59x_cb", vortex_attach, NULL, NULL, vortex_detach
+ "3c575_cb", vortex_attach, NULL, NULL, vortex_detach
};
#endif /* Cardbus support */
-int
-init_module(void)
+int init_module(void)
{
- if (debug >= 0)
- vortex_debug = debug;
if (vortex_debug)
- printk(version);
-
- root_vortex_dev = NULL;
+ printk(KERN_INFO "%s", version);
#ifdef CARDBUS
register_driver(&vortex_ops);
return 0;
#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);
#endif
}
#else
int tc59x_probe(struct device *dev)
{
- 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);
}
#endif /* not MODULE */
-static int vortex_scan(struct device *dev)
+#ifndef CARDBUS
+static int vortex_scan(struct device *dev, struct pci_id_info pci_tbl[])
{
int cards_found = 0;
@@ -623,25 +633,30 @@
unsigned char pci_bus, pci_device_fn;
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;
long ioaddr;
- 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)
!= 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_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;
+
{
#if LINUX_VERSION_CODE >= 0x20155
struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn);
- ioaddr = pdev->base_address[0];
+ ioaddr = pdev->base_address[0] & ~3;
irq = pdev->irq;
#else
u32 pci_ioaddr;
@@ -650,15 +665,28 @@
PCI_INTERRUPT_LINE, &pci_irq_line);
pcibios_read_config_dword(pci_bus, pci_device_fn,
PCI_BASE_ADDRESS_0, &pci_ioaddr);
- ioaddr = pci_ioaddr;
+ ioaddr = pci_ioaddr & ~3;;
irq = pci_irq_line;
#endif
}
- /* Remove I/O space marker in bit 0. */
- ioaddr &= ~3;
- 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);
+ }
if (ioaddr == 0) {
printk(KERN_WARNING " A 3Com network adapter has been found, "
@@ -668,34 +696,31 @@
continue;
}
- if (check_region(ioaddr, VORTEX_TOTAL_SIZE))
+ if (check_region(ioaddr, pci_tbl[chip_idx].io_size))
continue;
/* Activate the card. */
+ 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);
+ 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);
}
- 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);
if (dev) {
- struct vortex_private *vp = (struct vortex_private *)dev->priv;
/* Get and check the latency values. On the 3c590 series
the latency timer must be set to the maximum value to avoid
data corruption that occurs when the timer expires during
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;
pcibios_read_config_byte(pci_bus, pci_device_fn,
PCI_LATENCY_TIMER, &pci_latency);
@@ -715,7 +740,7 @@
/* Now check all slots of the EISA bus. */
if (EISA_bus) {
- static int ioaddr = 0x1000;
+ static long ioaddr = 0x1000;
for ( ; ioaddr < 0x9000; ioaddr += 0x1000) {
int device_id;
if (check_region(ioaddr, VORTEX_TOTAL_SIZE))
@@ -727,10 +752,8 @@
device_id = (inb(ioaddr + 0xC82)<<8) + inb(ioaddr + 0xC83);
if ((device_id & 0xFF00) != 0x5900)
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);
dev = 0;
cards_found++;
}
@@ -739,97 +762,58 @@
#ifdef MODULE
/* Special code to work-around the Compaq PCI BIOS32 problem. */
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++);
dev = 0;
}
#endif
- /* 3c515 cards are now supported by the 3c515.c driver. */
-
- return cards_found;
+ return cards_found ? 0 : -ENODEV;
}
+#endif /* ! Cardbus */
-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)
{
struct vortex_private *vp;
- const char *product_name;
- int board_index = 0;
+ int option;
+ unsigned int eeprom[0x40], checksum = 0; /* EEPROM contents */
+ int i;
- 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);
-#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);
- 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. */
dev->base_addr = ioaddr;
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;
- 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;
}
- ether_setup(dev);
+ memset(vp, 0, sizeof(*vp));
+ dev->priv = vp;
+
vp->next_module = root_vortex_dev;
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;
- 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;
+
if (option >= 0) {
vp->media_override = ((option & 7) == 2) ? 0 : option & 7;
vp->full_duplex = (option & 8) ? 1 : 0;
@@ -839,22 +823,11 @@
vp->full_duplex = 0;
vp->bus_master = 0;
}
+ if (card_idx < MAX_UNITS && full_duplex[card_idx] > 0)
+ vp->full_duplex = 1;
- 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;
/* Read the station address from the EEPROM. */
EL3WINDOW(0);
@@ -885,14 +858,30 @@
printk(" ***INVALID CHECKSUM %4.4x*** ", checksum);
for (i = 0; i < 3; i++)
- ether_addr[i] = htons(eeprom[i + 10]);
+ ((u16 *)dev->dev_addr)[i] = htons(eeprom[i + 10]);
for (i = 0; i < 6; i++)
printk("%c%2.2x", i ? ':' : ' ', dev->dev_addr[i]);
+#ifdef __sparc__
+ printk(", IRQ %s\n", __irq_itoa(dev->irq));
+#else
printk(", IRQ %d\n", dev->irq);
/* Tell them about an invalid IRQ. */
if (vortex_debug && (dev->irq <= 0 || dev->irq >= NR_IRQS))
printk(KERN_WARNING " *** Warning: IRQ %d is unlikely to work! ***\n",
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);
+ }
/* Extract our information from the EEPROM data. */
vp->info1 = eeprom[13];
@@ -918,7 +907,7 @@
config.u.ram_width ? "word" : "byte",
ram_split[config.u.ram_split],
config.u.autoselect ? "autoselect/" : "",
- config.u.xcvr ? "NWay Autonegotiation" :
+ config.u.xcvr > XCVR_ExtMII ? "" :
media_tbl[config.u.xcvr].name);
vp->default_media = config.u.xcvr;
vp->autoselect = config.u.autoselect;
@@ -931,22 +920,24 @@
} else
dev->if_port = vp->default_media;
- if (dev->if_port == XCVR_MII) {
+ if (dev->if_port == XCVR_MII || dev->if_port == XCVR_NWAY) {
int phy, phy_idx = 0;
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);
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++;
}
}
+ mii_preamble_required--;
if (phy_idx == 0) {
printk(KERN_WARNING" ***WARNING*** No MII transceivers found!\n");
vp->phys[0] = 24;
@@ -954,7 +945,7 @@
vp->advertising = mdio_read(ioaddr, vp->phys[0], 4);
if (vp->full_duplex) {
/* Only advertise the FD media types. */
- vp->advertising &= 0x015F;
+ vp->advertising &= ~0x02A0;
mdio_write(ioaddr, vp->phys[0], 4, vp->advertising);
}
}
@@ -968,30 +959,24 @@
}
/* 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);
/* The 3c59x-specific entries in the device structure. */
dev->open = &vortex_open;
dev->hard_start_xmit = &vortex_start_xmit;
dev->stop = &vortex_close;
dev->get_stats = &vortex_get_stats;
-#ifdef HAVE_PRIVATE_IOCTL
dev->do_ioctl = &vortex_ioctl;
-#endif
-#ifdef NEW_MULTICAST
dev->set_multicast_list = &set_rx_mode;
-#else
- dev->set_multicast_list = &set_multicast_list;
-#endif
- return 0;
+ return dev;
}
static int
vortex_open(struct device *dev)
{
- int ioaddr = dev->base_addr;
+ long ioaddr = dev->base_addr;
struct vortex_private *vp = (struct vortex_private *)dev->priv;
union wn3_config config;
int i;
@@ -1006,28 +991,31 @@
dev->name, vp->media_override,
media_tbl[vp->media_override].name);
dev->if_port = vp->media_override;
+ } else if (vp->autoselect && pci_tbl[vp->chip_id].drv_flags & HAS_NWAY) {
+ dev->if_port = XCVR_NWAY;
} else if (vp->autoselect) {
/* Find first available media type, starting with 100baseTx. */
dev->if_port = XCVR_100baseTx;
while (! (vp->available_media & media_tbl[dev->if_port].mask))
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);
} else
dev->if_port = vp->default_media;
+ 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;
config.u.xcvr = dev->if_port;
outl(config.i, ioaddr + Wn3_Config);
- if (dev->if_port == XCVR_MII) {
+ if (dev->if_port == XCVR_MII || dev->if_port == XCVR_NWAY) {
int mii_reg1, mii_reg5;
EL3WINDOW(4);
/* Read BMSR (reg1) only to clear old status. */
@@ -1067,20 +1055,10 @@
outw(SetStatusEnb | 0x00, ioaddr + EL3_CMD);
-#ifdef SA_SHIRQ
/* Use the now-standard shared IRQ implementation. */
if (request_irq(dev->irq, &vortex_interrupt, SA_SHIRQ, dev->name, dev)) {
return -EAGAIN;
}
-#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
if (vortex_debug > 1) {
EL3WINDOW(4);
@@ -1098,9 +1076,11 @@
if (dev->if_port == XCVR_10base2)
/* Start the thinnet transceiver. We should really wait 50ms...*/
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);
+ }
/* Switch to the stats window, and clear all stats by reading. */
outw(StatsDisable, ioaddr + EL3_CMD);
@@ -1127,22 +1107,23 @@
printk(KERN_DEBUG "%s: Filling in the Rx ring.\n", dev->name);
for (i = 0; i < RX_RING_SIZE; i++) {
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]));
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);
vp->rx_skbuff[i] = skb;
if (skb == NULL)
break; /* Bad news! */
skb->dev = dev; /* Mark as being used by this device. */
#if LINUX_VERSION_CODE >= 0x10300
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));
#else
vp->rx_ring[i].addr = virt_to_bus(skb->data);
#endif
}
- 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]));
outl(virt_to_bus(&vp->rx_ring[0]), ioaddr + UpListPtr);
}
if (vp->full_bus_master_tx) { /* Boomerang bus master Tx. */
@@ -1170,14 +1151,16 @@
(vp->full_bus_master_tx ? DownComplete : TxAvailable) |
(vp->full_bus_master_rx ? UpComplete : RxComplete) |
(vp->bus_master ? DMADone : 0);
+ vp->intr_enable = SetIntrEnb | IntLatch | TxAvailable | RxComplete |
+ StatsFull | HostError | TxComplete | IntReq
+ | (vp->bus_master ? DMADone : 0) | UpComplete | DownComplete;
outw(vp->status_enable, ioaddr + EL3_CMD);
/* Ack all pending events, and set active indicator mask. */
outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq,
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);
MOD_INC_USE_COUNT;
@@ -1186,24 +1169,23 @@
static void vortex_timer(unsigned long data)
{
-#ifdef AUTOMEDIA
struct device *dev = (struct device *)data;
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;
int ok = 0;
+ int media_status, mii_status, old_window;
if (vortex_debug > 1)
printk(KERN_DEBUG "%s: Media selection timer tick happened, %s.\n",
dev->name, media_tbl[dev->if_port].name);
- 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:
if (media_status & Media_LnkBeat) {
ok = 1;
if (vortex_debug > 1)
@@ -1212,27 +1194,40 @@
} else if (vortex_debug > 1)
printk(KERN_DEBUG "%s: Media %s is has no link beat, %x.\n",
dev->name, media_tbl[dev->if_port].name, media_status);
-
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) {
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;
+ }
}
+ break;
default: /* Other media types handled by Tx timeouts. */
if (vortex_debug > 1)
printk(KERN_DEBUG "%s: Media %s is has no indication, %x.\n",
dev->name, media_tbl[dev->if_port].name, media_status);
ok = 1;
- }
- if ( ! ok) {
+ }
+ if ( ! ok) {
union wn3_config config;
do {
@@ -1249,8 +1244,7 @@
printk(KERN_DEBUG "%s: Media selection failed, now trying "
"%s port.\n",
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);
}
outw((media_status & ~(Media_10TP|Media_SQE)) |
media_tbl[dev->if_port].media_bits, ioaddr + Wn4_Media);
@@ -1262,21 +1256,25 @@
outw(dev->if_port == XCVR_10base2 ? StartCoax : StopCoax,
ioaddr + EL3_CMD);
- }
- EL3WINDOW(old_window);
- } restore_flags(flags);
- if (vortex_debug > 1)
+ }
+ EL3WINDOW(old_window);
+ enable_irq(dev->irq);
+
+ if (vortex_debug > 2)
printk(KERN_DEBUG "%s: Media selection timer finished, %s.\n",
dev->name, media_tbl[dev->if_port].name);
-#endif /* AUTOMEDIA*/
+ if (next_tick) {
+ vp->timer.expires = RUN_AT(next_tick);
+ add_timer(&vp->timer);
+ }
return;
}
static void vortex_tx_timeout(struct device *dev)
{
struct vortex_private *vp = (struct vortex_private *)dev->priv;
- int ioaddr = dev->base_addr;
+ long ioaddr = dev->base_addr;
int j;
printk(KERN_ERR "%s: transmit timed out, tx_status %2.2x status %4.4x.\n",
@@ -1290,7 +1288,7 @@
printk(KERN_ERR "%s: Interrupt posted but not delivered --"
" IRQ blocked by another device?\n", dev->name);
/* 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);
}
outw(TxReset, ioaddr + EL3_CMD);
for (j = 200; j >= 0 ; j--)
@@ -1309,8 +1307,8 @@
for (i = 0; i < TX_RING_SIZE; i++) {
printk(KERN_DEBUG " %d: @%p length %8.8x status %8.8x\n", i,
&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));
}
}
#endif
@@ -1347,7 +1345,7 @@
vortex_error(struct device *dev, int status)
{
struct vortex_private *vp = (struct vortex_private *)dev->priv;
- int ioaddr = dev->base_addr;
+ long ioaddr = dev->base_addr;
int do_tx_reset = 0;
int i;
@@ -1387,8 +1385,10 @@
DoneDidThat++;
}
}
- 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);
+ }
if (status & HostError) {
u16 fifo_diag;
EL3WINDOW(4);
@@ -1434,7 +1434,7 @@
vortex_start_xmit(struct sk_buff *skb, struct device *dev)
{
struct vortex_private *vp = (struct vortex_private *)dev->priv;
- int ioaddr = dev->base_addr;
+ long ioaddr = dev->base_addr;
if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
if (jiffies - dev->trans_start >= TX_TIMEOUT)
@@ -1444,7 +1444,6 @@
/* Put out the doubleword header... */
outl(skb->len, ioaddr + TX_FIFO);
-#ifdef VORTEX_BUS_MASTER
if (vp->bus_master) {
/* Set the bus-master controller to transfer the packet. */
outl(virt_to_bus(skb->data), ioaddr + Wn7_MasterAddr);
@@ -1462,16 +1461,6 @@
/* Interrupt us when the FIFO has room for max-sized packet. */
outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD);
}
-#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 */
dev->trans_start = jiffies;
@@ -1506,7 +1495,7 @@
boomerang_start_xmit(struct sk_buff *skb, struct device *dev)
{
struct vortex_private *vp = (struct vortex_private *)dev->priv;
- int ioaddr = dev->base_addr;
+ long ioaddr = dev->base_addr;
if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
if (jiffies - dev->trans_start >= TX_TIMEOUT)
@@ -1528,13 +1517,12 @@
printk(KERN_WARNING "%s: Tx Ring full, refusing to send buffer.\n",
dev->name);
return 1;
- }
- /* end change 06/25/97 M. Sievers */
+ }
vp->tx_skbuff[entry] = skb;
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);
save_flags(flags);
cli();
@@ -1543,7 +1531,7 @@
for (i = 600; i >= 0 ; i--)
if ( (inw(ioaddr + EL3_STATUS) & CmdInProgress) == 0)
break;
- prev_entry->next = virt_to_bus(&vp->tx_ring[entry]);
+ prev_entry->next = cpu_to_le32(virt_to_bus(&vp->tx_ring[entry]));
if (inl(ioaddr + DownListPtr) == 0) {
outl(virt_to_bus(&vp->tx_ring[entry]), ioaddr + DownListPtr);
queued_packet++;
@@ -1555,7 +1543,7 @@
if (vp->cur_tx - vp->dirty_tx > TX_RING_SIZE - 1)
vp->tx_full = 1;
else { /* Clear previous interrupt enable. */
- prev_entry->status &= ~TxIntrUploaded;
+ prev_entry->status &= cpu_to_le32(~TxIntrUploaded);
clear_bit(0, (void*)&dev->tbusy);
}
dev->trans_start = jiffies;
@@ -1565,28 +1553,33 @@
/* The interrupt handler does all of the Rx thread work and cleans up
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)
{
-#ifdef SA_SHIRQ /* Use the now-standard shared IRQ implementation. */
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;
int work_done = max_interrupt_work;
- 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) {
printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name);
return;
}
+ dev->interrupt = 1;
+#endif
dev->interrupt = 1;
ioaddr = dev->base_addr;
latency = inb(ioaddr + Timer);
-
status = inw(ioaddr + EL3_STATUS);
if (vortex_debug > 4)
@@ -1635,17 +1628,23 @@
mark_bh(NET_BH);
}
}
-#ifdef VORTEX_BUS_MASTER
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);
+ }
}
-#endif
/* 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;
vortex_error(dev, status);
+ }
if (--work_done < 0) {
if ((status & (0x7fe - (UpComplete | DownComplete))) == 0) {
@@ -1658,13 +1657,14 @@
/* Disable all pending interrupts. */
outw(SetStatusEnb | ((~status) & 0x7FE), ioaddr + EL3_CMD);
outw(AckIntr | 0x7FF, ioaddr + EL3_CMD);
- /* Set a timer to reenable interrupts. */
-
+ /* The timer will reenable interrupts. */
break;
}
}
/* Acknowledge the IRQ. */
outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD);
+ if (vp->cb_fn_base) /* The PCMCIA people are idiots. */
+ writel(0x8000, vp->cb_fn_base + 4);
} while ((status = inw(ioaddr + EL3_STATUS)) & (IntLatch | RxComplete));
@@ -1672,16 +1672,18 @@
printk(KERN_DEBUG "%s: exiting interrupt, status %4.4x.\n",
dev->name, status);
+#if defined(__i386__)
+ clear_bit(0, (void*)&dev->interrupt);
+#else
dev->interrupt = 0;
- clear_bit(0, (void*)&vp->in_interrupt);
+#endif
return;
}
-static int
-vortex_rx(struct device *dev)
+static int vortex_rx(struct device *dev)
{
struct vortex_private *vp = (struct vortex_private *)dev->priv;
- int ioaddr = dev->base_addr;
+ long ioaddr = dev->base_addr;
int i;
short rx_status;
@@ -1704,25 +1706,28 @@
int pkt_len = rx_status & 0x1fff;
struct sk_buff *skb;
- skb = DEV_ALLOC_SKB(pkt_len + 5);
+ skb = dev_alloc_skb(pkt_len + 5);
if (vortex_debug > 4)
printk(KERN_DEBUG "Receiving packet size %d status %4.4x.\n",
pkt_len, rx_status);
if (skb != NULL) {
skb->dev = dev;
-#if LINUX_VERSION_CODE >= 0x10300
skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
/* '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);
+ }
outw(RxDiscard, ioaddr + EL3_CMD); /* Pop top Rx packet. */
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 */
netif_rx(skb);
dev->last_rx = jiffies;
vp->stats.rx_packets++;
@@ -1751,7 +1756,7 @@
{
struct vortex_private *vp = (struct vortex_private *)dev->priv;
int entry = vp->cur_rx % RX_RING_SIZE;
- int ioaddr = dev->base_addr;
+ long ioaddr = dev->base_addr;
int rx_status;
int rx_work_limit = vp->dirty_rx + RX_RING_SIZE - vp->cur_rx;
@@ -1759,8 +1764,9 @@
printk(KERN_DEBUG " In boomerang_rx(), status %4.4x, rx_status "
"%4.4x.\n",
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;
if (rx_status & RxDError) { /* Error, update stats. */
unsigned char rx_error = rx_status >> 16;
if (vortex_debug > 2)
@@ -1783,41 +1789,28 @@
/* Check if the packet is long enough to just accept without
copying to a properly sized skbuff. */
if (pkt_len < rx_copybreak
- && (skb = DEV_ALLOC_SKB(pkt_len + 2)) != 0) {
+ && (skb = dev_alloc_skb(pkt_len + 2)) != 0) {
skb->dev = dev;
-#if LINUX_VERSION_CODE >= 0x10300
skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
/* 'skb_put()' points to the start of sk_buff data area. */
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)),
pkt_len);
-#else
- memcpy(skb->data, bus_to_virt(vp->rx_ring[entry].addr), pkt_len);
- skb->len = pkt_len;
-#endif
rx_copy++;
- } else{
+ } else {
void *temp;
/* Pass up the skbuff already on the Rx ring. */
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;
- }
vp->rx_skbuff[entry] = NULL;
-#if LINUX_VERSION_CODE >= 0x10300
temp = skb_put(skb, pkt_len);
-#else
- temp = skb->data;
-#endif
/* 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)
printk(KERN_ERR "%s: Warning -- the skbuff addresses do not match"
" 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);
rx_nocopy++;
}
-#if LINUX_VERSION_CODE > 0x10300
skb->protocol = eth_type_trans(skb, dev);
{ /* Use hardware checksum info. */
int csum_bits = rx_status & 0xee000000;
@@ -1828,9 +1821,6 @@
rx_csumhits++;
}
}
-#else
- skb->len = pkt_len;
-#endif
netif_rx(skb);
dev->last_rx = jiffies;
vp->stats.rx_packets++;
@@ -1842,29 +1832,17 @@
struct sk_buff *skb;
entry = vp->dirty_rx % RX_RING_SIZE;
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)
break; /* Bad news! */
- }
skb->dev = dev; /* Mark as being used by this device. */
-#if LINUX_VERSION_CODE > 0x10300
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));
vp->rx_skbuff[entry] = skb;
}
vp->rx_ring[entry].status = 0; /* Clear complete bit. */
outw(UpUnstall, ioaddr + EL3_CMD);
}
-
- if (vp->dirty_rx >= RX_RING_SIZE ) {
- vp->cur_rx -= RX_RING_SIZE;
- vp->dirty_rx -= RX_RING_SIZE;
- }
-
return 0;
}
@@ -1872,7 +1850,7 @@
vortex_close(struct device *dev)
{
struct vortex_private *vp = (struct vortex_private *)dev->priv;
- int ioaddr = dev->base_addr;
+ long ioaddr = dev->base_addr;
int i;
dev->start = 0;
@@ -1899,12 +1877,7 @@
/* Turn off thinnet power. Green! */
outw(StopCoax, ioaddr + EL3_CMD);
-#ifdef SA_SHIRQ
free_irq(dev->irq, dev);
-#else
- free_irq(dev->irq);
- irq2dev_map[dev->irq] = 0;
-#endif
outw(SetIntrEnb | 0x0000, ioaddr + EL3_CMD);
@@ -1934,8 +1907,7 @@
return 0;
}
-static struct enet_statistics *
-vortex_get_stats(struct device *dev)
+static struct net_device_stats *vortex_get_stats(struct device *dev)
{
struct vortex_private *vp = (struct vortex_private *)dev->priv;
unsigned long flags;
@@ -1956,7 +1928,7 @@
table. This is done by checking that the ASM (!) code generated uses
atomic updates with '+='.
*/
-static void update_stats(int ioaddr, struct device *dev)
+static void update_stats(long ioaddr, struct device *dev)
{
struct vortex_private *vp = (struct vortex_private *)dev->priv;
@@ -1987,20 +1959,14 @@
return;
}
-#ifdef HAVE_PRIVATE_IOCTL
static int vortex_ioctl(struct device *dev, struct ifreq *rq, int cmd)
{
struct vortex_private *vp = (struct vortex_private *)dev->priv;
- int ioaddr = dev->base_addr;
+ long ioaddr = dev->base_addr;
u16 *data = (u16 *)&rq->ifr_data;
int phy = vp->phys[0] & 0x1f;
- 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) {
case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */
data[0] = phy;
case SIOCDEVPRIVATE+1: /* Read the specified MII register. */
@@ -2010,22 +1976,20 @@
case SIOCDEVPRIVATE+2: /* Write the specified MII register */
if (!suser())
return -EPERM;
+ EL3WINDOW(4);
mdio_write(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2]);
return 0;
default:
return -EOPNOTSUPP;
}
}
-#endif /* HAVE_PRIVATE_IOCTL */
-/* 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
multicast setting is to receive all multicast frames. At least
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)
{
- int ioaddr = dev->base_addr;
+ long ioaddr = dev->base_addr;
int new_mode;
if (dev->flags & IFF_PROMISC) {
@@ -2039,14 +2003,6 @@
outw(new_mode, ioaddr + EL3_CMD);
}
-#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
/* MII transceiver control section.
@@ -2057,7 +2013,7 @@
/* The maximum data clock rate is 2.5 Mhz. The minimum timing is usually
met by back-to-back PCI I/O cycles, but we insert a delay to avoid
"overclocking" issues. */
-#define mdio_delay() udelay(1)
+#define mdio_delay() inl(mdio_addr)
#define MDIO_SHIFT_CLK 0x01
#define MDIO_DIR_WRITE 0x04
@@ -2068,11 +2024,11 @@
/* Generate the preamble required for initial synchronization and
a few older transceivers. */
-static void mdio_sync(int ioaddr, int bits)
+static void mdio_sync(long ioaddr, int bits)
{
- int mdio_addr = ioaddr + Wn4_PhysicalMgmt;
+ long mdio_addr = ioaddr + Wn4_PhysicalMgmt;
- /* Establish sync by sending at least 32 logic ones. */
+ /* Establish sync by sending at least 32 logic ones. */
while (-- bits >= 0) {
outw(MDIO_DATA_WRITE1, mdio_addr);
mdio_delay();
@@ -2081,12 +2037,12 @@
}
}
-static int mdio_read(int ioaddr, int phy_id, int location)
+static int mdio_read(long ioaddr, int phy_id, int location)
{
int i;
int read_cmd = (0xf6 << 10) | (phy_id << 5) | location;
unsigned int retval = 0;
- int mdio_addr = ioaddr + Wn4_PhysicalMgmt;
+ long mdio_addr = ioaddr + Wn4_PhysicalMgmt;
if (mii_preamble_required)
mdio_sync(ioaddr, 32);
@@ -2107,13 +2063,17 @@
outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
mdio_delay();
}
- return retval>>1 & 0xffff;
+#if 0
+ return (retval>>1) & 0x1ffff;
+#else
+ return retval & 0x20000 ? 0xffff : retval>>1 & 0xffff;
+#endif
}
-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)
{
int write_cmd = 0x50020000 | (phy_id << 23) | (location << 18) | value;
- int mdio_addr = ioaddr + Wn4_PhysicalMgmt;
+ long mdio_addr = ioaddr + Wn4_PhysicalMgmt;
int i;
if (mii_preamble_required)
@@ -2140,8 +2100,7 @@
#ifdef MODULE
-void
-cleanup_module(void)
+void cleanup_module(void)
{
struct device *next_dev;
@@ -2151,11 +2110,14 @@
/* No need to check MOD_IN_USE, as sys_delete_module() checks. */
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;
unregister_netdev(root_vortex_dev);
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);
kfree(root_vortex_dev);
+ kfree(vp->priv_addr);
root_vortex_dev = next_dev;
}
}
@@ -2166,7 +2128,7 @@
* Local variables:
* compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
* 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/"
* c-indent-level: 4
* c-basic-offset: 4
* tab-width: 4
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/Makefile linux/drivers/net/Makefile
--- linux.vanilla/drivers/net/Makefile Sun Dec 6 00:14:39 1998
+++ linux/drivers/net/Makefile Fri Jan 29 15:38:50 1999
@@ -682,8 +682,8 @@
clean:
rm -f core *.o *.a *.s
-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
wd.o: wd.c CONFIG
$(CC) $(CPPFLAGS) $(CFLAGS) $(WD_OPTS) -c $<
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/README.rcpci linux/drivers/net/README.rcpci
--- linux.vanilla/drivers/net/README.rcpci Thu Jan 1 01:00:00 1970
+++ linux/drivers/net/README.rcpci Fri Jan 29 14:04:32 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 "
+"route add -net eth0"
+
+optional (if you want to be able to access other networks):
+"route add default gw 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/Space.c linux/drivers/net/Space.c
--- linux.vanilla/drivers/net/Space.c Sun Dec 6 00:14:39 1998
+++ linux/drivers/net/Space.c Mon Dec 14 18:32:50 1998
@@ -52,6 +52,7 @@
extern int express_probe(struct device *);
extern int eepro_probe(struct device *);
extern int el3_probe(struct device *);
+extern int tc515_probe(struct device *);
extern int at1500_probe(struct device *);
extern int at1700_probe(struct device *);
extern int fmv18x_probe(struct device *);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/at1700.c linux/drivers/net/at1700.c
--- linux.vanilla/drivers/net/at1700.c Sun Jun 21 18:41:04 1998
+++ linux/drivers/net/at1700.c Mon Dec 14 18:33:02 1998
@@ -595,7 +595,6 @@
/* The inverse routine to net_open(). */
static int net_close(struct device *dev)
{
- struct net_local *lp = (struct net_local *)dev->priv;
int ioaddr = dev->base_addr;
dev->tbusy = 1;
@@ -605,14 +604,6 @@
outb(0xda, ioaddr + CONFIG_0);
/* 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
/* Power-down the chip. Green, green, green! */
outb(0x00, ioaddr + CONFIG_1);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/de4x5.c linux/drivers/net/de4x5.c
--- linux.vanilla/drivers/net/de4x5.c Sun Dec 6 00:14:39 1998
+++ linux/drivers/net/de4x5.c Fri Jan 29 14:17:37 1999
@@ -404,11 +404,12 @@
alignment for Alpha's and avoid their unaligned
access traps. This flag is merely for log messages:
should do something more definitive though...
+ 0.5352 30-Dec-98 Fix driver recognition of the newer DECchips.
=========================================================================
*/
-static const char *version = "de4x5.c:V0.5351 1998/10/4 davies@maniac.ultranet.com\n";
+static const char *version = "de4x5.c:V0.5352 1998/12/30 davies@maniac.ultranet.com\n";
#include
@@ -769,7 +770,7 @@
int tx_new, tx_old; /* TX descriptor ring pointers */
char setup_frame[SETUP_FRAME_LEN]; /* Holds MCA and PA info. */
char frame[64]; /* Min sized packet for loopback*/
- struct net_device_stats stats; /* Public stats */
+ struct net_device_stats stats; /* Public stats */
struct {
u_int bins[DE4X5_PKT_STAT_SZ]; /* Private stats counters */
u_int unicast;
@@ -1356,7 +1357,6 @@
** Re-initialize the DE4X5...
*/
status = de4x5_init(dev);
-
lp->state = OPEN;
de4x5_dbg_open(dev);
@@ -1599,7 +1599,7 @@
DISABLE_IRQs; /* Ensure non re-entrancy */
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);
#if LINUX_VERSION_CODE >= ((2 << 16) | (1 << 8))
synchronize_irq();
@@ -2075,7 +2075,9 @@
irq = inb(EISA_REG0);
irq = de4x5_irq[(irq >> 1) & 0x03];
- if (is_DC2114x) device |= (cfrv & CFRV_RN);
+ if (is_DC2114x) {
+ device = ((cfrv & CFRV_RN) < DC2114x_BRK ? DC21142 : DC21143);
+ }
lp->chipset = device;
/* Write the PCI Configuration Registers */
@@ -2180,7 +2182,9 @@
lp->bus_num = pb;
/* Set the chipset information */
- if (is_DC2114x) device |= (cfrv & CFRV_RN);
+ if (is_DC2114x) {
+ device = ((cfrv & CFRV_RN) < DC2114x_BRK ? DC21142 : DC21143);
+ }
lp->chipset = device;
/* Get the board I/O address (64 bits on sparc64) */
@@ -2291,7 +2295,9 @@
lp->bus_num = pb;
/* Set the chipset information */
- if (is_DC2114x) device |= (cfrv & CFRV_RN);
+ if (is_DC2114x) {
+ device = ((cfrv & CFRV_RN) < DC2114x_BRK ? DC21142 : DC21143);
+ }
lp->chipset = device;
/* Get the board I/O address (64 bits on sparc64) */
@@ -5657,7 +5663,7 @@
cli();
copy_to_user(ioc->data, &lp->pktStats, ioc->len);
sti();
-
+
break;
case DE4X5_CLR_STATS: /* Zero out the driver statistics */
if (suser()) {
@@ -5830,6 +5836,12 @@
if (!mdev) mdev = p;
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));
+ }
kfree(p);
} else {
status = 0; /* At least one adapter will work */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/de4x5.h linux/drivers/net/de4x5.h
--- linux.vanilla/drivers/net/de4x5.h Sun Jun 21 18:41:05 1998
+++ linux/drivers/net/de4x5.h Fri Jan 29 14:17:37 1999
@@ -121,6 +121,7 @@
#define DC2114x DC2114x_DID
#define DC21142 (DC2114x_DID | 0x0010)
#define DC21143 (DC2114x_DID | 0x0030)
+#define DC2114x_BRK 0x0020 /* CFRV break between DC21142 & DC21143 */
#define is_DC21040 ((vendor == DC21040_VID) && (device == DC21040_DID))
#define is_DC21041 ((vendor == DC21041_VID) && (device == DC21041_DID))
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/depca.c linux/drivers/net/depca.c
--- linux.vanilla/drivers/net/depca.c Sun Jun 21 18:41:04 1998
+++ linux/drivers/net/depca.c Sun Dec 6 03:16:27 1998
@@ -154,7 +154,20 @@
the 'memory autoprobe' picking the wrong shared memory (for the case of
2 depca's in a PC).
+ ************************************************************************
+ 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.
+ ************************************************************************
TO DO:
------
@@ -202,11 +215,16 @@
0.422 29-Apr-96 Fix depca_hw_init() bug
0.423 7-Jun-96 Fix module load bug
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
+ 0.45 3-Nov-98 Added support for MCA EtherWORKS (DE210/DE212) cards
+ by
+ 0.451 5-Nov-98 Fixed mca stuff cuz I'm a dummy.
=========================================================================
*/
-static const char *version = "depca.c:v0.43 96/8/16 davies@maniac.ultranet.com\n";
+static const char *version = "depca.c:v0.451 1998/11/14 davies@maniac.ultranet.com\n";
#include
@@ -233,6 +251,10 @@
#include
#include
+#ifdef CONFIG_MCA
+#include
+#endif
+
#include "depca.h"
#ifdef DEPCA_DEBUG
@@ -280,15 +302,20 @@
static short mem_chkd = 0;
/*
+** Adapter ID for the MCA EtherWORKS DE210/212 adapter
+*/
+#define DE212_ID 0x6def
+
+/*
** Name <-> Adapter mapping
*/
#define DEPCA_SIGNATURE {"DEPCA",\
"DE100","DE101",\
"DE200","DE201","DE202",\
- "DE210",\
+ "DE210","DE212",\
"DE422",\
""}
-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;
/*
** Miscellaneous info...
@@ -342,7 +369,7 @@
char devname[DEPCA_STRLEN]; /* Device Product String */
char adapter_name[DEPCA_STRLEN];/* /proc/ioports string */
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 */
struct depca_tx_desc *tx_ring; /* Pointer to start of TX descriptor ring */
struct depca_init init_block;/* Shadow Initialization block */
char *rx_memcpy[NUM_RX_DESC]; /* CPU virt address of sh'd memory buffs */
@@ -393,7 +420,7 @@
/*
** Private functions
*/
-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);
static void depca_init_ring(struct device *dev);
static int depca_rx(struct device *dev);
static int depca_tx(struct device *dev);
@@ -407,6 +434,9 @@
static void SetMulticastFilter(struct device *dev);
static void isa_probe(struct device *dev, u_long iobase);
static void eisa_probe(struct device *dev, u_long iobase);
+#ifdef CONFIG_MCA
+static void mca_probe(struct device *dev, u_long iobase);
+#endif
static struct device *alloc_device(struct device *dev, u_long iobase);
static int depca_dev_index(char *s);
static struct device *insert_device(struct device *dev, u_long iobase, int (*init)(struct device *));
@@ -441,7 +471,8 @@
-int depca_probe(struct device *dev)
+int
+depca_probe(struct device *dev)
{
int tmp = num_depcas, status = -ENODEV;
u_long iobase = dev->base_addr;
@@ -450,6 +481,9 @@
printk("Autoprobing is not supported when loading a module based driver.\n");
status = -EIO;
} else {
+#ifdef CONFIG_MCA
+ mca_probe(dev, iobase);
+#endif
isa_probe(dev, iobase);
eisa_probe(dev, iobase);
@@ -472,7 +506,7 @@
}
static int
-depca_hw_init(struct device *dev, u_long ioaddr)
+depca_hw_init(struct device *dev, u_long ioaddr, int mca_slot)
{
struct depca_private *lp;
int i, j, offset, netRAM, mem_len, status=0;
@@ -495,7 +529,10 @@
if ((adapter != unknown) && mem_start) { /* found a DEPCA device */
dev->base_addr = ioaddr;
- 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 */
printk("%s: %s at 0x%04lx (EISA slot %d)",
dev->name, name, ioaddr, (int)((ioaddr>>12)&0x0f));
} else { /* ISA port address */
@@ -541,7 +578,8 @@
lp = (struct depca_private *)dev->priv;
memset((char *)dev->priv, 0, sizeof(struct depca_private));
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);
request_region(ioaddr, DEPCA_TOTAL_SIZE, lp->adapter_name);
/* Initialisation Block */
@@ -603,6 +641,7 @@
case de201:
case de202:
case de210:
+ case de212:
depca_irq = de2xx_irq;
break;
case de422:
@@ -1205,10 +1244,161 @@
return;
}
+#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
+
/*
** ISA bus I/O device probe
*/
-static void isa_probe(struct device *dev, u_long ioaddr)
+static void
+isa_probe(struct device *dev, u_long ioaddr)
{
int i = num_depcas, maxSlots;
s32 ports[] = DEPCA_IO_PORTS;
@@ -1225,17 +1415,17 @@
}
for (; (iname,ports[i]);
}
+ } else if (autoprobed) {
+ printk("%s: region already allocated at 0x%04x.\n", dev->name,ports[i]);
}
}
@@ -1246,7 +1436,8 @@
** EISA bus I/O device probe. Probe from slot 1 since slot 0 is usually
** the motherboard. Upto 15 EISA devices are supported.
*/
-static void eisa_probe(struct device *dev, u_long ioaddr)
+static void
+eisa_probe(struct device *dev, u_long ioaddr)
{
int i, maxSlots;
u_long iobase;
@@ -1267,19 +1458,19 @@
if ((iobase & 0x0fff) == 0) iobase += DEPCA_EISA_IO_PORTS;
for (; (iname,iobase);
}
}
+ } else if (autoprobed) {
+ printk("%s: region already allocated at 0x%04lx.\n",dev->name,iobase);
}
}
@@ -1683,7 +1874,7 @@
/*
** Perform IOCTL call functions here. Some are privileged operations and the
** 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.
*/
static int depca_ioctl(struct device *dev, struct ifreq *rq, int cmd)
{
@@ -1703,126 +1894,103 @@
tmp.addr[i] = dev->dev_addr[i];
}
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);
break;
+
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; idev_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; idev_addr[i] = tmp.addr[i];
}
+ 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 */
+ 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 */
break;
+
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 */
+ 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 */
break;
+
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 */
+ 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 */
break;
+
case DEPCA_SAY_BOO: /* Say "Boo!" to the kernel log file */
printk("%s: Boo!\n", dev->name);
-
break;
+
case DEPCA_GET_MCA: /* Get the multicast address table */
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);
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;
- }
+ 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);
break;
- case DEPCA_CLR_MCA: /* Clear all multicast addresses */
- if (suser()) {
- set_multicast_list(dev);
- } else {
- status = -EPERM;
- }
+ case DEPCA_CLR_MCA: /* Clear all multicast addresses */
+ if (!suser()) return -EPERM;
+ set_multicast_list(dev);
break;
+
case DEPCA_MCA_EN: /* Enable pass all multicast addressing */
- if (suser()) {
+ if (!suser()) return -EPERM;
set_multicast_list(dev);
- } else {
- status = -EPERM;
- }
-
break;
+
case DEPCA_GET_STATS: /* Get the driver statistics */
cli();
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);
}
sti();
-
break;
- case DEPCA_CLR_STATS: /* Zero out the driver statistics */
- if (suser()) {
- cli();
- memset(&lp->pktStats, 0, sizeof(lp->pktStats));
- sti();
- } else {
- status = -EPERM;
- }
+ case DEPCA_CLR_STATS: /* Zero out the driver statistics */
+ if (!suser()) return -EPERM;
+ cli();
+ memset(&lp->pktStats, 0, sizeof(lp->pktStats));
+ sti();
break;
+
case DEPCA_GET_REG: /* Get the DEPCA Registers */
i=0;
tmp.sval[i++] = inw(DEPCA_NICSR);
@@ -1830,25 +1998,25 @@
tmp.sval[i++] = inw(DEPCA_DATA);
memcpy(&tmp.sval[i], &lp->init_block, sizeof(struct depca_init));
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);
break;
+
default:
- status = -EOPNOTSUPP;
+ return -EOPNOTSUPP;
}
return status;
}
#ifdef MODULE
-static char devicename[9] = { 0, };
+static char devicename[9] = {0,};
static struct device thisDepca = {
devicename, /* device name is inserted by /linux/drivers/net/net_init.c */
0, 0, 0, 0,
0x200, 7, /* I/O address, IRQ */
- 0, 0, 0, NULL, depca_probe };
+ 0, 0, 0, NULL, depca_probe
+};
static int irq=7; /* EDIT THESE LINE FOR YOUR CONFIGURATION */
static int io=0x200; /* Or use the irq= io= options to insmod */
@@ -1869,8 +2037,13 @@
void
cleanup_module(void)
{
- 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);
thisDepca.priv = NULL;
}
thisDepca.irq=0;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/dgrs.c linux/drivers/net/dgrs.c
--- linux.vanilla/drivers/net/dgrs.c Fri Jul 24 17:28:59 1998
+++ linux/drivers/net/dgrs.c Mon Dec 14 18:33:16 1998
@@ -1254,10 +1254,11 @@
)
{
DGRS_PRIV *priv;
- int i;
#ifdef MODULE
{
+ int i;
+
/* Allocate and fill new device structure. */
int dev_size = sizeof(struct device) + sizeof(DGRS_PRIV);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/dummy.c linux/drivers/net/dummy.c
--- linux.vanilla/drivers/net/dummy.c Sun Jun 21 18:41:04 1998
+++ linux/drivers/net/dummy.c Fri Jan 29 14:29:36 1999
@@ -70,6 +70,10 @@
return 0;
}
+static int dummy_rebuild(void *eth, struct device *dev, unsigned long raddr, struct sk_buff *skb)
+{
+ return 0;
+}
int dummy_init(struct device *dev)
{
@@ -94,6 +98,7 @@
/* Fill in the fields of the device structure with ethernet-generic values. */
ether_setup(dev);
dev->flags |= IFF_NOARP;
+ dev->rebuild_header = dummy_rebuild;
return 0;
}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/eepro100.c linux/drivers/net/eepro100.c
--- linux.vanilla/drivers/net/eepro100.c Sun Dec 6 00:14:40 1998
+++ linux/drivers/net/eepro100.c Sun Dec 6 03:34:33 1998
@@ -7,7 +7,7 @@
of the GNU Public License, incorporated herein by reference.
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.
To use a built-in driver, install as drivers/net/eepro100.c.
To use as a module, use the compile-command at the end of the file.
@@ -15,11 +15,13 @@
Center of Excellence in Space Data and Information Sciences
Code 930.5, NASA Goddard Space Flight Center, Greenbelt MD 20771
For updates see
-
+ http://cesdis.gsfc.nasa.gov/linux/drivers/eepro100.html
+ There is also a mailing list based at
+ linux-eepro100@cesdis.gsfc.nasa.gov
*/
static const char *version =
-"eepro100.c:v0.99B 4/7/98 Donald Becker linux-eepro100@cesdis.gsfc.nasa.gov\n";
+"eepro100.c:v1.05 10/16/98 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/eepro100.html\n";
/* A few user-configurable values that apply to all boards.
First set are undocumented and spelled per Intel recommendations. */
@@ -41,6 +43,7 @@
/* Maximum number of multicast addresses to filter (vs. rx-all-multicast) */
static int multicast_filter_limit = 64;
+#include
#ifdef MODULE
#ifdef MODVERSIONS
#include
@@ -53,20 +56,18 @@
#include
#include
-#include
#include
#include
-#include
#include
#include
#include
#include
#include
-#include
-#include /* Processor type for cache alignment. */
+#if LINUX_VERSION_CODE < 0x20155
+#include /* Ignore the bogus warning in 2.1.100+ */
+#endif
#include
#include
-#include
#include
#include
@@ -74,9 +75,9 @@
#include
/* Unused in the 2.0.* version, but retained for documentation. */
-#if LINUX_VERSION_CODE > 0x20118
+#if LINUX_VERSION_CODE > 0x20118 && defined(MODULE)
MODULE_AUTHOR("Donald Becker ");
-MODULE_DESCRIPTION("Intel i82557/i82558 EtherExpressPro driver");
+MODULE_DESCRIPTION("Intel i82557/i82558 PCI EtherExpressPro driver");
MODULE_PARM(debug, "i");
MODULE_PARM(options, "1-" __MODULE_STRING(8) "i");
MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i");
@@ -95,6 +96,11 @@
#if (LINUX_VERSION_CODE < 0x20123)
#define test_and_set_bit(val, addr) set_bit(val, addr)
#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
/* The total I/O port extent of the board.
The registers beyond 0x18 only exist on the i82558. */
@@ -132,7 +138,7 @@
Despite the extra space overhead in each receive skbuff, the driver must use
the simplified Rx buffer mode to assure that only a single data buffer is
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.
The Speedo-3 has receive and command unit base addresses that are added to
almost all descriptor pointers. The driver sets these to zero, so that all
@@ -147,10 +153,13 @@
The driver must use the complex Tx command+descriptor mode in order to
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
(TxBD). A fixed ring of these TxCB+TxBD pairs are kept as part of the
speedo_private data structure for each adapter instance.
+The newer i82558 explicitly supports this structure, and can read the two
+TxBDs in the same PCI burst as the TxCB.
+
This ring structure is used for all normal transmit packets, but the
transmit packet descriptors aren't long enough for most non-Tx commands such
as CmdConfigure. This is complicated by the possibility that the chip has
@@ -181,10 +190,10 @@
doing the CU_RESUME
the chip processes the next-yet-valid post-final-command.
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.
Note: In previous generation Intel chips, restarting the command unit was a
notoriously slow process. This is presumably no longer true.
@@ -243,11 +252,11 @@
/* How to wait for the command unit to accept a command.
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)
{
- short wait = 100;
- do ;
- while(inb(cmd_ioaddr) && --wait >= 0);
+ int wait = 100;
+ do ;
+ while(inb(cmd_ioaddr) && --wait >= 0);
}
/* Operational parameter that usually are not changed. */
@@ -306,17 +315,24 @@
u16 size;
};
-/* 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,
+};
struct TxFD { /* Transmit frame descriptor set. */
s32 status;
u32 link; /* void * */
u32 tx_desc_addr; /* Always points to the tx_buf_addr element. */
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. */
};
/* Elements of the dump_statistics block. This block must be lword aligned. */
@@ -358,10 +374,9 @@
long last_rx_time; /* Last Rx, in jiffies, to handle Rx hang. */
unsigned int cur_rx, cur_tx; /* The next free ring entry */
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. */
int mc_setup_frm_len; /* The length of an allocated.. */
struct descriptor *mc_setup_frm; /* ..multicast setup frame. */
+ int mc_setup_busy; /* Avoid double-use of setup frame. */
int in_interrupt; /* Word-aligned dev->interrupt */
char rx_mode; /* Current PROMISC/ALLMULTI setting. */
unsigned int tx_full:1; /* The Tx queue is full. */
@@ -376,11 +391,16 @@
/* The parameters for a CmdConfigure operation.
There are so many options that it would be difficult to document each bit.
We mostly use the default or recommended settings. */
-const char basic_config_cmd[22] = {
+const char i82557_config_cmd[22] = {
22, 0x08, 0, 0, 0, 0x80, 0x32, 0x03, 1, /* 1=Use MII 0=Use AUI */
0, 0x2E, 0, 0x60, 0,
0xf2, 0x48, 0, 0x40, 0xf2, 0x80, /* 0x40=Force full-duplex */
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, };
/* PHY media interface chips. */
static const char *phys[] = {
@@ -392,12 +412,12 @@
S80C24, I82555, DP83840A=10, };
static const char is_mii[] = { 0, 1, 1, 0, 1, 1, 0, 1 };
-static void speedo_found1(struct device *dev, int ioaddr, int irq,
+static void speedo_found1(struct device *dev, long ioaddr, int irq,
int card_idx);
-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);
static int speedo_open(struct device *dev);
static void speedo_timer(unsigned long data);
static void speedo_init_rx_ring(struct device *dev);
@@ -420,68 +440,91 @@
static int debug = -1; /* The debug level */
#endif
+#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
+
/* A list of all installed Speedo devices, for removing the driver module. */
static struct device *root_speedo_dev = NULL;
int eepro100_init(struct device *dev)
{
int cards_found = 0;
+ static int pci_index = 0;
- 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;
pcibios_read_config_byte(pci_bus, pci_device_fn,
PCI_INTERRUPT_LINE, &pci_irq_line);
/* Note: BASE_ADDRESS_0 is for memory-mapping the registers. */
pcibios_read_config_dword(pci_bus, pci_device_fn,
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);
}
+ 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++;
}
return cards_found;
}
-static void speedo_found1(struct device *dev, int ioaddr, int irq,
+static void speedo_found1(struct device *dev, long ioaddr, int irq,
int card_idx)
{
static int did_version = 0; /* Already printed version info. */
@@ -495,7 +538,7 @@
dev = init_etherdev(dev, sizeof(struct speedo_private));
- if (dev->mem_start > 0)
+ if (dev->mem_start > 0)
option = dev->mem_start;
else if (card_idx >= 0 && options[card_idx] >= 0)
option = options[card_idx];
@@ -508,8 +551,10 @@
{
u16 sum = 0;
int j;
+ int addr_len = read_eeprom(ioaddr, 0, 6) == 0xffff ? 8 : 6;
+
for (j = 0, i = 0; i < 0x40; i++) {
- u16 value = read_eeprom(ioaddr, i);
+ u16 value = read_eeprom(ioaddr, i, addr_len);
eeprom[i] = value;
sum += value;
if (i < 3) {
@@ -535,7 +580,7 @@
else
product = "Intel EtherExpress Pro 10/100";
- printk(KERN_INFO "%s: %s at %#3x, ", dev->name, product, ioaddr);
+ printk(KERN_INFO "%s: %s at %#3lx, ", dev->name, product, ioaddr);
for (i = 0; i < 5; i++)
printk("%2.2X:", dev->dev_addr[i]);
@@ -666,22 +711,22 @@
#define eeprom_delay(nanosec) udelay(1);
/* 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)
-static int read_eeprom(int ioaddr, int location)
+static int read_eeprom(long ioaddr, int location, int addr_len)
{
- int i;
unsigned short retval = 0;
int ee_addr = ioaddr + SCBeeprom;
int read_cmd = location | EE_READ_CMD;
+ int i;
outw(EE_ENB & ~EE_CS, ee_addr);
outw(EE_ENB, ee_addr);
/* Shift the read command bits out. */
- for (i = 10; i >= 0; i--) {
+ for (i = 12; i >= 0; i--) {
short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
outw(EE_ENB | dataval, ee_addr);
eeprom_delay(100);
@@ -703,7 +748,7 @@
return retval;
}
-static int mdio_read(int ioaddr, int phy_id, int location)
+static int mdio_read(long ioaddr, int phy_id, int location)
{
int val, boguscnt = 64*10; /* <64 usec. to complete, typ 27 ticks */
outl(0x08000000 | (location<<16) | (phy_id<<21), ioaddr + SCBCtrlMDI);
@@ -716,7 +761,7 @@
return val & 0xffff;
}
-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)
{
int val, boguscnt = 64*10; /* <64 usec. to complete, typ 27 ticks */
outl(0x04000000 | (location<<16) | (phy_id<<21) | value,
@@ -735,7 +780,7 @@
speedo_open(struct device *dev)
{
struct speedo_private *sp = (struct speedo_private *)dev->priv;
- int ioaddr = dev->base_addr;
+ long ioaddr = dev->base_addr;
#ifdef notdef
/* We could reset the chip, but should not need to. */
@@ -752,6 +797,22 @@
MOD_INC_USE_COUNT;
+ /* 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
+ }
+
/* Load the statistics block address. */
wait_for_cmd_done(ioaddr + SCBCmd);
outl(virt_to_bus(&sp->lstats), ioaddr + SCBPointer);
@@ -805,6 +866,7 @@
/* Setup the chip and configure the multicast list. */
sp->mc_setup_frm = NULL;
sp->mc_setup_frm_len = 0;
+ sp->mc_setup_busy = 0;
sp->rx_mode = -1; /* Invalid -> always reset the mode. */
set_rx_mode(dev);
@@ -825,6 +887,9 @@
wait_for_cmd_done(ioaddr + SCBCmd);
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);
return 0;
}
@@ -833,24 +898,22 @@
{
struct device *dev = (struct device *)data;
struct speedo_private *sp = (struct speedo_private *)dev->priv;
- int tickssofar = jiffies - sp->last_rx_time;
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",
dev->name, inw(ioaddr + SCBStatus));
}
- 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);
}
+ /* We must continue to monitor the media. */
+ sp->timer.expires = RUN_AT(2*HZ); /* 2.0 sec. */
+ add_timer(&sp->timer);
}
/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
@@ -862,30 +925,32 @@
int i;
sp->cur_rx = 0;
- sp->dirty_rx = RX_RING_SIZE - 1;
for (i = 0; i < RX_RING_SIZE; i++) {
struct sk_buff *skb;
- skb = alloc_skb(PKT_BUF_SZ, GFP_ATOMIC);
+ skb = dev_alloc_skb(PKT_BUF_SZ + sizeof(struct RxFD));
sp->rx_skbuff[i] = skb;
if (skb == NULL)
- break; /* Bad news! */
+ break; /* OK. Just initially short of Rx bufs. */
skb->dev = dev; /* Mark as being used by this device. */
-
rxf = (struct RxFD *)skb->tail;
- skb_reserve(skb, sizeof(struct RxFD));
sp->rx_ringp[i] = rxf;
+ skb_reserve(skb, sizeof(struct RxFD));
if (last_rxf)
last_rxf->link = virt_to_bus(rxf);
last_rxf = rxf;
rxf->status = 0x00000001; /* '1' is flag value only. */
rxf->link = 0; /* None yet. */
/* This field unused by i82557, we use it as a consistency check. */
+#ifdef final_version
+ rxf->rx_buf_addr = 0xffffffff;
+#else
rxf->rx_buf_addr = virt_to_bus(skb->tail);
-
+#endif
rxf->count = 0;
rxf->size = PKT_BUF_SZ;
}
+ sp->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
/* Mark the last entry as end-of-list. */
last_rxf->status = 0xC0000002; /* '2' is flag value only. */
sp->last_rxf = last_rxf;
@@ -894,20 +959,21 @@
static void speedo_tx_timeout(struct device *dev)
{
struct speedo_private *sp = (struct speedo_private *)dev->priv;
- int ioaddr = dev->base_addr;
+ long ioaddr = dev->base_addr;
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);
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);
} else {
- outw(DRVR_INT, ioaddr + SCBCmd);
+ outw(DRVR_INT, ioaddr + SCBCmd);
}
/* Reset the MII transceiver, suggested by Fred Young @ scalable.com. */
if ((sp->phy[0] & 0x8000) == 0) {
@@ -916,6 +982,9 @@
mdio_write(ioaddr, phy_addr, 1, 0x0000);
mdio_write(ioaddr, phy_addr, 4, 0x0000);
mdio_write(ioaddr, phy_addr, 0, 0x8000);
+#ifdef honor_default_port
+ mdio_write(ioaddr, phy_addr, 0, mii_ctrl[dev->default_port & 7]);
+#endif
}
sp->stats.tx_errors++;
dev->trans_start = jiffies;
@@ -926,7 +995,7 @@
speedo_start_xmit(struct sk_buff *skb, struct device *dev)
{
struct speedo_private *sp = (struct speedo_private *)dev->priv;
- int ioaddr = dev->base_addr;
+ long ioaddr = dev->base_addr;
int entry;
/* Block a timer-based transmit from overlapping. This could better be
@@ -963,22 +1032,22 @@
sp->tx_ring[entry].link =
virt_to_bus(&sp->tx_ring[sp->cur_tx % TX_RING_SIZE]);
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);
/* The data region is always in one buffer descriptor, Tx FIFO
threshold of 256. */
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;
/* Todo: perhaps leave the interrupt bit set if the Tx queue is more
than half full. Argument against: we should be receiving packets
and scavenging the queue. Argument for: if so, it shouldn't
matter. */
sp->last_cmd->command &= ~(CmdSuspend | CmdIntr);
sp->last_cmd = (struct descriptor *)&sp->tx_ring[entry];
+ restore_flags(flags);
/* Trigger the command unit resume. */
wait_for_cmd_done(ioaddr + SCBCmd);
outw(CU_RESUME, ioaddr + SCBCmd);
- restore_flags(flags);
}
/* Leave room for set_rx_mode() to fill two entries. */
@@ -998,7 +1067,7 @@
{
struct device *dev = (struct device *)dev_instance;
struct speedo_private *sp;
- int ioaddr, boguscnt = max_interrupt_work;
+ long ioaddr, boguscnt = max_interrupt_work;
unsigned short status;
#ifndef final_version
@@ -1015,6 +1084,7 @@
if (test_and_set_bit(0, (void*)&sp->in_interrupt)) {
printk(KERN_ERR"%s: SMP simultaneous entry of an interrupt handler.\n",
dev->name);
+ sp->in_interrupt = 0; /* Avoid halting machine. */
return;
}
dev->interrupt = 1;
@@ -1058,14 +1128,15 @@
if (speedo_debug > 5)
printk(KERN_DEBUG " scavenge candidate %d status %4.4x.\n",
entry, status);
- if ((status & 0x8000) == 0)
+ if ((status & StatusComplete) == 0)
break; /* It still hasn't been processed. */
/* Free the original skb. */
if (sp->tx_skbuff[entry]) {
sp->stats.tx_packets++; /* Count only user packets. */
- dev_kfree_skb(sp->tx_skbuff[entry], FREE_WRITE);
+ dev_free_skb(sp->tx_skbuff[entry]);
sp->tx_skbuff[entry] = 0;
- }
+ } else if ((sp->tx_ring[entry].status&0x70000) == CmdNOp << 16)
+ sp->mc_setup_busy = 0;
dirty_tx++;
}
@@ -1113,108 +1184,104 @@
struct speedo_private *sp = (struct speedo_private *)dev->priv;
int entry = sp->cur_rx % RX_RING_SIZE;
int status;
+ int rx_work_limit = sp->dirty_rx + RX_RING_SIZE - sp->cur_rx;
if (speedo_debug > 4)
printk(KERN_DEBUG " In speedo_rx().\n");
/* 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) {
+ if (--rx_work_limit < 0)
+ break;
if (speedo_debug > 4)
printk(KERN_DEBUG " speedo_rx() status %8.8x len %d.\n", status,
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);
+ }
} else {
- /* Malloc up new buffer, compatible with net-2e. */
int pkt_len = sp->rx_ringp[entry]->count & 0x3fff;
struct sk_buff *skb;
- int rx_in_place = 0;
/* Check if the packet is long enough to just accept without
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
/* 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);
#else
memcpy(skb_put(skb, pkt_len),
bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr), pkt_len);
#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;
}
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb);
sp->stats.rx_packets++;
}
+ entry = (++sp->cur_rx) % RX_RING_SIZE;
+ }
- /* 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];
}
+ 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;
}
sp->last_rx_time = jiffies;
@@ -1224,7 +1291,7 @@
static int
speedo_close(struct device *dev)
{
- int ioaddr = dev->base_addr;
+ long ioaddr = dev->base_addr;
struct speedo_private *sp = (struct speedo_private *)dev->priv;
int i;
@@ -1250,7 +1317,7 @@
sp->rx_skbuff[i] = 0;
/* Clear the Rx descriptors. */
if (skb)
- dev_kfree_skb(skb, FREE_WRITE);
+ dev_free_skb(skb);
}
for (i = 0; i < TX_RING_SIZE; i++) {
@@ -1258,7 +1325,7 @@
sp->tx_skbuff[i] = 0;
/* Clear the Tx descriptors. */
if (skb)
- dev_kfree_skb(skb, FREE_WRITE);
+ dev_free_skb(skb);
}
if (sp->mc_setup_frm) {
kfree(sp->mc_setup_frm);
@@ -1303,7 +1370,7 @@
speedo_get_stats(struct device *dev)
{
struct speedo_private *sp = (struct speedo_private *)dev->priv;
- int ioaddr = dev->base_addr;
+ long ioaddr = dev->base_addr;
if (sp->lstats.done_marker == 0xA007) { /* Previous dump finished */
sp->stats.tx_aborted_errors += sp->lstats.tx_coll16_errs;
@@ -1329,7 +1396,7 @@
static int speedo_ioctl(struct device *dev, struct ifreq *rq, int cmd)
{
struct speedo_private *sp = (struct speedo_private *)dev->priv;
- int ioaddr = dev->base_addr;
+ long ioaddr = dev->base_addr;
u16 *data = (u16 *)&rq->ifr_data;
int phy = sp->phy[0] & 0x1f;
@@ -1362,7 +1429,8 @@
set_rx_mode(struct device *dev)
{
struct speedo_private *sp = (struct speedo_private *)dev->priv;
- int ioaddr = dev->base_addr;
+ long ioaddr = dev->base_addr;
+ struct descriptor *last_cmd;
char new_rx_mode;
unsigned long flags;
int entry, i;
@@ -1383,57 +1451,55 @@
}
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. */
cli();
- /* Fill the "real" tx_ring frame with a no-op and point it to us. */
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];
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;
}
+ /* Trigger the command unit resume. */
+ last_cmd->command &= ~CmdSuspend;
+ wait_for_cmd_done(ioaddr + SCBCmd);
+ outw(CU_RESUME, ioaddr + SCBCmd);
}
- 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
fits within one tx_ring[] entry. */
- u16 *setup_params, *eaddrs;
struct dev_mc_list *mclist;
+ u16 *setup_params, *eaddrs;
- save_flags(flags);
+ save_flags(flags); /* Lock to protect sp->cur_tx. */
cli();
entry = sp->cur_tx++ % TX_RING_SIZE;
+ last_cmd = sp->last_cmd;
+ sp->last_cmd = (struct descriptor *)&sp->tx_ring[entry];
+ restore_flags(flags);
+
sp->tx_skbuff[entry] = 0;
sp->tx_ring[entry].status = (CmdSuspend | CmdMulticastList) << 16;
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]);
sp->tx_ring[entry].tx_desc_addr = 0; /* Really MC list count. */
setup_params = (u16 *)&sp->tx_ring[entry].tx_desc_addr;
*setup_params++ = dev->mc_count*6;
@@ -1446,36 +1512,39 @@
*setup_params++ = *eaddrs++;
}
- sp->last_cmd->command &= ~CmdSuspend;
+ last_cmd->command &= ~CmdSuspend;
/* Immediately trigger the command unit resume. */
wait_for_cmd_done(ioaddr + SCBCmd);
outw(CU_RESUME, ioaddr + SCBCmd);
- sp->last_cmd = (struct descriptor *)&sp->tx_ring[entry];
- restore_flags(flags);
} else if (new_rx_mode == 0) {
- /* This does not work correctly, but why not? */
struct dev_mc_list *mclist;
- u16 *eaddrs;
+ u16 *setup_params, *eaddrs;
struct descriptor *mc_setup_frm = sp->mc_setup_frm;
- u16 *setup_params;
int i;
if (sp->mc_setup_frm_len < 10 + dev->mc_count*6
|| sp->mc_setup_frm == NULL) {
- /* Allocate a new frame, 10bytes + addrs, with a few
- extra entries for growth. */
+ /* Allocate a full setup frame, 10bytes + . */
if (sp->mc_setup_frm)
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;
sp->mc_setup_frm = kmalloc(sp->mc_setup_frm_len, GFP_ATOMIC);
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);
sp->rx_mode = -1; /* We failed, try again. */
return;
}
}
+ /* 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;
+ }
mc_setup_frm = sp->mc_setup_frm;
- /* Construct the new setup frame. */
+ /* Fill the setup frame. */
if (speedo_debug > 1)
printk(KERN_DEBUG "%s: Constructing a setup frame at %p, "
"%d bytes.\n",
@@ -1483,7 +1552,7 @@
mc_setup_frm->status = 0;
mc_setup_frm->command = CmdSuspend | CmdIntr | CmdMulticastList;
/* Link set below. */
- setup_params = (u16 *)mc_setup_frm->params;
+ setup_params = (u16 *)&mc_setup_frm->params;
*setup_params++ = dev->mc_count*6;
/* Fill in the multicast addresses. */
for (i = 0, mclist = dev->mc_list; i < dev->mc_count;
@@ -1498,10 +1567,10 @@
save_flags(flags);
cli();
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);
/* Change the command to a NoOp, pointing to the CmdMulti command. */
sp->tx_skbuff[entry] = 0;
@@ -1510,17 +1579,15 @@
/* Set the link in the setup frame. */
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]));
- sp->last_cmd->command &= ~CmdSuspend;
+ last_cmd->command &= ~CmdSuspend;
/* Immediately trigger the command unit resume. */
wait_for_cmd_done(ioaddr + SCBCmd);
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);
}
sp->rx_mode = new_rx_mode;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/epic100.c linux/drivers/net/epic100.c
--- linux.vanilla/drivers/net/epic100.c Sun Dec 6 00:14:40 1998
+++ linux/drivers/net/epic100.c Sun Dec 27 20:48:40 1998
@@ -1,6 +1,6 @@
/* epic100.c: A SMC 83c170 EPIC/100 Fast Ethernet driver for Linux. */
/*
- Written 1997-1998 by Donald Becker.
+ Written/copyright 1997-1998 by Donald Becker.
This software may be used and distributed according to the terms
of the GNU Public License, incorporated herein by reference.
@@ -10,15 +10,15 @@
SMC EtherPower II 9432 PCI adapter, and several CardBus cards.
The author may be reached as becker@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
Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
- Support and updates available at
+ Information and updates available at
http://cesdis.gsfc.nasa.gov/linux/drivers/epic100.html
*/
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";
/* A few user-configurable values. */
@@ -118,6 +118,7 @@
/* The I/O extent. */
#define EPIC_TOTAL_SIZE 0x100
+#define epic_debug debug
static int epic_debug = 1;
/*
@@ -155,7 +156,8 @@
/* The rest of these values should never change. */
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);
enum pci_flags_bit {
PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
@@ -166,9 +168,11 @@
u16 vendor_id, device_id, device_id_mask, pci_flags;
int io_size, min_latency;
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);
} 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,
PCI_USES_IO|PCI_USES_MASTER|PCI_ADDR0, EPIC_TOTAL_SIZE, 32, epic_probe1},
{0,},
};
@@ -276,7 +280,7 @@
int epic100_probe(struct device *dev)
{
int cards_found = 0;
- int chip_idx;
+ int chip_idx, irq;
u16 pci_command, new_command;
unsigned char pci_bus, pci_device_fn;
@@ -298,6 +302,7 @@
continue;
pci_bus = pcidev->bus->number;
pci_device_fn = pcidev->devfn;
+ irq = pcidev->irq;
#else
int pci_index;
@@ -305,6 +310,7 @@
return -ENODEV;
for (pci_index = 0; pci_index < 0xff; pci_index++) {
+ u8 pci_irq_line;
u16 vendor, device;
u32 pci_ioaddr;
@@ -327,8 +333,11 @@
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);
/* Remove I/O space marker in bit 0. */
pci_ioaddr &= ~3;
+ irq = pci_irq_line;
if (check_region(pci_ioaddr, chip_tbl[chip_idx].io_size))
continue;
@@ -350,8 +359,8 @@
PCI_COMMAND, new_command);
}
- 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);
/* Check the latency timer. */
if (dev) {
@@ -375,17 +384,12 @@
}
#endif /* not CARDBUS */
-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)
{
- static int did_version = 0; /* Already printed version info. */
struct epic_private *ep;
int i, option = 0, duplex = 0;
- u16 chip_id;
- u32 ioaddr;
-
- if (epic_debug > 0 && did_version++ == 0)
- printk(KERN_INFO "%s", version);
if (dev && dev->mem_start) {
option = dev->mem_start;
@@ -399,26 +403,10 @@
dev = init_etherdev(dev, 0);
- { /* 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
- }
-
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);
/* Bring the chip out of low-power mode. */
outl(0x4200, ioaddr + GENCTL);
@@ -427,7 +415,7 @@
/* Turn on the MII transceiver. */
outl(0x12, ioaddr + MIICfg);
- if (chip_id == 6)
+ if (chip_idx == 1)
outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL);
outl(0x0200, ioaddr + GENCTL);
@@ -447,7 +435,7 @@
}
/* 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);
/* The data structures must be quadword aligned. */
ep = kmalloc(sizeof(*ep), GFP_KERNEL | GFP_DMA);
@@ -457,9 +445,13 @@
ep->next_module = root_epic_dev;
root_epic_dev = dev;
- 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
/* Find the connected MII xcvrs.
Doing this in open() would allow detecting external xcvrs later, but
@@ -545,7 +537,6 @@
int read_cmd = location |
(inl(ee_addr) & 0x40) ? EE_READ64_CMD : EE_READ256_CMD;
- printk("EEctrl is %x.\n", inl(ee_addr));
outl(EE_ENB & ~EE_CS, ee_addr);
outl(EE_ENB, ee_addr);
@@ -930,11 +921,9 @@
static void epic_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
{
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;
#if defined(__i386__)
/* A lock to prevent simultaneous entry bug on Intel SMP machines. */
@@ -1340,12 +1329,18 @@
if (loc->bus != LOC_PCI) return NULL;
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);
pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, &io);
pcibios_read_config_byte(bus, devfn, PCI_INTERRUPT_LINE, &irq);
pcibios_read_config_word(bus, devfn, PCI_DEVICE_ID, &dev_id);
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);
if (dev) {
dev_node_t *node = kmalloc(sizeof(dev_node_t), GFP_KERNEL);
strcpy(node->dev_name, dev->name);
@@ -1410,14 +1405,10 @@
#ifdef MODULE
-/* An additional parameter that may be passed in... */
-static int debug = -1;
-
-int
-init_module(void)
+int init_module(void)
{
- if (debug >= 0)
- epic_debug = debug;
+ if (epic_debug)
+ printk(KERN_INFO "%s", version);
#ifdef CARDBUS
register_driver(&epic_ops);
@@ -1427,8 +1418,7 @@
#endif
}
-void
-cleanup_module(void)
+void cleanup_module(void)
{
struct device *next_dev;
@@ -1438,11 +1428,13 @@
/* No need to check MOD_IN_USE, as sys_delete_module() checks. */
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;
unregister_netdev(root_epic_dev);
release_region(root_epic_dev->base_addr, EPIC_TOTAL_SIZE);
kfree(root_epic_dev);
root_epic_dev = next_dev;
+ kfree(ep);
}
}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/eth16i.c linux/drivers/net/eth16i.c
--- linux.vanilla/drivers/net/eth16i.c Sun Dec 6 00:14:40 1998
+++ linux/drivers/net/eth16i.c Mon Dec 14 18:33:22 1998
@@ -886,7 +886,7 @@
creg[0] &= 0x0F; /* Mask collision cnr */
creg[2] &= 0x7F; /* Mask DCLEN bit */
-#ifdef 0
+#if 0
/*
This was removed because the card was sometimes left to state
from which it couldn't be find anymore. If there is need
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/lance.c linux/drivers/net/lance.c
--- linux.vanilla/drivers/net/lance.c Sun Dec 6 00:14:40 1998
+++ linux/drivers/net/lance.c Mon Dec 14 18:29:48 1998
@@ -334,14 +334,17 @@
dev->base_addr = io[this_dev];
dev->dma = dma[this_dev];
dev->init = lance_probe;
+#if NO_AUTOPROBE_MODULE
if (io[this_dev] == 0) {
if (this_dev != 0) break; /* only complain once */
printk(KERN_NOTICE "lance.c: Module autoprobing not allowed. Append \"io=0xNNN\" value(s).\n");
return -EPERM;
}
+#endif
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");
return -ENXIO;
}
found++;
@@ -350,8 +353,7 @@
return 0;
}
-void
-cleanup_module(void)
+void cleanup_module(void)
{
int this_dev;
@@ -390,15 +392,21 @@
unsigned short pci_command;
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)
break;
pcibios_read_config_byte(pci_bus, pci_device_fn,
- PCI_INTERRUPT_LINE, &pci_irq_line);
+ PCI_INTERRUPT_LINE, &pci_irq_line);
pcibios_read_config_dword(pci_bus, pci_device_fn,
- PCI_BASE_ADDRESS_0, &pci_ioaddr);
+ PCI_BASE_ADDRESS_0, &pci_ioaddr);
/* Remove I/O space marker in bit 0. */
pci_ioaddr &= ~3;
+
+ /* Avoid already found cards from previous calls
+ */
+ if (check_region(pci_ioaddr, LANCE_TOTAL_SIZE))
+ continue;
+
/* PCI Spec 2.1 states that it is either the driver or PCI card's
* responsibility to set the PCI Master Enable Bit if needed.
* (From Mark Stockton )
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/ne.c linux/drivers/net/ne.c
--- linux.vanilla/drivers/net/ne.c Sun Jun 21 18:41:04 1998
+++ linux/drivers/net/ne.c Tue Mar 2 00:51:17 1999
@@ -97,6 +97,7 @@
{"ET-100","ET-200", {0x00, 0x45, 0x54}}, /* YANG and YA clone */
{"COMPEX","COMPEX16",{0x00,0x80,0x48}}, /* Broken ISA Compex cards */
{"E-LAN100", "E-LAN200", {0x00, 0x00, 0x5d}}, /* Broken ne1000 clones */
+ {"PCM-4823", "PCM-4823", {0x00, 0xc0, 0x6c}}, /* Broken Advantech MoBo */
{0,}
};
#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/ni52.c linux/drivers/net/ni52.c
--- linux.vanilla/drivers/net/ni52.c Fri Jul 24 17:28:59 1998
+++ linux/drivers/net/ni52.c Mon Dec 14 18:33:43 1998
@@ -363,10 +363,11 @@
#endif
int base_addr = dev->base_addr;
- if (base_addr > 0x1ff) /* Check a single specified location. */
+ if (base_addr > 0x1ff) { /* Check a single specified location. */
if( (inb(base_addr+NI52_MAGIC1) == NI52_MAGICVAL1) &&
(inb(base_addr+NI52_MAGIC2) == NI52_MAGICVAL2))
return ni52_probe1(dev, base_addr);
+ }
else if (base_addr > 0) /* Don't probe at all. */
return ENXIO;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/pi2.c linux/drivers/net/pi2.c
--- linux.vanilla/drivers/net/pi2.c Fri Jul 24 17:29:00 1998
+++ linux/drivers/net/pi2.c Mon Dec 14 18:33:51 1998
@@ -1452,7 +1452,7 @@
static int pi_open(struct device *dev)
{
unsigned long flags;
- static first_time = 1;
+ static int first_time = 1;
struct pi_local *lp = (struct pi_local *) dev->priv;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/ppp.c linux/drivers/net/ppp.c
--- linux.vanilla/drivers/net/ppp.c Sun Jun 21 18:41:04 1998
+++ linux/drivers/net/ppp.c Mon Dec 14 18:41:59 1998
@@ -3155,7 +3155,7 @@
ppp_stats.tx_heartbeat_errors = 0;
if (ppp->flags & SC_DEBUG)
- printk (KERN_INFO "ppp_dev_stats called");
+ printk (KERN_INFO "ppp_dev_stats called\n");
return &ppp_stats;
}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/pt.c linux/drivers/net/pt.c
--- linux.vanilla/drivers/net/pt.c Fri Jul 24 17:29:00 1998
+++ linux/drivers/net/pt.c Mon Dec 14 18:33:58 1998
@@ -909,7 +909,7 @@
{
unsigned long flags;
struct pt_local *lp = dev->priv;
- static first_time = 1;
+ static int first_time = 1;
if (dev->base_addr & CHANA)
{
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/rcif.h linux/drivers/net/rcif.h
--- linux.vanilla/drivers/net/rcif.h Sun Dec 6 00:14:40 1998
+++ linux/drivers/net/rcif.h Fri Jan 29 14:03:40 1999
@@ -8,7 +8,7 @@
** RedCreek InterFace include file.
**
** ---------------------------------------------------------------------
-** --- Copyright (c) 1998, RedCreek Communications Inc. ---
+** --- Copyright (c) 1998-1999, RedCreek Communications Inc. ---
** --- All rights reserved. ---
** ---------------------------------------------------------------------
**
@@ -38,7 +38,7 @@
/* The following protocol revision # should be incremented every time
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 */
/* define a single TCB & buffer */
typedef struct /* a single buffer */
@@ -124,6 +124,31 @@
U32 LinkSpeedCode;
} RCgetspeed; /* <---- RCgetspeed */
+ /* 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 */
+
/* GETFIRMWAREVER structure */
#define FirmStringLen 80
struct RCgetfwver_tag {
@@ -136,12 +161,23 @@
U32 NetMask;
} RCgetipandmask; /* <---- RCgetipandmask */
+ /* SETIPANDMASK structure */
+ struct RCsetipnmask_tag {
+ U32 IpAddr;
+ U32 NetMask;
+ } RCsetipandmask; /* <---- RCsetipandmask */
+
/* GETMAC structure */
#define MAC_SIZE 10
struct RCgetmac_tag {
U8 mac[MAC_SIZE];
} RCgetmac; /* <---- RCgetmac */
+ /* SETMAC structure */
+ struct RCsetmac_tag {
+ U8 mac[MAC_SIZE];
+ } RCsetmac; /* <---- RCsetmac */
+
/* GETLINKSTATUS structure */
struct RCgetlnkstatus_tag {
U32 ReturnStatus;
@@ -166,35 +202,56 @@
union RC_user_data_tag { /* structure tags used are taken from RC_user_tag structure above */
struct RCgetinfo_tag *getinfo;
struct RCgetspeed_tag *getspeed;
+ struct RCgetprom_tag *getprom;
+ struct RCgetbroadcast_tag *getbroadcast;
struct RCgetfwver_tag *getfwver;
struct RCgetipnmask_tag *getipandmask;
struct RCgetmac_tag *getmac;
struct RCgetlnkstatus_tag *getlinkstatus;
struct RCgetlinkstats_tag *getlinkstatistics;
struct RCdefault_tag *rcdefault;
+ struct RCsetspeed_tag *setspeed;
+ struct RCsetprom_tag *setprom;
+ struct RCsetbroadcast_tag *setbroadcast;
+ struct RCsetipnmask_tag *setipandmask;
+ struct RCsetmac_tag *setmac;
} _RC_user_data; /* declare as a global, so the defines below will work */
/* 3) Structure short-cut entry */
/* define structure short-cuts */ /* structure names are taken from RC_user_tag structure above */
#define RCUS_GETINFO data.RCgetinfo;
#define RCUS_GETSPEED data.RCgetspeed;
+#define RCUS_GETPROM data.RCgetprom;
+#define RCUS_GETBROADCAST data.RCgetbroadcast;
#define RCUS_GETFWVER data.RCgetfwver;
#define RCUS_GETIPANDMASK data.RCgetipandmask;
#define RCUS_GETMAC data.RCgetmac;
#define RCUS_GETLINKSTATUS data.RCgetlnkstatus;
#define RCUS_GETLINKSTATISTICS data.RCgetlinkstats;
#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;
/* 4) Data short-cut entry */
/* define data short-cuts */ /* pointer names are from RC_user_data_tag union (just below RC_user_tag) */
#define RCUD_GETINFO _RC_user_data.getinfo
#define RCUD_GETSPEED _RC_user_data.getspeed
+#define RCUD_GETPROM _RC_user_data.getprom
+#define RCUD_GETBROADCAST _RC_user_data.getbroadcast
#define RCUD_GETFWVER _RC_user_data.getfwver
#define RCUD_GETIPANDMASK _RC_user_data.getipandmask
#define RCUD_GETMAC _RC_user_data.getmac
#define RCUD_GETLINKSTATUS _RC_user_data.getlinkstatus
#define RCUD_GETLINKSTATISTICS _RC_user_data.getlinkstatistics
#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
/* 5) Command identifier entry */
/* define command identifiers */
@@ -205,7 +262,14 @@
#define RCUC_GETMAC 0x05
#define RCUC_GETLINKSTATUS 0x06
#define RCUC_GETLINKSTATISTICS 0x07
+#define RCUC_GETPROM 0x14
+#define RCUC_GETBROADCAST 0x15
#define RCUC_DEFAULT 0xff
+#define RCUC_SETSPEED 0x08
+#define RCUC_SETIPANDMASK 0x09
+#define RCUC_SETMAC 0x0a
+#define RCUC_SETPROM 0x16
+#define RCUC_SETBROADCAST 0x17
/* define ioctl commands to use, when talking to RC 45/PCI driver */
#define RCU_PROTOCOL_REV SIOCDEVPRIVATE
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/rclanmtl.c linux/drivers/net/rclanmtl.c
--- linux.vanilla/drivers/net/rclanmtl.c Thu Jan 1 01:00:00 1970
+++ linux/drivers/net/rclanmtl.c Fri Jan 29 14:03:56 1999
@@ -0,0 +1,2307 @@
+/*
+** *************************************************************************
+**
+**
+** R C L A N M T L . C $Revision: 5 $
+**
+**
+** 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.
+** *************************************************************************
+*/
+
+#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 1
+
+ /* 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)
+{
+ 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/rclanmtl.h linux/drivers/net/rclanmtl.h
--- linux.vanilla/drivers/net/rclanmtl.h Thu Jan 1 01:00:00 1970
+++ linux/drivers/net/rclanmtl.h Fri Jan 29 14:03:56 1999
@@ -0,0 +1,637 @@
+/*
+** *************************************************************************
+**
+**
+** R C L A N M T L . H $Revision: 5 $
+**
+**
+** 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
+#else
+#include
+#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 buffer reference
+** +-----------------------+
+** | 1 | one segment buffer
+** +-----------------------+ _
+** | | size \
+** +-----------------------+ \ segment descriptor
+** | | 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/rcmtl.c linux/drivers/net/rcmtl.c
--- linux.vanilla/drivers/net/rcmtl.c Sun Dec 6 00:14:40 1998
+++ linux/drivers/net/rcmtl.c Thu Jan 1 01:00:00 1970
@@ -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 */
-#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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/rcmtl.h linux/drivers/net/rcmtl.h
--- linux.vanilla/drivers/net/rcmtl.h Sun Dec 6 00:14:40 1998
+++ linux/drivers/net/rcmtl.h Thu Jan 1 01:00:00 1970
@@ -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
-** (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
-#else
-#include
-#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 buffer reference
-** +-----------------------+
-** | 1 | one segment buffer
-** +-----------------------+ _
-** | | size \
-** +-----------------------+ \ segment descriptor
-** | | 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/rcpci45.c linux/drivers/net/rcpci45.c
--- linux.vanilla/drivers/net/rcpci45.c Sun Dec 6 00:14:40 1998
+++ linux/drivers/net/rcpci45.c Fri Jan 29 14:03:29 1999
@@ -4,7 +4,7 @@
**
**
** ---------------------------------------------------------------------
-** --- Copyright (c) 1998, RedCreek Communications Inc. ---
+** --- Copyright (c) 1998, 1999, RedCreek Communications Inc. ---
** --- All rights reserved. ---
** ---------------------------------------------------------------------
**
@@ -12,14 +12,13 @@
**
** Known Problems
**
-** Billions and Billions...
-**
-** ... apparently added by Brian. Pete knows of no bugs.
+** None known at this time.
**
** TODO:
** -Get rid of the wait loops in the API and replace them
** 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.
**
** 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
@@ -35,20 +34,22 @@
** along with this program; if not, write to the Free Software
** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
**
+**
+** Pete Popov, January 11,99: Fixed a couple of 2.1.x problems
+** (virt_to_bus() not called), tested it under 2.2pre5, and added a
+** #define 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.
+**
***************************************************************************/
-#define __NO_VERSION__ /* don't define kernel_verion in module.h */
-
static char *version =
-"RedCreek Communications PCI linux driver version 1.32 Beta\n";
+"RedCreek Communications PCI linux driver version 2.00\n";
-#include
#include
#include
-
-static char kernel_version [] = UTS_RELEASE;
-
#include
#include
#include
@@ -65,25 +66,34 @@
#include
#include
+#if LINUX_VERSION_CODE >= 0x020100
+#define LINUX_2_1
+#endif
+
+#ifdef LINUX_2_1
+#include
+#endif
+
#include
#include
#include
#include
+
#define RC_LINUX_MODULE
-#include "rcmtl.h"
+#include "rclanmtl.h"
#include "rcif.h"
#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)
#define NEW_MULTICAST
#include
+#ifndef LINUX_2_1
+#define ioremap vremap
+#define iounmap vfree
+#endif
+
/* PCI/45 Configuration space values */
#define RC_PCI45_VENDOR_ID 0x4916
#define RC_PCI45_DEVICE_ID 0x1960
@@ -111,25 +121,25 @@
typedef struct
{
- /*
- * 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;
- 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 */
}
DPA, *PDPA;
@@ -138,10 +148,10 @@
static PDPA PCIAdapters[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
+ 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
};
@@ -173,258 +183,258 @@
int rcpci_probe(struct netdevice *dev)
#endif
{
- int cards_found;
+ int cards_found;
- printk(version);
+ printk(version);
- root_RCdev = NULL;
- cards_found = RCscan();
-#ifdef MODULE
- return cards_found ? 0 : -ENODEV;
+ root_RCdev = NULL;
+ cards_found = RCscan();
+#ifdef MODULE
+ return cards_found ? 0 : -ENODEV;
#else
- return -1;
-#endif
+ return -1;
+#endif
}
-static int RCscan(void)
+static int RCscan()
{
- int cards_found = 0;
- struct device *dev = 0;
+ int cards_found = 0;
+ struct device *dev = 0;
- 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");
- }
+ 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
-
- /*
- * 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");
+#if 1
+ if (check_region(pci_ioaddr, 2*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)) {
+ 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;
- }
+ 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;
+ 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;
}
static struct device *
RCfound_device(struct device *dev, int memaddr, int irq,
int bus, int function, int product_index, int card_idx)
{
- 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.
+ */
+ dev = (struct device *) kmalloc(dev_size, GFP_DMA | GFP_KERNEL |GFP_ATOMIC);
+ memset(dev, 0, dev_size);
#ifdef RCDEBUG
- printk("rc: dev = 0x%08X\n", (uint)dev);
+ printk("rc: dev = 0x%08X\n", (uint)dev);
#endif
- /*
- * 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);
+ /*
+ * 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 RCInitI2OMsgLayer().
+ */
+ pDpa->PLanApiPA = (void *)(((long)pDpa + sizeof(DPA) + 0xff) & ~0xff);
#ifdef RCDEBUG
- printk("rc: pDpa->PLanApiPA = 0x%x\n", (uint)pDpa->PLanApiPA);
+ printk("rc: pDpa->PLanApiPA = 0x%x\n", (uint)pDpa->PLanApiPA);
#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);
+ /* 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 0;
+ }
+
+ 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);
#ifdef RCDEBUG
- printk("rc: RCfound_device: 0x%x, priv = 0x%x, vaddr = 0x%x\n",
- (uint)dev, (uint)dev->priv, (uint)vaddr);
+ printk("rc: I2O msg initted: status = 0x%x\n", init_status);
#endif
- dev->base_addr = (unsigned long)vaddr;
- dev->irq = irq;
- dev->interrupt = 0;
+ if (init_status)
+ {
+ printk("rc: Unable to initialize msg layer\n");
+ free_irq(dev->irq, dev);
+ iounmap(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);
+ iounmap(vaddr);
+ kfree(dev);
+ return 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 );
- 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;
+ 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);
+ iounmap(vaddr);
+ kfree(dev);
+ return 0;
+ }
+ return dev;
}
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;
+ 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
@@ -438,25 +448,25 @@
#ifdef RCDEBUG
printk("rc: RCopen\n");
#endif
- RCEnableAdapterInterrupts(pDpa->id);
+ RCEnableI2OInterrupts(pDpa->id);
if (pDpa->nexus)
{
- /* 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.
+ */
printk("rc: Waking up adapter...\n");
RCResetLANCard(pDpa->id,0,0,0);
}
else
{
- pDpa->nexus = 1;
+ pDpa->nexus = 1;
}
while(post_buffers)
@@ -469,19 +479,19 @@
if ( count < requested )
{
- /*
- * 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 */
}
else
- post_buffers -= count;
+ post_buffers -= count;
}
pDpa->numOutRcvBuffers = MAX_NMBR_RCV_BUFFERS - post_buffers;
pDpa->shutdown = 0; /* just in case */
@@ -496,68 +506,69 @@
RC_xmit_packet(struct sk_buff *skb, struct device *dev)
{
- 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;
- if (dev->tbusy || pDpa->shutdown || pDpa->reboot)
- {
+ if (dev->tbusy || pDpa->shutdown || pDpa->reboot)
+ {
#ifdef RCDEBUG
- printk("rc: RC_xmit_packet: tbusy!\n");
+ printk("rc: RC_xmit_packet: tbusy!\n");
#endif
- return 1;
- }
+ return 1;
+ }
- 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;
}
/*
* RCxmit_callback()
*
- * The transmit callback routine. It's called by RCProcMsgQ()
+ * The transmit callback routine. It's called by RCProcI2OMsgQ()
* because the adapter is done with one or more transmit buffers and
* it's returning them to us, or we asked the adapter to return the
* outstanding transmit buffers by calling RCResetLANCard() with
@@ -574,80 +585,84 @@
PDPA pDpa;
struct device *dev;
- 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;
// 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);
+ }
#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");
#endif
#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);
#endif
- while (PcktCount--)
- {
- skb = (struct sk_buff *)(BufferContext[0]);
+ while (PcktCount--)
+ {
+ skb = (struct sk_buff *)(BufferContext[0]);
#ifdef RCDEBUG
- printk("rc: skb = 0x%x\n", (uint)skb);
+ printk("rc: skb = 0x%x\n", (uint)skb);
#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;
}
static void
RCreset_callback(U32 Status, U32 p1, U32 p2, U16 AdapterID)
{
- PDPA pDpa;
- struct device *dev;
+ PDPA pDpa;
+ struct device *dev;
- pDpa = PCIAdapters[AdapterID];
- dev = pDpa->dev;
+ pDpa = PCIAdapters[AdapterID];
+ dev = pDpa->dev;
#ifdef RCDEBUG
- printk("rc: RCreset_callback Status 0x%x\n", (uint)Status);
+ printk("rc: RCreset_callback Status 0x%x\n", (uint)Status);
#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((30*HZ)/10); /* 3 sec. */
+ pDpa->timer.data = (unsigned long)dev;
+ pDpa->timer.function = &rc_timer; /* timer handler */
+ add_timer(&pDpa->timer);
+ }
@@ -656,33 +671,33 @@
static void
RCreboot_callback(U32 Status, U32 p1, U32 p2, U16 AdapterID)
{
- PDPA pDpa;
+ PDPA pDpa;
- pDpa = PCIAdapters[AdapterID];
+ pDpa = PCIAdapters[AdapterID];
#ifdef RCDEBUG
- printk("rc: RCreboot: rcv buffers outstanding = %d\n",
- (uint)pDpa->numOutRcvBuffers);
+ printk("rc: RCreboot: rcv buffers outstanding = %d\n",
+ (uint)pDpa->numOutRcvBuffers);
#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
+ * 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);
}
@@ -699,7 +714,7 @@
* RCrecv_callback()
*
* 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
* filled (one ethernet packet per buffer).
*/
static void
@@ -710,134 +725,144 @@
U16 AdapterID)
{
- 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;
- pDpa = PCIAdapters[AdapterID];
- dev = pDpa->dev;
+ pDpa = PCIAdapters[AdapterID];
+ dev = pDpa->dev;
- ptcb->bcount = 1;
+ ptcb->bcount = 1;
#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);
#endif
#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);
#endif
- 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.
+ */
- 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);
+ 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 == 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--)
+ {
skb = (struct sk_buff *)PacketDescBlock[0];
+#ifndef LINUX_2_1
+ skb->free = 1;
+ skb->lock = 0;
+#endif
#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
- if ( (memcmp(dev->dev_addr, skb->data, 6)) &&
- (!broadcast_packet(skb->data)))
+#ifdef LINUX_2_1
+ dev_kfree_skb (skb);
+#else
+ dev_kfree_skb(skb, FREE_READ);
+#endif
+ 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
+ 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)
{
- /*
- * 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
}
else
{
- 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++;
}
- pDpa->numOutRcvBuffers--;
- PacketDescBlock += BD_SIZE; /* point to next context field */
- }
- }
+ }
+ else
+ {
+ 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 */
+ }
+ }
- /*
- * 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;
+ }
}
@@ -846,156 +871,156 @@
*
* Interrupt handler.
* 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
* calls one of our callback functions.
*/
static void
RCinterrupt(int irq, void *dev_id, struct pt_regs *regs)
{
- PDPA pDpa;
- struct device *dev = (struct device *)(dev_id);
+ PDPA pDpa;
+ struct device *dev = (struct device *)(dev_id);
- pDpa = (PDPA) (dev->priv);
+ pDpa = (PDPA) (dev->priv);
- if (pDpa->shutdown)
- printk("rc: shutdown: service irq\n");
+ if (pDpa->shutdown)
+ printk("rc: shutdown: service irq\n");
#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);
+ 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);
#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;
- RCProcMsgQ(pDpa->id);
- dev->interrupt = 0;
+ RCProcI2OMsgQ(pDpa->id);
+ dev->interrupt = 0;
- return;
+ return;
}
#define REBOOT_REINIT_RETRY_LIMIT 10
static void rc_timer(unsigned long data)
{
- 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, pDpa->PLanApiPA,
+ (PFNTXCALLBACK)RCxmit_callback,
+ (PFNRXCALLBACK)RCrecv_callback,
+ (PFNCALLBACK)RCreboot_callback);
+
+ switch(init_status)
+ {
+ case RC_RTN_NO_ERROR:
- 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");
+ 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");
+ 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((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");
+ }
}
static int
RCclose(struct device *dev)
{
- PDPA pDpa = (PDPA) dev->priv;
+ PDPA pDpa = (PDPA) dev->priv;
#ifdef RCDEBUG
- printk("rc: RCclose\r\n");
+ printk("rc: RCclose\r\n");
#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;
+ }
#ifdef RCDEBUG
- printk("rc: receive buffers outstanding: %d\n",
- (uint)pDpa->numOutRcvBuffers);
+ printk("rc: receive buffers outstanding: %d\n",
+ (uint)pDpa->numOutRcvBuffers);
#endif
- pDpa->shutdown = 1;
+ pDpa->shutdown = 1;
- /*
- * 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.
+ */
- 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);
- dev->flags &= ~IFF_UP;
- return 0;
+ dev->flags &= ~IFF_UP;
+ return 0;
}
static struct enet_statistics *
@@ -1097,236 +1122,298 @@
switch (cmd) {
- 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;
- 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
#ifdef RCDEBUG
- printk("RCioctl: RCuser_cmd = 0x%x\n", RCuser.cmd);
+ printk("RCioctl: RCuser_cmd = 0x%x\n", RCuser.cmd);
#endif
- 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))
{
- 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;
}
- 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);
break;
- } /* RCU_COMMAND */
-
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;
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;
}
return 0;
}
static int RCconfig(struct device *dev, struct ifmap *map)
{
- /*
- * To be completed ...
+ /*
+ * To be completed ...
*/
- 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;
/* 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;
}
-#ifdef MODULE
-void cleanup_module(void)
+void
+cleanup_module(void)
{
- PDPA pDpa;
- struct device *next;
+ PDPA pDpa;
+ struct device *next;
#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);
#endif
- while (root_RCdev)
- {
- pDpa = (PDPA) root_RCdev->priv;
+ while (root_RCdev)
+ {
+ pDpa = (PDPA) root_RCdev->priv;
#ifdef RCDEBUG
- printk("rc: cleanup 0x%08X\n", (uint)root_RCdev);
+ printk("rc: cleanup 0x%08X\n", (uint)root_RCdev);
#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;
+ }
}
-#endif
-
static int
RC_allocate_and_post_buffers(struct device *dev, int numBuffers)
{
- 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)
+ {
#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");
#endif
- numBuffers = 32;
- }
+ numBuffers = 32;
+ }
- p = (PU32) kmalloc(sizeof(U32) + numBuffers*sizeof(singleB), GFP_ATOMIC);
+ p = (PU32) kmalloc(sizeof(U32) + numBuffers*sizeof(singleB), GFP_ATOMIC);
+
+#ifdef RCDEBUG
+ printk("rc: TCB = 0x%x\n", (uint)p);
+#endif
+
+ 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: TCB = 0x%x\n", (uint)p);
+ 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
- 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; icontext = (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 */
+ for (i=0; icontext = (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 */
}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/rtl8139.c linux/drivers/net/rtl8139.c
--- linux.vanilla/drivers/net/rtl8139.c Sun Dec 6 00:14:40 1998
+++ linux/drivers/net/rtl8139.c Sun Dec 6 03:40:04 1998
@@ -20,11 +20,22 @@
*/
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";
/* A few user-configurable values. */
/* 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};
/* Size of the in-memory receive ring. */
#define RX_BUF_LEN_IDX 3 /* 0==8K, 1==16K, 2==32K, 3==64K */
@@ -39,12 +50,13 @@
/* The following settings are log_2(bytes)-4: 0 == 16 bytes .. 6==1024. */
#define RX_FIFO_THRESH 4 /* Rx buffer level before first PCI xfer. */
#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<
#ifdef MODULE
#ifdef MODVERSIONS
#include
@@ -60,40 +72,49 @@
#include
#include
#include
-#include
#include
#include
#include
#include
#include
-#include
+#include
+#include
+#include
#include /* Processor type for cache alignment. */
#include
#include
-#include
-#include
-#include
-#include
+/* Kernel compatibility defines, some common to David Hind's PCMCIA package.
+ This is only in the support-all-kernels source code. */
#define RUN_AT(x) (jiffies + (x))
#include
-#if (LINUX_VERSION_CODE < 0x20123)
+#if LINUX_VERSION_CODE < 0x20123
#define test_and_set_bit(val, addr) set_bit(val, addr)
#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
+#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
/* The I/O extent. */
#define RTL8129_TOTAL_SIZE 0x80
-#ifdef HAVE_DEVLIST
-struct netdev_entry rtl8139_drv =
-{"RTL8139", rtl8139_probe, RTL8129_TOTAL_SIZE, NULL};
-#endif
-
-static int rtl8129_debug = 1;
-
/*
Theory of Operation
@@ -139,16 +160,45 @@
IVc. Errata
*/
+
+
+/* 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,
+};
-#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
/* The rest of these values should never change. */
#define NUM_TX_DESC 4 /* Number of Tx descriptor registers. */
@@ -157,7 +207,7 @@
enum RTL8129_registers {
MAC0=0, /* Ethernet hardware address. */
MAR0=8, /* Multicast filter. */
- TxStat0=0x10, /* Transmit status (Four 32bit registers). */
+ TxStatus0=0x10, /* Transmit status (Four 32bit registers). */
TxAddr0=0x20, /* Tx descriptors (also four 32bit). */
RxBuf=0x30, RxEarlyCnt=0x34, RxEarlyStatus=0x36,
ChipCmd=0x37, RxBufPtr=0x38, RxBufAddr=0x3A,
@@ -168,7 +218,8 @@
Cfg9346=0x50, Config0=0x51, Config1=0x52,
FlashReg=0x54, GPPinData=0x58, GPPinDir=0x59, MII_SMI=0x5A, HltClk=0x5B,
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,
/* Undocumented registers, but required for proper operation. */
FIFOTMS=0x70, /* FIFO Test Mode Select */
CSCR=0x74, /* Chip Status and Configuration Register. */
@@ -214,24 +265,24 @@
struct device *next_module;
int chip_id;
int chip_revision;
+ unsigned char pci_bus, pci_devfn;
#if LINUX_VERSION_CODE > 0x20139
struct net_device_stats stats;
#else
struct enet_statistics stats;
#endif
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;
/* The saved address of a sent-in-place packet/buffer, for skfree(). */
struct sk_buff* tx_skbuff[NUM_TX_DESC];
unsigned char *tx_buf[NUM_TX_DESC]; /* Tx bounce buffers */
unsigned char *rx_ring;
unsigned char *tx_bufs; /* Tx bounce buffer region. */
- unsigned char mc_filter[8]; /* Current multicast filter. */
char phys[4]; /* MII device addresses. */
- int in_interrupt; /* Alpha needs word-wide lock. */
unsigned int tx_full:1; /* The Tx queue is full. */
unsigned int full_duplex:1; /* Full-duplex operation requested. */
+ unsigned int duplex_lock:1; /* Full-duplex operation requested. */
unsigned int default_port:4; /* Last dev->if_port value. */
unsigned int media2:4; /* Secondary monitored media port. */
unsigned int medialock:1; /* Don't sense media type. */
@@ -239,24 +290,21 @@
};
#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
MODULE_AUTHOR("Donald Becker ");
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");
MODULE_PARM(max_interrupt_work, "i");
+MODULE_PARM(debug, "i");
#endif
#endif
-static struct device *rtl8129_probe1(struct device *dev, int ioaddr, int irq,
- int chip_id, int options, int card_idx);
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);
static void rtl8129_timer(unsigned long data);
static void rtl8129_tx_timeout(struct device *dev);
static void rtl8129_init_ring(struct device *dev);
@@ -264,145 +312,138 @@
static int rtl8129_rx(struct device *dev);
static void rtl8129_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
static int rtl8129_close(struct device *dev);
+static int mii_ioctl(struct device *dev, struct ifreq *rq, int cmd);
static struct enet_statistics *rtl8129_get_stats(struct device *dev);
+static inline u32 ether_crc(int length, unsigned char *data);
static void set_rx_mode(struct device *dev);
-#ifdef MODULE
/* A list of all installed RTL8129 devices, for removing the driver module. */
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. */
int rtl8139_probe(struct device *dev)
{
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;
- /* 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;
- 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)
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;
- 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;
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);
- /* 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
+ }
- /* 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);
+ }
-#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);
- 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);
}
}
+ dev = 0;
+ cards_found++;
}
-#if defined (MODULE)
- return cards_found;
-#else
return cards_found ? 0 : -ENODEV;
-#endif
}
-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)
{
static int did_version = 0; /* Already printed version info. */
struct rtl8129_private *tp;
- int i;
+ int i, option = found_cnt < MAX_UNITS ? options[found_cnt] : 0;
if (rtl8129_debug > 0 && did_version++ == 0)
printk(KERN_INFO "%s", version);
dev = init_etherdev(dev, 0);
- 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);
/* Bring the chip out of low-power mode. */
outb(0x00, ioaddr + Config1);
- /* 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);
for (i = 0; i < 5; i++)
printk("%2.2x:", dev->dev_addr[i]);
printk("%2.2x.\n", dev->dev_addr[i]);
- 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 : "");
- }
-
/* 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);
dev->base_addr = ioaddr;
dev->irq = irq;
@@ -412,22 +453,21 @@
memset(tp, 0, sizeof(*tp));
dev->priv = tp;
-#ifdef MODULE
tp->next_module = root_rtl8129_dev;
root_rtl8129_dev = dev;
-#endif
- tp->chip_id = chip_id;
+ tp->chip_id = chip_idx;
+ tp->pci_bus = pci_bus;
+ tp->pci_devfn = pci_devfn;
/* Find the connected MII xcvrs.
Doing this in open() would allow detecting external xcvrs later, but
takes too much time. */
- if (chip_id == 0x8129) {
+ if (rtl_cap_tbl[chip_idx] & HAS_MII_XCVR) {
int phy, phy_idx;
for (phy = 0, phy_idx = 0; phy < 32 && phy_idx < sizeof(tp->phys);
phy++) {
- int mii_status = mdio_read(ioaddr, phy, 1);
-
+ int mii_status = mdio_read(dev, phy, 1);
if (mii_status != 0xffff && mii_status != 0x0000) {
tp->phys[phy_idx++] = phy;
printk(KERN_INFO "%s: MII transceiver found at address %d.\n",
@@ -441,7 +481,7 @@
tp->phys[0] = -1;
}
} else {
- tp->phys[0] = -1;
+ tp->phys[0] = 32;
}
/* Put the chip into low-power mode. */
@@ -450,18 +490,21 @@
outb('H', ioaddr + HltClk); /* 'R' would leave the clock running. */
/* 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;
if (tp->default_port)
tp->medialock = 1;
}
-#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;
}
-#endif
/* The Rtl8129-specific entries in the device structure. */
dev->open = &rtl8129_open;
@@ -469,6 +512,7 @@
dev->stop = &rtl8129_close;
dev->get_stats = &rtl8129_get_stats;
dev->set_multicast_list = &set_rx_mode;
+ dev->do_ioctl = &mii_ioctl;
return dev;
}
@@ -485,25 +529,21 @@
#define EE_ENB (0x80 | EE_CS)
/* 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.
*/
-#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)
/* 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)
-static int read_eeprom(int ioaddr, int location)
+static int read_eeprom(long ioaddr, int location)
{
int i;
unsigned retval = 0;
- int ee_addr = ioaddr + Cfg9346;
+ long ee_addr = ioaddr + Cfg9346;
int read_cmd = location | EE_READ_CMD;
outb(EE_ENB & ~EE_CS, ee_addr);
@@ -513,20 +553,19 @@
for (i = 10; i >= 0; i--) {
int dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
outb(EE_ENB | dataval, ee_addr);
- eeprom_delay(100);
+ eeprom_delay();
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();
}
outb(EE_ENB, ee_addr);
+ eeprom_delay();
for (i = 16; i > 0; i--) {
outb(EE_ENB | EE_SHIFT_CLK, ee_addr);
- eeprom_delay(100);
+ eeprom_delay();
retval = (retval << 1) | ((inb(ee_addr) & EE_DATA_READ) ? 1 : 0);
outb(EE_ENB, ee_addr);
- eeprom_delay(100);
+ eeprom_delay();
}
/* Terminate the EEPROM access. */
@@ -544,38 +583,42 @@
#define MDIO_DATA_OUT 0x04
#define MDIO_DATA_IN 0x02
#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 };
/* Syncronize the MII management interface by shifting 32 one bits out. */
-static void mdio_sync(int ioaddr)
+static void mdio_sync(long mdio_addr)
{
int i;
- int mdio_addr = ioaddr + MII_SMI;
for (i = 32; i >= 0; i--) {
- outb(MDIO_DIR | MDIO_DATA_OUT, mdio_addr);
+ outb(MDIO_WRITE1, mdio_addr);
mdio_delay();
- outb(MDIO_DIR | MDIO_DATA_OUT | MDIO_CLK, mdio_addr);
+ outb(MDIO_WRITE1 | MDIO_CLK, mdio_addr);
mdio_delay();
}
return;
}
-static int mdio_read(int ioaddr, int phy_id, int location)
+static int mdio_read(struct device *dev, int phy_id, int location)
{
- 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;
int retval = 0;
- int mdio_addr = ioaddr + MII_SMI;
+ int i;
- 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);
/* Shift the read command bits out. */
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;
outb(MDIO_DIR | dataval, mdio_addr);
mdio_delay();
@@ -593,14 +636,45 @@
}
return (retval>>1) & 0xffff;
}
+
+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;
+}
+
static int
rtl8129_open(struct device *dev)
{
struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
- int ioaddr = dev->base_addr;
+ long ioaddr = dev->base_addr;
int i;
- int full_duplex = 0;
/* Soft reset the chip. */
outb(CmdReset, ioaddr + ChipCmd);
@@ -636,29 +710,26 @@
outl((RX_FIFO_THRESH << 13) | (RX_BUF_LEN_IDX << 11) | (RX_DMA_BURST<<8),
ioaddr + RxConfig);
outl((TX_DMA_BURST<<8)|0x03000000, ioaddr + TxConfig);
+ tp->tx_flag = (TX_FIFO_THRESH<<11) & 0x003f0000;
- 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);
if (mii_reg5 == 0xffff)
; /* Not there */
else if ((mii_reg5 & 0x0100) == 0x0100
|| (mii_reg5 & 0x00C0) == 0x0040)
- full_duplex = 1;
+ tp->full_duplex = 1;
if (rtl8129_debug > 1)
printk(KERN_INFO"%s: Setting %s%s-duplex based on"
" auto-negotiated partner ability %4.4x.\n", dev->name,
mii_reg5 == 0 ? "" :
(mii_reg5 & 0x0180) ? "100mbps " : "10mbps ",
- full_duplex ? "full" : "half", mii_reg5);
+ tp->full_duplex ? "full" : "half", mii_reg5);
}
outb(0xC0, ioaddr + Cfg9346);
- outb(full_duplex ? 0x60 : 0x20, ioaddr + Config1);
+ outb(tp->full_duplex ? 0x60 : 0x20, ioaddr + Config1);
outb(0x00, ioaddr + Cfg9346);
outl(virt_to_bus(tp->rx_ring), ioaddr + RxBuf);
@@ -678,10 +749,10 @@
| TxErr | TxOK | RxErr | RxOK, ioaddr + IntrMask);
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"
" GP Pins %2.2x %s-duplex.\n",
dev->name, ioaddr, dev->irq, inb(ioaddr + GPPinData),
- full_duplex ? "full" : "half");
+ tp->full_duplex ? "full" : "half");
/* Set the timer to switch to check for link beat and perhaps switch
to an alternate media type. */
@@ -698,26 +769,26 @@
{
struct device *dev = (struct device *)data;
struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
- int ioaddr = dev->base_addr;
+ long ioaddr = dev->base_addr;
int next_tick = 0;
+ int mii_reg5 = mdio_read(dev, tp->phys[0], 5);
- 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;
}
+
if (rtl8129_debug > 2) {
- if (tp->chip_id == 0x8129)
+ if (rtl_cap_tbl[tp->chip_id] & HAS_MII_XCVR)
printk(KERN_DEBUG"%s: Media selection tick, GP pins %2.2x.\n",
dev->name, inb(ioaddr + GPPinData));
else
@@ -740,41 +811,51 @@
static void rtl8129_tx_timeout(struct device *dev)
{
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));
/* Disable interrupts by clearing the interrupt mask. */
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));
/* 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);
for (i = 0; i < NUM_TX_DESC; i++)
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),
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");
/* Soft reset the chip. */
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;
for (i = 0; i < 6; i++)
outb(dev->dev_addr[i], ioaddr + MAC0 + i);
+ 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);
{ /* Save the unsent Tx packets. */
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];
tp->dirty_tx = tp->cur_tx = 0;
for (i = 0; i < j; i++) {
@@ -785,27 +866,20 @@
} else
outl(virt_to_bus(skb->data), ioaddr + TxAddr0 + i*4);
/* 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);
}
tp->cur_tx = i;
while (i < NUM_TX_DESC)
tp->tx_skbuff[i] = 0;
if (tp->cur_tx - tp->dirty_tx < NUM_TX_DESC) {/* Typical path */
dev->tbusy = 0;
+ tp->tx_full = 0;
} else {
tp->tx_full = 1;
}
}
- /* 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);
-
dev->trans_start = jiffies;
tp->stats.tx_errors++;
/* Enable all known interrupts by setting the interrupt mask. */
@@ -823,8 +897,8 @@
int i;
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;
for (i = 0; i < NUM_TX_DESC; i++) {
tp->tx_skbuff[i] = 0;
@@ -836,7 +910,7 @@
rtl8129_start_xmit(struct sk_buff *skb, struct device *dev)
{
struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
- int ioaddr = dev->base_addr;
+ long ioaddr = dev->base_addr;
int entry;
/* Block a timer-based transmit from overlapping. This could better be
@@ -858,20 +932,19 @@
} else
outl(virt_to_bus(skb->data), ioaddr + TxAddr0 + entry*4);
/* 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);
if (++tp->cur_tx - tp->dirty_tx < NUM_TX_DESC) {/* Typical path */
- dev->tbusy = 0;
+ clear_bit(0, (void*)&dev->tbusy);
} else {
tp->tx_full = 1;
}
dev->trans_start = jiffies;
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);
return 0;
}
@@ -881,23 +954,26 @@
static void rtl8129_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
{
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;
int status;
+ long ioaddr = dev->base_addr;
- 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. */
return;
}
-
- ioaddr = dev->base_addr;
- tp = (struct rtl8129_private *)dev->priv;
- if (test_and_set_bit(0, (void*)&tp->in_interrupt)) {
+#else
+ if (dev->interrupt) {
printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name);
return;
}
dev->interrupt = 1;
+#endif
do {
status = inw(ioaddr + IntrStatus);
@@ -920,9 +996,9 @@
for (dirty_tx = tp->dirty_tx; dirty_tx < tp->cur_tx; dirty_tx++) {
int entry = dirty_tx % NUM_TX_DESC;
- int txstatus = inl(ioaddr + TxStat0 + entry*4);
+ int txstatus = inl(ioaddr + TxStatus0 + entry*4);
- if ( ! (txstatus & TxHostOwns))
+ if ( ! (txstatus & (TxStatOK | TxUnderrun | TxAborted)))
break; /* It still hasn't been Txed */
/* Note: TxCarrierLost is always asserted at 100mbps. */
@@ -949,7 +1025,9 @@
/* No count for tp->stats.tx_deferred */
#endif
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;
tp->stats.tx_fifo_errors++;
}
tp->stats.collisions += (txstatus >> 24) & 15;
@@ -960,7 +1038,7 @@
}
/* Free the original skb. */
- dev_kfree_skb(tp->tx_skbuff[entry], FREE_WRITE);
+ dev_free_skb(tp->tx_skbuff[entry]);
tp->tx_skbuff[entry] = 0;
}
@@ -972,8 +1050,7 @@
}
#endif
- 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) {
/* The ring is no longer full, clear tbusy. */
tp->tx_full = 0;
dev->tbusy = 0;
@@ -986,10 +1063,29 @@
/* Check uncommon events with one test. */
if (status & (PCIErr|PCSTimeout |RxUnderrun|RxOverflow|RxFIFOOver
|TxErr|RxErr)) {
+ if (rtl8129_debug > 2)
+ printk(KERN_NOTICE"%s: Abnormal interrupt, status %8.8x.\n",
+ dev->name, status);
+
+ if (status == 0xffffffff)
+ break;
/* Update the error count. */
tp->stats.rx_missed_errors += inl(ioaddr + RxMissed);
outl(0, ioaddr + RxMissed);
+ 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;
+ }
if (status & (RxUnderrun | RxOverflow | RxErr | RxFIFOOver))
tp->stats.rx_errors++;
@@ -1000,7 +1096,14 @@
tp->cur_rx = inw(ioaddr + RxBufAddr) % RX_BUF_LEN;
outw(tp->cur_rx - 16, ioaddr + RxBufPtr);
}
- /* 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);
+ }
}
if (--boguscnt < 0) {
printk(KERN_WARNING"%s: Too much work at interrupt, "
@@ -1016,18 +1119,20 @@
printk(KERN_DEBUG"%s: exiting interrupt, intr_status=%#4.4x.\n",
dev->name, inl(ioaddr + IntrStatus));
+#if defined(__i386__)
+ clear_bit(0, (void*)&dev->interrupt);
+#else
dev->interrupt = 0;
- clear_bit(0, (void*)&tp->in_interrupt);
+#endif
return;
}
/* The data sheet doesn't describe the Rx ring at all, so I'm guessing at the
field alignments and semantics. */
-static int
-rtl8129_rx(struct device *dev)
+static int rtl8129_rx(struct device *dev)
{
struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
- int ioaddr = dev->base_addr;
+ long ioaddr = dev->base_addr;
unsigned char *rx_ring = tp->rx_ring;
u16 cur_rx = tp->cur_rx;
@@ -1103,9 +1208,16 @@
printk(".\n");
memset(rx_ring, 0xcc, 16);
}
- } 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
memcpy(skb_put(skb, rx_size), &rx_ring[ring_offset + 4],
rx_size);
+#endif
+ }
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb);
#if LINUX_VERSION_CODE > 0x20119
@@ -1114,8 +1226,7 @@
tp->stats.rx_packets++;
}
- cur_rx += rx_size + 4;
- cur_rx = (cur_rx + 3) & ~3;
+ cur_rx = (cur_rx + rx_size + 4 + 3) & ~3;
outw(cur_rx - 16, ioaddr + RxBufPtr);
}
if (rtl8129_debug > 4)
@@ -1130,7 +1241,7 @@
static int
rtl8129_close(struct device *dev)
{
- int ioaddr = dev->base_addr;
+ long ioaddr = dev->base_addr;
struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
int i;
@@ -1157,7 +1268,7 @@
for (i = 0; i < NUM_TX_DESC; i++) {
if (tp->tx_skbuff[i])
- dev_kfree_skb(tp->tx_skbuff[i], FREE_WRITE);
+ dev_free_skb(tp->tx_skbuff[i]);
tp->tx_skbuff[i] = 0;
}
kfree(tp->rx_ring);
@@ -1173,11 +1284,33 @@
return 0;
}
+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;
+ }
+}
+
static struct enet_statistics *
rtl8129_get_stats(struct device *dev)
{
struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
- int ioaddr = dev->base_addr;
+ long ioaddr = dev->base_addr;
if (dev->start) {
tp->stats.rx_missed_errors += inl(ioaddr + RxMissed);
@@ -1188,88 +1321,69 @@
}
/* 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)
{
- unsigned int crc = 0xffffffff; /* Initial value. */
- while(--length >= 0) {
+ int crc = -1;
+
+ while(--length >= 0) {
unsigned char current_octet = *data++;
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;
}
+/* Bits in RxConfig. */
+enum rx_mode_bits {
+ AcceptErr=0x20, AcceptRunt=0x10, AcceptBroadcast=0x08,
+ AcceptMulticast=0x04, AcceptMyPhys=0x02, AcceptAllPhys=0x01,
+};
+
static void set_rx_mode(struct device *dev)
{
- 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;
- 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) {
/* Unconditionally log net taps. */
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)) {
/* 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;
} else {
struct dev_mc_list *mclist;
-
- memset(mc_filter, 0, sizeof(mc_filter));
+ rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
+ mc_filter[1] = mc_filter[0] = 0;
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) & 0x3f,
- mc_filter);
+ set_bit(ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26, mc_filter);
}
- /* 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);
return;
}
#ifdef MODULE
-
-/* An additional parameter that may be passed in... */
-static int debug = -1;
-
-int
-init_module(void)
+int init_module(void)
{
- 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);
}
void
@@ -1279,9 +1393,13 @@
/* No need to check MOD_IN_USE, as sys_delete_module() checks. */
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;
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);
kfree(root_rtl8129_dev);
root_rtl8129_dev = next_dev;
}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sdla.c linux/drivers/net/sdla.c
--- linux.vanilla/drivers/net/sdla.c Sun Jun 21 18:41:06 1998
+++ linux/drivers/net/sdla.c Mon Dec 14 18:34:34 1998
@@ -452,7 +452,7 @@
save_flags(pflags);
cli();
SDLA_WINDOW(dev, window);
- waiting = ((volatile)(cmd_buf->opp_flag));
+ waiting = ((volatile int)(cmd_buf->opp_flag));
restore_flags(pflags);
}
}
@@ -566,11 +566,12 @@
flp->dlci[i] = -*(short *)(master->dev_addr);
master->mtu = slave->mtu;
- if (slave->start)
+ if (slave->start) {
if (flp->config.station == FRAD_STATION_CPE)
sdla_reconfig(slave);
else
sdla_cmd(slave, SDLA_ADD_DLCI, 0, 0, master->dev_addr, sizeof(short), NULL, NULL);
+ }
return(0);
}
@@ -594,11 +595,12 @@
MOD_DEC_USE_COUNT;
- if (slave->start)
+ if (slave->start) {
if (flp->config.station == FRAD_STATION_CPE)
sdla_reconfig(slave);
else
sdla_cmd(slave, SDLA_DELETE_DLCI, 0, 0, master->dev_addr, sizeof(short), NULL, NULL);
+ }
return(0);
}
@@ -623,13 +625,14 @@
ret = SDLA_RET_OK;
len = sizeof(struct dlci_conf);
- if (slave->start)
+ if (slave->start) {
if (get)
ret = sdla_cmd(slave, SDLA_READ_DLCI_CONFIGURATION, abs(flp->dlci[i]), 0,
NULL, 0, &dlp->config, &len);
else
ret = sdla_cmd(slave, SDLA_SET_DLCI_CONFIGURATION, abs(flp->dlci[i]), 0,
&dlp->config, sizeof(struct dlci_conf) - 4 * sizeof(short), NULL, NULL);
+ }
return(ret == SDLA_RET_OK ? 0 : -EIO);
}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/skeleton.c linux/drivers/net/skeleton.c
--- linux.vanilla/drivers/net/skeleton.c Sun Jun 21 18:41:04 1998
+++ linux/drivers/net/skeleton.c Wed Dec 9 20:02:31 1998
@@ -362,15 +362,6 @@
dev->trans_start = jiffies;
}
/*
- * 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;
- }
- /*
* Block a timer-based transmit from overlapping. This could better be
* done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
*/
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/tulip.c linux/drivers/net/tulip.c
--- linux.vanilla/drivers/net/tulip.c Sun Dec 6 00:14:40 1998
+++ linux/drivers/net/tulip.c Fri Dec 11 20:18:43 1998
@@ -5,9 +5,9 @@
This software may be used and distributed according to the terms
of the GNU Public License, incorporated herein by reference.
- This driver is for the Digital "Tulip" ethernet adapter interface.
+ This driver is for the Digital "Tulip" Ethernet adapter interface.
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.
The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
Center of Excellence in Space Data and Information Sciences
@@ -18,7 +18,7 @@
*/
#define SMP_CHECK
-static const char version[] = "tulip.c:v0.89H 5/23/98 becker@cesdis.gsfc.nasa.gov\n";
+static const char version[] = "tulip.c:v0.90 10/20/98 becker@cesdis.gsfc.nasa.gov\n";
/* A few user-configurable values. */
@@ -63,14 +63,20 @@
/* Operational parameters that usually are not changed. */
/* Time in jiffies before concluding the transmitter is hung. */
#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
#include
+#include
#ifdef MODULE
#ifdef MODVERSIONS
#include
#endif
#include
-#include
#else
#define MOD_INC_USE_COUNT
#define MOD_DEC_USE_COUNT
@@ -80,87 +86,65 @@
#include
#include
#include
-#include
#include