Commit 4d178ac9 authored by Linus Torvalds's avatar Linus Torvalds

Linux 2.2.4

As of 2.2.4, I should be synchronized with the Sparc[64] and PPC ports,
which is the major reason why the patch is pretty huge. Apart from the
architecture synchronizations, 2.2.4 does:

 - dumping core over NFS could do bad things. Core-dumping cleaned up and
   fixed.

 - various small TCP/IP buglets fixed. Linux got confused by hosts that
   didn't report any mss, and had problems with zero-sized fragments, etc.

 - various small, often silly bugs fixed (PC BIOS PCI buglet, alpha
   semaphores, bottom half interrupts, fork() returns wrong error code).

 - tons of driver updates

 - updated net scheduling code (CONFIG_NET_SCHED)

Most of the fixes aren't all that noticeable, but some of them can be
showstoppers depending on whether you've ever seen them.
parent 7d4fc34b
......@@ -1769,7 +1769,7 @@ S: USA
N: Jaspreet Singh
E: jaspreet@sangoma.com
W: www.sangoma.com
D: WANPIPE driver for Sangoma S508/FT1 cards
D: WANPIPE drivers & API Support for Sangoma S508/FT1 cards
S: Sangoma Technologies Inc.,
S: 1001 Denison Street
S: Suite 101
......
......@@ -19,10 +19,6 @@ need to bother doing so in the form of a diff, as this is generated by
texinfo so a diff is useless anyway (though I can incorporate one by
hand if you insist upon sending it that way ;-).
Check out
http://www.mindspring.com/~nunez/info/linux/LinuxBleed.html for an
HTML-ized shopping list.
For those of you in Europe,
http://www.datanet.hu/generations/linux/Changes2.html is an
English-language HTML version.
......@@ -30,10 +26,14 @@ English-language HTML version.
The most current version should always be available from
http://cyberbuzz.gatech.edu/kaboom/linux/ as well.
Voir
http://www.linux-france.com/article/sys/Changes-2.2/Changes-2.2.1.html
pour la traduction français.
Also, don't forget http://www.linuxhq.com/ for all your Linux kernel
needs.
Last updated: January 18, 1999
Last updated: March 16, 1999
Current Author: Chris Ricker (kaboom@gatech.edu or chris.ricker@m.cc.utah.edu).
Current Minimal Requirements
......@@ -43,17 +43,17 @@ Current Minimal Requirements
encountered a bug! If you're unsure what version you're currently
running, the suggested command should tell you.
- Kernel modules 2.1.121 ; insmod -V
- Kernel modutils 2.1.121 ; insmod -V
- Gnu C 2.7.2.3 ; gcc --version
- Binutils 2.8.1.0.23 ; ld -v
- Linux libc5 C Library 5.4.46 ; ls -l /lib/libc.so.*
- Linux libc6 C Library 2.0.7pre6 ; ls -l /lib/libc.so.*
- Linux libc5 C Library 5.4.46 ; ls -l /lib/libc*
- Linux libc6 C Library 2.0.7pre6 ; ls -l /lib/libc*
- Dynamic Linker (ld.so) 1.9.9 ; ldd --version or ldd -v
- Linux C++ Library 2.7.2.8 ; ls -l /usr/lib/libg++.so.*
- Procps 1.2.9 ; ps --version
- Procinfo 15 ; procinfo -v
- Procinfo 16 ; procinfo -v
- Psmisc 17 ; pstree -V
- Net-tools 1.49 ; hostname -V
- Net-tools 1.50 ; hostname -V
- Loadlin 1.6a
- Sh-utils 1.16 ; basename --v
- Autofs 3.1.1 ; automount --version
......@@ -61,8 +61,8 @@ running, the suggested command should tell you.
- Bash 1.14.7 ; bash -version
- Ncpfs 2.2.0 ; ncpmount -v
- Pcmcia-cs 3.0.7 ; cardmgr -V
- PPP 2.3.5 ; pppd -v
- Util-linux 2.9g ; chsh -v
- PPP 2.3.5 ; pppd --version
- Util-linux 2.9i ; chsh -v
Upgrade notes
*************
......@@ -142,7 +142,9 @@ fixed in later releases. Please make sure you don't install ld.so-2.x
unless you're running glibc2 / libc6.
If you upgrade to libc-5.4.x, you may also need to upgrade ypbind if
you're using NIS.
you're using NIS. For ypbind and glibc, you'll probably need the
ypbind-3.3-glibc5.diff patch available in the same place as the ypbind
source.
If you upgrade to libc-5.4.46, please read and pay attention to its
accompanying release notes. The section about it breaking make is not a
......@@ -189,6 +191,12 @@ Either use binutils-2.8.1.0.23 or binutils-2.9.1.0.7 or later. Glibc2
users should especially try to use the 2.9.1.0.x releases, as they
resolve known issues with glibc2 and binutils-2.8.x releases.
libbfd, libiberty, and /usr/include/bfd.h, which are part of recent
binutils packages, are also required to compile ksymoops. Depending
upon your distribution, this may require you to install both binutils
and binutils-development packages (Debian puts bfd.h in binutils-dev,
for example).
Gnu C
=====
......@@ -247,7 +255,7 @@ available from http://juanjox.linuxhq.com/ .
DHCP clients for 2.0 do not work with the new networking code in the
2.2 kernel. You will need to upgrade your dhcpcd / dhcpclient.
The ISDN code in the stock 2.0 kernel may not work for you. If it
The ISDN code in the stock 2.2 kernel may not work for you. If it
doesn't, look in ftp://ftp.suse.com/pub/isdn4linux for updated versions.
Memory
......@@ -278,7 +286,7 @@ RPM
===
If you run Red Hat Linux or any other distribution that uses RPM,
you need to upgrade RPM to version 2.2.7 or later.
you need to upgrade RPM to a 2.5.x or later version.
DOSEMU
======
......@@ -324,7 +332,7 @@ Syncookies
When you build your kernel with Syncookie support
(CONFIG_SYN_COOKIES) the syncookie code still defaults to off (unlike
the 2.0.30+ behavior). You have to explicitly enable it by issuing the
following command: echo 1 > /proc/sys/net/ipv4/tcp_syncookies
following command: echo 1 > /proc/sys/net/ipv4/tcp_syncookies
Bash
====
......@@ -444,6 +452,30 @@ Ping
Most distributed ping clients are buggy. Get an updated one from the
iputils package.
Patch
=====
Really old versions of patch cannot delete files. This can be a
problem if you try to upgrade via patches. If, for example, you are
unable to compile Linux 2.2, you may have an outdated version of patch.
Upgrade, re-patch the kernel, and try again.
Process accounting
==================
If you use process accounting, you need to recompile the package
against 2.2 kernel includes for it to work properly. Furthermore, when
you do so, watch out for a quirky configure script. Your generated
config.h file needs to
#define HAVE_LINUX_ACCT_H
but instead it often has
/* #undef HAVE_LINUX_ACCT_H */
so be sure to check that when you recompile.
Where to get the files
**********************
......@@ -481,7 +513,7 @@ ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.egcs-1.0.3
ftp://metalab.unc.edu/pub/Linux/GCC/release.egcs-1.0.3
Gnu C 2.7.2.3 source:
ftp://prep.ai.mit.edu/pub/gnu/gcc-2.7.2.3.tar.gz
ftp://ftp.gnu.org/gnu/gcc/gcc-2.7.2.3.tar.gz
ftp://metalab.unc.edu/pub/gnu/gcc-2.7.2.3.tar.gz
Linux C Library
......@@ -501,12 +533,8 @@ ftp://ftp.kernel.org/pub/software/libs/glibc/glibc-2.0.7pre6.tar.bz2
Linux C++ Library
=================
The 2.7.2.8 release:
ftp://tsx-11.mit.edu/pub/linux/packages/GCC/libg++-2.7.2.8.bin.tar.gz
ftp://metalab.unc.edu/pub/Linux/GCC/libg++-2.7.2.8.bin.tar.gz
Installation notes:
ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.libg++-2.7.2.8
ftp://metalab.unc.edu/pub/Linux/GCC/release.libg++-2.7.2.8
The 2.7.2 release:
ftp://ftp.gnu.org/gnu/libg++/libg++-2.7.2.tar.gz
Dynamic Linker
==============
......@@ -531,8 +559,8 @@ ftp://metalab.unc.edu/pub/Linux/system/status/ps/procps-1.2.9.tgz
Procinfo utilities
==================
The 15 release:
ftp://ftp.cistron.nl/pub/people/svm/procinfo-15.tar.gz
The 16 release:
ftp://ftp.cistron.nl/pub/people/svm/procinfo-16.tar.gz
Psmisc utilities
================
......@@ -544,15 +572,9 @@ ftp://metalab.unc.edu/pub/Linux/system/status/ps/psmisc-17.tar.gz
RPM utilities
=============
The 2.2.7 release for Intel:
ftp://ftp.redhat.com/pub/redhat/old-releases/redhat-4.0/updates/i386/rpm-2.2.7-1.i386.rpm
ftp://ftp.redhat.com/pub/redhat/old-releases/redhat-4.0/updates/i386/rpm-devel-2.2.7-1.i386.rpm
The 2.2.7 release for Alpha:
ftp://ftp.redhat.com/pub/redhat/old-releases/redhat-4.0/updates/axp/rpm-2.2.7-1.axp.rpm
ftp://ftp.redhat.com/pub/redhat/old-releases/redhat-4.0/updates/axp/rpm-devel-2.2.7-1.axp.rpm
The 2.2.7 release for SPARC:
ftp://ftp.redhat.com/pub/redhat/old-releases/redhat-4.0/updates/sparc/rpm-2.2.7-1.sparc.rpm
ftp://ftp.redhat.com/pub/redhat/old-releases/redhat-4.0/updates/sparc/rpm-devel-2.2.7-1.sparc.rpm
The 2.5.1 source release:
ftp://ftp.rpm.org/pub/rpm/dist/rpm-2.5.x/rpm-2.5.1-1.src.rpm
ftp://ftp.rpm.org/pub/rpm/dist/rpm-2.5.x/rpm-2.5.1.tar.gz
DOSEMU
======
......@@ -573,26 +595,26 @@ Sh-utils
The 1.16 release:
ftp://metalab.unc.edu/pub/gnu/sh-utils-1.16.tar.gz
ftp://prep.ai.mit.edu/pub/gnu/sh-utils-1.16.tar.gz
ftp://ftp.gnu.org/gnu/sh-utils/sh-utils-1.16.tar.gz
Util-linux
==========
The 2.9 release:
ftp://ftp.win.tue.nl/pub/linux/utils/util-linux/util-linux-2.9g.tar.gz
ftp://ftp.win.tue.nl/pub/linux/utils/util-linux/util-linux-2.9i.tar.gz
Autofs
======
The 3.1.1 release:
ftp://ftp.kernel.org/pub/linux/daemons/autofs/autofs-3.1.1.tar.gz
The 3.1.3 release:
ftp://ftp.kernel.org/pub/linux/daemons/autofs/autofs-3.1.3.tar.gz
NFS
===
The user-land 2.2beta40 release:
ftp://ftp.mathematik.th-darmstadt.de/pub/linux/okir/nfs-server-2.2beta40.tar.gz
ftp://linux.nrao.edu/mirrors/fb0429.mathematik.th-darmstadt.de/pub/linux/okir/nfs-server-2.2beta40.tar.gz
ftp://ftp.mathematik.th-darmstadt.de/pub/linux/okir/dontuse/nfs-server-2.2beta40.tar.gz
ftp://linux.nrao.edu/mirrors/fb0429.mathematik.th-darmstadt.de/pub/linux/okir/dontuse/nfs-server-2.2beta40.tar.gz
The kernel-level 12/04/98 release:
ftp://ftp.yggdrasil.com/private/hjl/knfsd-981204.tar.gz
......@@ -601,30 +623,30 @@ ftp://ftp.kernel.org/pub/linux/devel/gcc/knfsd-981204.tar.gz
Net-tools
=========
The 1.49 release:
ftp://ftp.cs-ipv6.lancs.ac.uk/pub/Code/Linux/Net_Tools/net-tools-1.49.tar.gz
http://www.tazenda.demon.co.uk/phil/net-tools/net-tools-1.49.tar.gz
The 1.50 release:
ftp://ftp.cs-ipv6.lancs.ac.uk/pub/Code/Linux/Net_Tools/net-tools-1.50.tar.gz
http://www.tazenda.demon.co.uk/phil/net-tools/net-tools-1.50.tar.gz
Ypbind
======
The 3.3 release:
ftp://ftp.uni-paderborn.de/pub/linux/local/yp/ypbind-3.3.tar.gz
ftp://ftp.kernel.org/pub/linux/utils/net/NIS/ypbind-3.3.tar.gz
Sysklogd
========
The 1.3-30 release:
ftp://metalab.unc.edu/pub/Linux/system/daemons/sysklogd-1.3-30.tar.gz
The 1.3-31 release:
ftp://metalab.unc.edu/pub/Linux/system/daemons/sysklogd-1.3-31.tar.gz
Bash
====
The 1.14.7 release:
ftp://prep.ai.mit.edu/pub/gnu/bash-1.14.7.tar.gz
ftp://ftp.gnu.org/gnu/bash/bash-1.14.7.tar.gz
The 2.02.1 release:
ftp://prep.ai.mit.edu/pub/gnu/bash-2.02.1.tar.gz
ftp://ftp.gnu.org/gnu/bash/bash-2.02.1.tar.gz
Ncpfs
=====
......@@ -726,8 +748,14 @@ ftp://ftp.uk.linux.org/pub/linux/sct/quota/quota-1.55-10.src.rpm
IP utils
========
The 11/01/98 release:
ftp://ftp.inr.ac.ru/pub/ip-routing/iputils-ss981101.tar.gz
The 03/01/99 release:
ftp://ftp.inr.ac.ru/ip-routing/iproute2-2.1.99-now-ss990301.tar.gz
Patch
=====
The 2.5 release:
ftp://ftp.gnu.org/gnu/patch/patch-2.5.tar.gz
Other Info
==========
......@@ -744,7 +772,7 @@ distribution), most of these are available in RPM format. Check around
your favorite Red Hat mirror site before installing the non-RPM
version. Remember, you might need to use the --force option to get the
upgrade to install. ftp://contrib.redhat.com/ ,
ftp://developer.redhat.com/ , or ftp://rawhide.redhat.com/ will have
ftp://developer.redhat.com/ , or ftp://updates.redhat.com/ will have
almost everything you need, and Red Hat 5.2 ships with most necessary
software.
......
......@@ -229,8 +229,8 @@ S: Maintained
DIGI INTL. EPCA DRIVER
P: Daniel Taylor
M: support@dgii.com
M: digilnux@dgii.com
L: digiboard@list.fuller.edu
M: danielt@dgii.com
L: digilnux@dgii.com
S: Maintained
DIGI RIGHTSWITCH NETWORK DRIVER
......@@ -719,10 +719,8 @@ W: http://www.stallion.com
S: Supported
STARMODE RADIO IP (STRIP) PROTOCOL DRIVER
P: Stuart Cheshire
M: cheshire@cs.stanford.edu
W: http://mosquitonet.Stanford.EDU/strip.html
S: Maintained
S: Unsupported ?
SVGA HANDLING
P: Martin Mares
......@@ -819,4 +817,4 @@ S: Maintained
THE REST
P: Linus Torvalds
S: Buried alive in diapers
S: Buried alive in reporters
......@@ -37,6 +37,7 @@
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/sysinfo.h>
#include <asm/hwrpb.h>
extern int do_mount(kdev_t, const char *, const char *, char *, int, void *);
extern int do_pipe(int *);
......@@ -762,14 +763,10 @@ asmlinkage long osf_proplist_syscall(enum pl_code code, union pl_args *args)
asmlinkage int osf_sigstack(struct sigstack *uss, struct sigstack *uoss)
{
unsigned long usp = rdusp();
unsigned long oss_sp, oss_os;
unsigned long oss_sp = current->sas_ss_sp + current->sas_ss_size;
unsigned long oss_os = on_sig_stack(usp);
int error;
if (uoss) {
oss_sp = current->sas_ss_sp + current->sas_ss_size;
oss_os = on_sig_stack(usp);
}
if (uss) {
void *ss_sp;
......@@ -880,10 +877,12 @@ asmlinkage unsigned long osf_getsysinfo(unsigned long op, void *buffer,
int *start, void *arg)
{
unsigned long w;
struct percpu_struct *cpu;
switch (op) {
case GSI_IEEE_FP_CONTROL:
/* Return current software fp control & status bits. */
/* Note that DU doesn't verify available space here. */
w = current->tss.flags & IEEE_SW_MASK;
if (put_user(w, (unsigned long *) buffer))
return -EFAULT;
......@@ -898,10 +897,28 @@ asmlinkage unsigned long osf_getsysinfo(unsigned long op, void *buffer,
break;
case GSI_UACPROC:
if (nbytes < sizeof(unsigned int))
return -EINVAL;
w = (current->tss.flags >> UAC_SHIFT) & UAC_BITMASK;
if (put_user(w, (unsigned int *)buffer))
return -EFAULT;
return 0;
return 1;
case GSI_PROC_TYPE:
if (nbytes < sizeof(unsigned long))
return -EINVAL;
cpu = (struct percpu_struct*)
((char*)hwrpb + hwrpb->processor_offset);
if (put_user(w, (unsigned long *)buffer))
return -EFAULT;
return 1;
case GSI_GET_HWRPB:
if (nbytes < sizeof(*hwrpb))
return -EINVAL;
if (copy_to_user(buffer, hwrpb, nbytes) != 0)
return -EFAULT;
return 1;
default:
break;
......
......@@ -464,8 +464,7 @@ __initfunc(static int amd_model(struct cpuinfo_x86 *c))
rdmsr(0xC0000082, l, h);
if((l&0xFFFF0000)==0)
{
mbytes>>=2;
l=(mbytes<<22)|(1<<16);
l=((mbytes>>2)<<22)|(1<<16);
save_flags(flags);
__cli();
__asm__ __volatile__ ("wbinvd": : :"memory");
......
......@@ -161,7 +161,7 @@ do_aout32_core_dump(long signr, struct pt_regs * regs)
set_fs(KERNEL_DS);
DUMP_WRITE(current,sizeof(*current));
close_coredump:
close_fp(file, NULL);
filp_close(file, NULL);
end_coredump:
set_fs(fs);
return has_dumped;
......
......@@ -900,7 +900,7 @@ amiga_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector)
continue;
}
printk("Warning: Trashed word at 0xd0 in block %d "
"ignored in checksum calculation\n",kdevname(dev),blk);
"ignored in checksum calculation\n",blk);
}
printk(" RDSK");
blk = htonl(rdb->rdb_PartitionList);
......
......@@ -43,33 +43,6 @@
#include "ide.h"
/*
* CompactFlash cards and their brethern pretend to be removable hard disks, except:
* (1) they never have a slave unit, and
* (2) they don't have doorlock mechanisms.
* This test catches them, and is invoked elsewhere when setting appropriate config bits.
*
* FIXME: This treatment is probably applicable for *all* PCMCIA (PC CARD) devices,
* so in linux 2.3.x we should change this to just treat all PCMCIA drives this way,
* and get rid of the model-name tests below (too big of an interface change for 2.2.x).
* At that time, we might also consider parameterizing the timeouts and retries,
* since these are MUCH faster than mechanical drives. -M.Lord
*/
int drive_is_flashcard (ide_drive_t *drive)
{
struct hd_driveid *id = drive->id;
if (drive->removable && id != NULL) {
if (!strncmp(id->model, "KODAK ATA_FLASH", 15) /* Kodak */
|| !strncmp(id->model, "Hitachi CV", 10) /* Hitachi */
|| !strncmp(id->model, "SunDisk SDCFB", 13)) /* SunDisk */
{
return 1; /* yes, it is a flash memory card */
}
}
return 0; /* no, it is not a flash memory card */
}
static inline void do_identify (ide_drive_t *drive, byte cmd)
{
int bswap = 1;
......
......@@ -253,6 +253,33 @@ static void init_ide_data (void)
system_bus_speed = 0;
}
/*
* CompactFlash cards and their brethern pretend to be removable hard disks, except:
* (1) they never have a slave unit, and
* (2) they don't have doorlock mechanisms.
* This test catches them, and is invoked elsewhere when setting appropriate config bits.
*
* FIXME: This treatment is probably applicable for *all* PCMCIA (PC CARD) devices,
* so in linux 2.3.x we should change this to just treat all PCMCIA drives this way,
* and get rid of the model-name tests below (too big of an interface change for 2.2.x).
* At that time, we might also consider parameterizing the timeouts and retries,
* since these are MUCH faster than mechanical drives. -M.Lord
*/
int drive_is_flashcard (ide_drive_t *drive)
{
struct hd_driveid *id = drive->id;
if (drive->removable && id != NULL) {
if (!strncmp(id->model, "KODAK ATA_FLASH", 15) /* Kodak */
|| !strncmp(id->model, "Hitachi CV", 10) /* Hitachi */
|| !strncmp(id->model, "SunDisk SDCFB", 13)) /* SunDisk */
{
return 1; /* yes, it is a flash memory card */
}
}
return 0; /* no, it is not a flash memory card */
}
/*
* ide_system_bus_speed() returns what we think is the system VESA/PCI
* bus speed (in MHz). This is used for calculating interface PIO timings.
......
......@@ -771,7 +771,7 @@ static void rs_interrupt_multi(int irq, void *dev_id, struct pt_regs * regs)
continue;
if (!multi->port4)
break;
if ((inb(multi->port4) & multi->mask4) == multi->match4)
if ((inb(multi->port4) & multi->mask4) != multi->match4)
continue;
break;
}
......@@ -1274,6 +1274,8 @@ static void change_speed(struct async_struct *info,
/* Determine divisor based on baud rate */
baud = tty_get_baud_rate(info->tty);
if (!baud)
baud = 9600; /* B0 transition handled in rs_set_termios */
baud_base = info->state->baud_base;
if (baud == 38400 &&
((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST))
......@@ -1740,7 +1742,7 @@ static int set_serial_info(struct async_struct * info,
check_and_exit:
if (!state->port || !state->type)
return 0;
if (state->flags & ASYNC_INITIALIZED) {
if (info->flags & ASYNC_INITIALIZED) {
if (((old_state.flags & ASYNC_SPD_MASK) !=
(state->flags & ASYNC_SPD_MASK)) ||
(old_state.custom_divisor != state->custom_divisor)) {
......@@ -2162,8 +2164,9 @@ static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios)
{
struct async_struct *info = (struct async_struct *)tty->driver_data;
unsigned long flags;
unsigned int cflag = tty->termios->c_cflag;
if ( (tty->termios->c_cflag == old_termios->c_cflag)
if ( (cflag == old_termios->c_cflag)
&& ( RELEVANT_IFLAG(tty->termios->c_iflag)
== RELEVANT_IFLAG(old_termios->c_iflag)))
return;
......@@ -2172,7 +2175,7 @@ static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios)
/* Handle transition to B0 status */
if ((old_termios->c_cflag & CBAUD) &&
!(tty->termios->c_cflag & CBAUD)) {
!(cflag & CBAUD)) {
info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS);
save_flags(flags); cli();
serial_out(info, UART_MCR, info->MCR);
......@@ -2181,7 +2184,7 @@ static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios)
/* Handle transition away from B0 status */
if (!(old_termios->c_cflag & CBAUD) &&
(tty->termios->c_cflag & CBAUD)) {
(cflag & CBAUD)) {
info->MCR |= UART_MCR_DTR;
if (!(tty->termios->c_cflag & CRTSCTS) ||
!test_bit(TTY_THROTTLED, &tty->flags)) {
......
......@@ -1143,7 +1143,7 @@ static void release_dev(struct file * filp)
/*
* We've decremented tty->count, so we should zero out
* filp->private_data, to break the link between the tty and
* the file descriptor. Otherwise if close_fp() blocks before
* the file descriptor. Otherwise if filp_close() blocks before
* the the file descriptor is removed from the inuse_filp
* list, check_tty_count() could observe a discrepancy and
* printk a warning message to the user.
......
......@@ -831,7 +831,10 @@ el3_rx(struct device *dev)
static void
set_multicast_list(struct device *dev)
{
unsigned long flags;
struct el3_private *lp = (struct el3_private *)dev->priv;
int ioaddr = dev->base_addr;
if (el3_debug > 1) {
static int old = 0;
if (old != dev->mc_count) {
......@@ -839,6 +842,7 @@ set_multicast_list(struct device *dev)
printk("%s: Setting Rx mode to %d addresses.\n", dev->name, dev->mc_count);
}
}
spin_lock_irqsave(&lp->lock, flags);
if (dev->flags&IFF_PROMISC) {
outw(SetRxFilter | RxStation | RxMulticast | RxBroadcast | RxProm,
ioaddr + EL3_CMD);
......@@ -848,6 +852,7 @@ set_multicast_list(struct device *dev)
}
else
outw(SetRxFilter | RxStation | RxBroadcast, ioaddr + EL3_CMD);
spin_unlock_irqrestore(&lp->lock, flags);
}
static int
......
......@@ -82,7 +82,7 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
tristate 'RealTek 8129/8139 (not 8019/8029!) support' CONFIG_RTL8139
tristate 'Packet Engines Yellowfin Gigabit-NIC support' CONFIG_YELLOWFIN
tristate 'Alteon AceNIC & 3Com 3C985 Gigabit support' CONFIG_ACENIC
tristate 'Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support' CONFIG_ACENIC
fi
bool 'Other ISA cards' CONFIG_NET_ISA
if [ "$CONFIG_NET_ISA" = "y" ]; then
......
......@@ -16,6 +16,9 @@
* 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.
*
* Additional work by Pete Wyckoff <wyckoff@ca.sandia.gov> for initial
* Alpha and trace dump support.
*/
#define PKT_COPY_THRESHOLD 300
......@@ -40,6 +43,7 @@
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/byteorder.h>
#include <asm/uaccess.h>
#include "acenic.h"
......@@ -52,10 +56,23 @@
#include "acenic_firmware.h"
#ifndef PCI_VENDOR_ID_ALTEON
#define PCI_VENDOR_ID_ALTEON 0x12ae
#define PCI_DEVICE_ID_ALTEON_ACENIC 0x0001
#endif
#ifndef PCI_DEVICE_ID_3COM_3C985
#define PCI_DEVICE_ID_3COM_3C985 0x0001
#endif
#ifndef PCI_VENDOR_ID_NETGEAR
#define PCI_VENDOR_ID_NETGEAR 0x1385
#define PCI_DEVICE_ID_NETGEAR_GA620 0x620a
#endif
/*
* This driver currently supports Tigon I and Tigon II based cards
* including the Alteon AceNIC and the 3Com 3C985.
* including the Alteon AceNIC and the 3Com 3C985. The driver should
* also work on the NetGear GA620, however I have not been able to
* test that myself.
*
* This card is really neat, it supports receive hardware checksumming
* and jumbo frames (up to 9000 bytes) and does a lot of work in the
......@@ -114,30 +131,50 @@
* max_rx_desc=<val> - maximum number of receive descriptors
* (packets) received before interrupting the host.
*
* tx_ratio=<val> - 7 bit value (0 - 63) specifying the split in 64th
* increments of the NIC's on board memory to be used for
* transmit and receive buffers. For the 1MB NIC app. 800KB
* is available, on the 1/2MB NIC app. 300KB is available.
* 68KB will always be available as a minimum for both
* directions. The default value is a 50/50 split.
*
* If you use more than one NIC, specify the parameters for the
* individual NICs with a comma, ie. trace=0,0x00001fff,0 you want to
* run tracing on NIC #2 but not on NIC #1 and #3.
*
* TODO:
*
* - Add multicast support.
* - Proper multicast support.
* - NIC dump support.
* - More tuning parameters.
*
* The mini ring is not used under Linux and I am not sure it makes sense
* to actually use it.
*/
/*
* Default values for tuning parameters
*/
#define DEF_TX_RATIO 31
#define DEF_TX_COAL TICKS_PER_SEC / 500
#define DEF_TX_MAX_DESC 7
#define DEF_RX_COAL TICKS_PER_SEC / 10000
#define DEF_RX_MAX_DESC 2
#define DEF_TRACE 0
#define DEF_STAT 2 * TICKS_PER_SEC
static int link[8] = {0, };
static int trace[8] = {0, };
static int tx_coal_tick[8] = {0, };
static int rx_coal_tick[8] = {0, };
static int max_tx_desc[8] = {0, };
static int max_rx_desc[8] = {0, };
static int tx_ratio[8] = {0, };
static const char *version = "acenic.c: v0.24 01/13/99 Jes Sorensen (Jes.Sorensen@cern.ch)\n";
static const char __initdata *version = "acenic.c: v0.32 03/15/99 Jes Sorensen (Jes.Sorensen@cern.ch)\n";
static struct device *root_dev = NULL;
static int ace_load_firmware(struct device *dev);
static int probed __initdata = 0;
__initfunc(int acenic_probe (struct device *dev))
......@@ -163,13 +200,15 @@ __initfunc(int acenic_probe (struct device *dev))
version_disp = 0;
while((pdev = pci_find_class(PCI_CLASS_NETWORK_ETHERNET << 8, pdev)))
{
while ((pdev = pci_find_class(PCI_CLASS_NETWORK_ETHERNET<<8, pdev))){
dev = NULL;
if ((pdev->vendor != PCI_VENDOR_ID_ALTEON) &&
if (!((pdev->vendor == PCI_VENDOR_ID_ALTEON) &&
(pdev->device == PCI_DEVICE_ID_ALTEON_ACENIC)) &&
!((pdev->vendor == PCI_VENDOR_ID_3COM) &&
(pdev->device == PCI_DEVICE_ID_3COM_3C985)))
(pdev->device == PCI_DEVICE_ID_3COM_3C985)) &&
!((pdev->vendor == PCI_VENDOR_ID_NETGEAR) &&
(pdev->device == PCI_DEVICE_ID_NETGEAR_GA620)))
continue;
dev = init_etherdev(dev, sizeof(struct ace_private));
......@@ -182,6 +221,8 @@ __initfunc(int acenic_probe (struct device *dev))
if (!dev->priv)
dev->priv = kmalloc(sizeof(*ap), GFP_KERNEL);
if (!dev->priv)
return -ENOMEM;
ap = dev->priv;
ap->pdev = pdev;
......@@ -197,6 +238,9 @@ __initfunc(int acenic_probe (struct device *dev))
dev->stop = &ace_close;
dev->get_stats = &ace_get_stats;
dev->set_multicast_list = &ace_set_multicast_list;
#if 0
dev->do_ioctl = &ace_ioctl;
#endif
dev->set_mac_address = &ace_set_mac_addr;
dev->change_mtu = &ace_change_mtu;
......@@ -234,6 +278,10 @@ __initfunc(int acenic_probe (struct device *dev))
sprintf(ap->name, "3Com 3C985 Gigabit Ethernet");
printk(KERN_INFO "%s: 3Com 3C985 ", dev->name);
break;
case PCI_VENDOR_ID_NETGEAR:
sprintf(ap->name, "NetGear GA620 Gigabit Ethernet");
printk(KERN_INFO "%s: NetGear GA620 ", dev->name);
break;
default:
sprintf(ap->name, "Unknown AceNIC based Gigabit Ethernet");
printk(KERN_INFO "%s: Unknown AceNIC ", dev->name);
......@@ -256,9 +304,11 @@ __initfunc(int acenic_probe (struct device *dev))
}
#ifdef MODULE
ace_init(dev, boards_found);
if (ace_init(dev, boards_found))
continue;
#else
ace_init(dev, -1);
if (ace_init(dev, -1))
continue;
#endif
boards_found++;
......@@ -317,17 +367,18 @@ void cleanup_module(void)
short i;
unsigned long flags;
while (root_dev) {
while (root_dev){
next = ((struct ace_private *)root_dev->priv)->next;
ap = (struct ace_private *)root_dev->priv;
regs = ap->regs;
spin_lock_irqsave(&ap->lock, flags);
regs->CpuCtrl |= CPU_HALT;
writel(readl(&regs->CpuCtrl) | CPU_HALT, &regs->CpuCtrl);
if (ap->version == 2)
regs->CpuBCtrl |= CPU_HALT;
regs->Mb0Lo = 0;
writel(readl(&regs->CpuBCtrl) | CPU_HALT,
&regs->CpuBCtrl);
writel(0, &regs->Mb0Lo);
spin_unlock_irqrestore(&ap->lock, flags);
......@@ -337,7 +388,7 @@ void cleanup_module(void)
for (i = 0; i < RX_STD_RING_ENTRIES; i++) {
if (ap->rx_std_skbuff[i]) {
ap->rx_std_ring[i].size = 0;
ap->rx_std_ring[i].addr = 0;
set_aceaddr_bus(&ap->rx_std_ring[i].addr, 0);
dev_kfree_skb(ap->rx_std_skbuff[i]);
}
}
......@@ -363,12 +414,12 @@ static inline void ace_issue_cmd(struct ace_regs *regs, struct cmd *cmd)
{
u32 idx;
idx = regs->CmdPrd;
idx = readl(&regs->CmdPrd);
regs->CmdRng[idx] = *(u32 *)(cmd);
writel(*(u32 *)(cmd), &regs->CmdRng[idx]);
idx = (idx + 1) % CMD_RING_ENTRIES;
regs->CmdPrd = idx;
writel(idx, &regs->CmdPrd);
}
......@@ -384,51 +435,42 @@ __initfunc(static int ace_init(struct device *dev, int board_idx))
ap = dev->priv;
regs = ap->regs;
#if 0
regs->HostCtrl |= 0x08;
regs->CpuCtrl = CPU_RESET;
regs->CpuBCtrl = CPU_RESET;
{
long myjif = jiffies + HZ;
while (time_before(jiffies, myjif));
}
#endif
/*
* Don't access any other registes before this point!
*/
#ifdef __BIG_ENDIAN
regs->HostCtrl = ((BYTE_SWAP | WORD_SWAP | CLR_INT) |
((BYTE_SWAP | WORD_SWAP | CLR_INT) << 24));
writel(((BYTE_SWAP | WORD_SWAP | CLR_INT) |
((BYTE_SWAP | WORD_SWAP | CLR_INT) << 24)),
&regs->HostCtrl);
#else
regs->HostCtrl = (CLR_INT | WORD_SWAP |
((CLR_INT | WORD_SWAP) << 24));
writel((CLR_INT | WORD_SWAP | ((CLR_INT | WORD_SWAP) << 24)),
&regs->HostCtrl);
#endif
mb();
/*
* Stop the NIC CPU and clear pending interrupts
*/
regs->CpuCtrl |= CPU_HALT;
regs->Mb0Lo = 0;
writel(readl(&regs->CpuCtrl) | CPU_HALT, &regs->CpuCtrl);
writel(0, &regs->Mb0Lo);
tig_ver = regs->HostCtrl >> 28;
tig_ver = readl(&regs->HostCtrl) >> 28;
switch(tig_ver){
case 4:
printk(KERN_INFO" Tigon I (Rev. 4), Firmware: %i.%i.%i, ",
tigonFwReleaseMajor, tigonFwReleaseMinor,
tigonFwReleaseFix);
regs->LocalCtrl = 0;
writel(0, &regs->LocalCtrl);
ap->version = 1;
break;
case 6:
printk(KERN_INFO" Tigon II (Rev. %i), Firmware: %i.%i.%i, ",
tig_ver, tigon2FwReleaseMajor, tigon2FwReleaseMinor,
tigon2FwReleaseFix);
regs->CpuBCtrl |= CPU_HALT;
regs->LocalCtrl = SRAM_BANK_512K;
regs->MiscCfg = SYNC_SRAM_TIMING;
writel(readl(&regs->CpuBCtrl) | CPU_HALT, &regs->CpuBCtrl);
writel(SRAM_BANK_512K, &regs->LocalCtrl);
writel(SYNC_SRAM_TIMING, &regs->MiscCfg);
ap->version = 2;
break;
default:
......@@ -445,8 +487,8 @@ __initfunc(static int ace_init(struct device *dev, int board_idx))
* `Firmware not running' problem on the Tigon II.
*/
#ifdef __LITTLE_ENDIAN
regs->ModeStat = ACE_BYTE_SWAP_DATA | ACE_WARN | ACE_FATAL
| ACE_WORD_SWAP;
writel(ACE_BYTE_SWAP_DATA | ACE_WARN | ACE_FATAL |
ACE_WORD_SWAP | ACE_NO_JUMBO_FRAG, &regs->ModeStat);
#else
#error "this driver doesn't run on big-endian machines yet!"
#endif
......@@ -462,8 +504,8 @@ __initfunc(static int ace_init(struct device *dev, int board_idx))
mac2 |= read_eeprom_byte(regs, 0x8c+i);
}
regs->MacAddrHi = mac1;
regs->MacAddrLo = mac2;
writel(mac1, &regs->MacAddrHi);
writel(mac2, &regs->MacAddrLo);
printk("MAC: %02x:%02x:%02x:%02x:%02x:%02x\n",
(mac1 >> 8) & 0xff, mac1 & 0xff, (mac2 >> 24) &0xff,
......@@ -514,10 +556,9 @@ __initfunc(static int ace_init(struct device *dev, int board_idx))
}
}
}
regs->PciState = tmp;
writel(tmp, &regs->PciState);
if (request_irq(dev->irq, ace_interrupt, SA_SHIRQ, ap->name, dev))
{
if (request_irq(dev->irq, ace_interrupt, SA_SHIRQ, ap->name, dev)) {
printk(KERN_WARNING "%s: Requested IRQ %d is busy\n",
dev->name, dev->irq);
return -EAGAIN;
......@@ -548,150 +589,149 @@ __initfunc(static int ace_init(struct device *dev, int board_idx))
tmp_ptr = virt_to_bus((void *)info);
#if (BITS_PER_LONG == 64)
regs->InfoPtrHi = (tmp_ptr >> 32);
writel(tmp_ptr >> 32, &regs->InfoPtrHi);
#else
regs->InfoPtrHi = 0;
writel(0, &regs->InfoPtrHi);
#endif
regs->InfoPtrLo = ((tmp_ptr) & 0xffffffff);
writel(tmp_ptr & 0xffffffff, &regs->InfoPtrLo);
memset(ap->evt_ring, 0, EVT_RING_ENTRIES * sizeof(struct event));
info->evt_ctrl.rngptr = virt_to_bus(ap->evt_ring);
set_aceaddr(&info->evt_ctrl.rngptr, ap->evt_ring);
info->evt_ctrl.flags = 0;
info->evt_prd_ptr = virt_to_bus(&ap->evt_prd);
set_aceaddr(&info->evt_prd_ptr, &ap->evt_prd);
ap->evt_prd = 0;
regs->EvtCsm = 0;
writel(0, &regs->EvtCsm);
info->cmd_ctrl.flags = 0;
info->cmd_ctrl.rngptr = 0x100;
set_aceaddr_bus(&info->cmd_ctrl.rngptr, (void *)0x100);
info->cmd_ctrl.max_len = 0;
for (i = 0; i < CMD_RING_ENTRIES; i++) {
regs->CmdRng[i] = 0;
}
for (i = 0; i < CMD_RING_ENTRIES; i++)
writel(0, &regs->CmdRng[i]);
regs->CmdPrd = 0;
regs->CmdCsm = 0;
writel(0, &regs->CmdPrd);
writel(0, &regs->CmdCsm);
info->stats2_ptr = virt_to_bus(&info->s.stats);
set_aceaddr(&info->stats2_ptr, &info->s.stats);
info->rx_std_ctrl.max_len = ACE_STD_MTU + ETH_HLEN + 4;
info->rx_std_ctrl.rngptr = virt_to_bus(ap->rx_std_ring);
info->rx_std_ctrl.flags = RX_TCP_UDP_SUM;
set_aceaddr(&info->rx_std_ctrl.rngptr, ap->rx_std_ring);
info->rx_std_ctrl.flags = FLG_RX_TCP_UDP_SUM;
memset(ap->rx_std_ring, 0,
RX_STD_RING_ENTRIES * sizeof(struct rx_desc));
info->rx_jumbo_ctrl.max_len = 0;
info->rx_jumbo_ctrl.rngptr = virt_to_bus(ap->rx_jumbo_ring);
info->rx_jumbo_ctrl.flags = RX_TCP_UDP_SUM;
set_aceaddr(&info->rx_jumbo_ctrl.rngptr, ap->rx_jumbo_ring);
info->rx_jumbo_ctrl.flags = FLG_RX_TCP_UDP_SUM;
memset(ap->rx_jumbo_ring, 0,
RX_JUMBO_RING_ENTRIES * sizeof(struct rx_desc));
info->rx_return_ctrl.max_len = 0;
info->rx_return_ctrl.rngptr = virt_to_bus(ap->rx_return_ring);
info->rx_mini_ctrl.max_len = 0;
#if 0
set_aceaddr(&info->rx_mini_ctrl.rngptr, ap->rx_mini_ring);
#else
set_aceaddr_bus(&info->rx_mini_ctrl.rngptr, 0);
#endif
info->rx_mini_ctrl.flags = FLG_RNG_DISABLED;
#if 0
memset(ap->rx_mini_ring, 0,
RX_MINI_RING_ENTRIES * sizeof(struct rx_desc));
#endif
set_aceaddr(&info->rx_return_ctrl.rngptr, ap->rx_return_ring);
info->rx_return_ctrl.flags = 0;
info->rx_return_ctrl.max_len = RX_RETURN_RING_ENTRIES;
memset(ap->rx_return_ring, 0,
RX_RETURN_RING_ENTRIES * sizeof(struct rx_desc));
info->rx_ret_prd_ptr = virt_to_bus(&ap->rx_ret_prd);
set_aceaddr(&info->rx_ret_prd_ptr, &ap->rx_ret_prd);
regs->WinBase = TX_RING_BASE;
writel(TX_RING_BASE, &regs->WinBase);
ap->tx_ring = (struct tx_desc *)regs->Window;
memset(ap->tx_ring, 0, TX_RING_ENTRIES * sizeof(struct tx_desc));
for (i = 0; i < (TX_RING_ENTRIES * sizeof(struct tx_desc) / 4); i++){
writel(0, (unsigned long)ap->tx_ring + i * 4);
}
info->tx_ctrl.max_len = TX_RING_ENTRIES;
info->tx_ctrl.flags = 0;
#if (BITS_PER_LONG == 64) && defined(__BIG_ENDIAN)
info->tx_ctrl.rngptr = TX_RING_BASE << 32;
#else
info->tx_ctrl.rngptr = TX_RING_BASE;
#endif
set_aceaddr_bus(&info->tx_ctrl.rngptr, (void *)TX_RING_BASE);
info->tx_csm_ptr = virt_to_bus(&ap->tx_csm);
set_aceaddr(&info->tx_csm_ptr, &ap->tx_csm);
/*
* Potential item for tuning parameter
*/
regs->DmaReadCfg = DMA_THRESH_8W;
regs->DmaWriteCfg = DMA_THRESH_8W;
regs->MaskInt = 0;
regs->IfIdx = 1;
regs->AssistState = 1;
#if 0
{
u32 tmp;
tmp = regs->MacRxState;
tmp &= ~4;
regs->MacRxState = tmp;
}
#endif
regs->TuneStatTicks = 2 * TICKS_PER_SEC;
writel(DMA_THRESH_8W, &regs->DmaReadCfg);
writel(DMA_THRESH_8W, &regs->DmaWriteCfg);
writel(0, &regs->MaskInt);
writel(1, &regs->IfIdx);
writel(1, &regs->AssistState);
writel(DEF_STAT, &regs->TuneStatTicks);
writel(DEF_TX_COAL, &regs->TuneTxCoalTicks);
writel(DEF_TX_MAX_DESC, &regs->TuneMaxTxDesc);
writel(DEF_RX_COAL, &regs->TuneRxCoalTicks);
writel(DEF_RX_MAX_DESC, &regs->TuneMaxRxDesc);
writel(DEF_TRACE, &regs->TuneTrace);
writel(DEF_TX_RATIO, &regs->TxBufRat);
if (board_idx >= 8) {
printk(KERN_WARNING "%s: more then 8 NICs detected, "
"ignoring module parameters!\n", dev->name);
board_idx = -1;
}
if (board_idx >= 0) {
if ((board_idx < 8) && tx_coal_tick[board_idx])
regs->TuneTxCoalTicks = tx_coal_tick[board_idx] *
TICKS_PER_SEC / 1000;
else
regs->TuneTxCoalTicks = TICKS_PER_SEC / 500;
if ((board_idx < 8) && max_tx_desc[board_idx])
regs->TuneMaxTxDesc = max_tx_desc[board_idx];
else
regs->TuneMaxTxDesc = 7;
if ((board_idx < 8) && rx_coal_tick[board_idx])
regs->TuneRxCoalTicks = rx_coal_tick[board_idx] *
TICKS_PER_SEC / 1000;
else
regs->TuneRxCoalTicks = TICKS_PER_SEC / 10000;
if ((board_idx < 8) && max_rx_desc[board_idx])
regs->TuneMaxRxDesc = max_rx_desc[board_idx];
else
regs->TuneMaxRxDesc = 2;
if (board_idx < 8)
regs->TuneTrace = trace[board_idx];
else
regs->TuneTrace = 0;
}else{
regs->TuneTxCoalTicks = TICKS_PER_SEC / 500;
regs->TuneMaxTxDesc = 7;
regs->TuneRxCoalTicks = TICKS_PER_SEC / 10000;
regs->TuneMaxRxDesc = 2;
regs->TuneTrace = 0;
if (tx_coal_tick[board_idx])
writel(tx_coal_tick[board_idx],
&regs->TuneTxCoalTicks);
if (max_tx_desc[board_idx])
writel(max_tx_desc[board_idx], &regs->TuneMaxTxDesc);
if (rx_coal_tick[board_idx])
writel(rx_coal_tick[board_idx],
&regs->TuneRxCoalTicks);
if (max_rx_desc[board_idx])
writel(max_rx_desc[board_idx], &regs->TuneMaxRxDesc);
if (trace[board_idx])
writel(trace[board_idx], &regs->TuneTrace);
if ((tx_ratio[board_idx] >= 0) && (tx_ratio[board_idx] < 64))
writel(tx_ratio[board_idx], &regs->TxBufRat);
}
tmp = LNK_ENABLE;
if ((board_idx > 7) || (board_idx < 0) || !(link[board_idx])){
if (board_idx > 7)
printk(KERN_WARNING "%s: more then 8 NICs detected, "
"ignoring link options!\n", dev->name);
/*
* No link options specified, we go for the defaults
*/
tmp |= LNK_FULL_DUPLEX | LNK_1000MB | LNK_100MB | LNK_10MB |
LNK_RX_FLOW_CTL_Y | LNK_NEG_FCTL | LNK_NEGOTIATE;
/*
* Default link parameters
*/
tmp = LNK_ENABLE | LNK_FULL_DUPLEX | LNK_1000MB | LNK_100MB |
LNK_10MB | LNK_RX_FLOW_CTL_Y | LNK_NEG_FCTL | LNK_NEGOTIATE;
if(ap->version == 2)
tmp |= LNK_TX_FLOW_CTL_Y;
if(ap->version == 2)
tmp |= LNK_TX_FLOW_CTL_Y;
} else {
/*
* Override link default parameters
*/
if ((board_idx >= 0) && link[board_idx]) {
int option = link[board_idx];
tmp = LNK_ENABLE;
if (option & 0x01){
printk(KERN_INFO "%s: Setting half duplex link\n",
dev->name);
tmp |= LNK_FULL_DUPLEX;
tmp &= ~LNK_FULL_DUPLEX;
}
if ((option & 0x02) == 0)
tmp |= LNK_NEGOTIATE;
if (option & 0x02)
tmp &= ~LNK_NEGOTIATE;
if (option & 0x10)
tmp |= LNK_10MB;
if (option & 0x20)
......@@ -718,22 +758,22 @@ __initfunc(static int ace_init(struct device *dev, int board_idx))
}
}
regs->TuneLink = tmp;
writel(tmp, &regs->TuneLink);
if (ap->version == 2)
regs->TuneFastLink = tmp;
writel(tmp, &regs->TuneFastLink);
if (ap->version == 1)
regs->Pc = tigonFwStartAddr;
writel(tigonFwStartAddr, &regs->Pc);
else if (ap->version == 2)
regs->Pc = tigon2FwStartAddr;
writel(tigon2FwStartAddr, &regs->Pc);
regs->Mb0Lo = 0;
writel(0, &regs->Mb0Lo);
/*
* Start the NIC CPU
*/
regs->CpuCtrl = (regs->CpuCtrl & ~(CPU_HALT | CPU_TRACE));
writel(readl(&regs->CpuCtrl) & ~(CPU_HALT|CPU_TRACE), &regs->CpuCtrl);
/*
* Wait for the firmware to spin up - max 3 seconds.
......@@ -743,7 +783,7 @@ __initfunc(static int ace_init(struct device *dev, int board_idx))
if (!ap->fw_running){
printk(KERN_ERR "%s: Firmware NOT running!\n", dev->name);
ace_dump_trace(ap);
regs->CpuCtrl |= CPU_HALT;
writel(readl(&regs->CpuCtrl) | CPU_HALT, &regs->CpuCtrl);
return -EBUSY;
}
......@@ -773,7 +813,7 @@ static void ace_timer(unsigned long data)
*/
if (ap->tx_csm != ap->tx_ret_csm){
printk(KERN_WARNING "%s: Transmitter is stuck, %08x\n",
dev->name, regs->HostCtrl);
dev->name, (unsigned int)readl(&regs->HostCtrl));
}
ap->timer.expires = jiffies + (5/2*HZ);
......@@ -786,9 +826,11 @@ static void ace_timer(unsigned long data)
*/
static void ace_dump_trace(struct ace_private *ap)
{
#if 0
if (!ap->trace_buf)
if (!(ap->trace_buf = kmalloc(ACE_TRACE_SIZE, GFP_KERNEL)));
return;
#endif
}
......@@ -819,7 +861,7 @@ static int ace_load_std_rx_ring(struct device *dev)
ap->tx_full = 0;
ap->cur_rx = ap->dirty_rx = 0;
ap->tx_prd = ap->tx_csm = ap->tx_ret_csm = 0;
regs->RxRetCsm = 0;
writel(0, &regs->RxRetCsm);
for (i = 0; i < RX_RING_THRESH; i++) {
struct sk_buff *skb;
......@@ -833,7 +875,7 @@ static int ace_load_std_rx_ring(struct device *dev)
*/
skb_reserve(skb, 2);
ap->rx_std_ring[i].addr = virt_to_bus(skb->data);
set_aceaddr(&ap->rx_std_ring[i].addr, skb->data);
ap->rx_std_ring[i].size = ACE_STD_MTU + ETH_HLEN + 4;
ap->rx_std_ring[i].flags = 0;
......@@ -877,7 +919,7 @@ static int ace_load_jumbo_rx_ring(struct device *dev)
spin_lock_irqsave(&ap->lock, flags);
for (i = 0; i < RX_RING_THRESH; i++) {
for (i = 0; i < RX_RING_JUMBO_THRESH; i++) {
struct sk_buff *skb;
ap->rx_jumbo_ring[i].flags = 0;
......@@ -889,10 +931,10 @@ static int ace_load_jumbo_rx_ring(struct device *dev)
*/
skb_reserve(skb, 2);
ap->rx_jumbo_ring[i].addr = virt_to_bus(skb->data);
set_aceaddr(&ap->rx_jumbo_ring[i].addr, skb->data);
ap->rx_jumbo_ring[i].size = ACE_JUMBO_MTU + ETH_HLEN + 4;
ap->rx_jumbo_ring[i].flags = JUMBO_FLAG;
ap->rx_jumbo_ring[i].flags = DFLG_RX_JUMBO;
ap->rx_jumbo_ring[i].type = DESC_RX;
ap->rx_jumbo_ring[i].idx = i;
......@@ -939,7 +981,7 @@ static int ace_flush_jumbo_rx_ring(struct device *dev)
for (i = 0; i < RX_JUMBO_RING_ENTRIES; i++) {
if (ap->rx_jumbo_skbuff[i]) {
ap->rx_jumbo_ring[i].size = 0;
ap->rx_jumbo_ring[i].addr = 0;
set_aceaddr_bus(&ap->rx_jumbo_ring[i].addr, 0);
dev_kfree_skb(ap->rx_jumbo_skbuff[i]);
}
}
......@@ -959,10 +1001,8 @@ static int ace_flush_jumbo_rx_ring(struct device *dev)
static u32 ace_handle_event(struct device *dev, u32 evtcsm, u32 evtprd)
{
struct ace_private *ap;
struct ace_regs *regs;
ap = (struct ace_private *)dev->priv;
regs = ap->regs;
while (evtcsm != evtprd){
switch (ap->evt_ring[evtcsm].evt){
......@@ -1019,24 +1059,24 @@ static u32 ace_handle_event(struct device *dev, u32 evtcsm, u32 evtprd)
}
static int rx_int(struct device *dev, u32 rxretprd, u32 rxretcsm)
static int ace_rx_int(struct device *dev, u32 rxretprd, u32 rxretcsm)
{
struct ace_private *ap = (struct ace_private *)dev->priv;
u32 idx, oldidx;
struct ace_regs *regs = ap->regs;
u32 idx, oldidx;
idx = rxretcsm;
while(idx != rxretprd){
while (idx != rxretprd){
struct sk_buff *skb, *newskb, *oldskb;
struct rx_desc *newrxdesc, *oldrxdesc;
u32 prdidx, size;
unsigned long addr;
void *addr;
u16 csum;
int jumbo;
oldidx = ap->rx_return_ring[idx].idx;
jumbo = ap->rx_return_ring[idx].flags & JUMBO_FLAG;
jumbo = ap->rx_return_ring[idx].flags & DFLG_RX_JUMBO;
if (jumbo){
oldskb = ap->rx_jumbo_skbuff[oldidx];
......@@ -1065,7 +1105,7 @@ static int rx_int(struct device *dev, u32 rxretprd, u32 rxretcsm)
skb_reserve(skb, 2);
memcpy(skb_put(skb, size), oldskb->data, size);
addr = oldrxdesc->addr;
addr = get_aceaddr_bus(&oldrxdesc->addr);
newskb = oldskb;
}else{
skb = oldskb;
......@@ -1084,21 +1124,21 @@ static int rx_int(struct device *dev, u32 rxretprd, u32 rxretcsm)
* aligned receive buffers
*/
skb_reserve(newskb, 2);
addr = virt_to_bus(newskb->data);
addr = (void *)virt_to_bus(newskb->data);
}
newrxdesc->addr = addr;
set_aceaddr_bus(&newrxdesc->addr, addr);
newrxdesc->size = size;
newrxdesc->flags = oldrxdesc->flags;
newrxdesc->idx = prdidx;
newrxdesc->type = DESC_RX;
#if (BITS_PER_LONG == 32)
newrxdesc->zero = 0;
newrxdesc->addr.addrhi = 0;
#endif
oldrxdesc->size = 0;
oldrxdesc->addr = 0;
set_aceaddr_bus(&oldrxdesc->addr, 0);
if (jumbo){
ap->rx_jumbo_skbuff[oldidx] = NULL;
......@@ -1152,7 +1192,11 @@ static int rx_int(struct device *dev, u32 rxretprd, u32 rxretcsm)
idx = (idx + 1) % RX_RETURN_RING_ENTRIES;
}
out:
regs->RxRetCsm = idx;
/*
* According to the documentation RxRetCsm is obsolete with
* the 12.3.x Firmware - my Tigon I NIC's seem to disagree!
*/
writel(idx, &regs->RxRetCsm);
ap->cur_rx = idx;
return idx;
......@@ -1180,7 +1224,7 @@ static void ace_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
* we want to make sure it is actually our interrupt before
* spending any time in here.
*/
if (!(regs->HostCtrl & IN_INT)){
if (!(readl(&regs->HostCtrl) & IN_INT)){
spin_unlock(&ap->lock);
return;
}
......@@ -1188,7 +1232,16 @@ static void ace_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
/*
* Tell the card not to generate interrupts while we are in here.
*/
regs->Mb0Lo = 1;
writel(1, &regs->Mb0Lo);
/*
* Service RX ints before TX
*/
rxretprd = ap->rx_ret_prd;
rxretcsm = ap->cur_rx;
if (rxretprd != rxretcsm)
rxretprd = ace_rx_int(dev, rxretprd, rxretcsm);
txcsm = ap->tx_csm;
if (txcsm != ap->tx_ret_csm) {
......@@ -1201,9 +1254,11 @@ static void ace_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
ap->tx_skbuff[idx] = NULL;
ap->tx_ring[idx].size = 0;
ap->tx_ring[idx].addr = 0;
ap->tx_ring[idx].flags = 0;
#if (BITS_PER_LONG == 64)
writel(0, &ap->tx_ring[idx].addr.addrhi);
#endif
writel(0, &ap->tx_ring[idx].addr.addrlo);
writel(0, &ap->tx_ring[idx].flagsize);
idx = (idx + 1) % TX_RING_ENTRIES;
} while (idx != txcsm);
......@@ -1224,21 +1279,15 @@ static void ace_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
ap->tx_ret_csm = txcsm;
}
rxretprd = ap->rx_ret_prd;
rxretcsm = ap->cur_rx;
if (rxretprd != rxretcsm)
rxretprd = rx_int(dev, rxretprd, rxretcsm);
evtcsm = regs->EvtCsm;
evtcsm = readl(&regs->EvtCsm);
evtprd = ap->evt_prd;
if (evtcsm != evtprd){
evtcsm = ace_handle_event(dev, evtcsm, evtprd);
}
regs->EvtCsm = evtcsm;
regs->Mb0Lo = 0;
writel(evtcsm, &regs->EvtCsm);
writel(0, &regs->Mb0Lo);
spin_unlock(&ap->lock);
}
......@@ -1258,7 +1307,7 @@ static int ace_open(struct device *dev)
return -EBUSY;
}
regs->IfMtu = dev->mtu + ETH_HLEN + 4;
writel(dev->mtu + ETH_HLEN + 4, &regs->IfMtu);
cmd.evt = C_HOST_STATE;
cmd.code = C_C_STACK_UP;
......@@ -1277,6 +1326,7 @@ static int ace_open(struct device *dev)
ap->promisc = 1;
}else
ap->promisc = 0;
ap->mcast_all = 0;
#if 0
{ long myjif = jiffies + HZ;
......@@ -1338,8 +1388,9 @@ static int ace_close(struct device *dev)
for (i = 0; i < TX_RING_ENTRIES; i++) {
if (ap->tx_skbuff[i]) {
ap->tx_ring[i].size = 0;
ap->tx_ring[i].addr = 0;
writel(0, &ap->tx_ring[i].addr.addrhi);
writel(0, &ap->tx_ring[i].addr.addrlo);
writel(0, &ap->tx_ring[i].flagsize);
dev_kfree_skb(ap->tx_skbuff[i]);
}
}
......@@ -1359,30 +1410,37 @@ static int ace_start_xmit(struct sk_buff *skb, struct device *dev)
struct ace_private *ap = (struct ace_private *)dev->priv;
struct ace_regs *regs = ap->regs;
unsigned long flags;
u32 idx;
unsigned long addr;
u32 idx, flagsize;
spin_lock_irqsave(&ap->lock, flags);
idx = ap->tx_prd;
ap->tx_skbuff[idx] = skb;
ap->tx_ring[idx].addr = virt_to_bus(skb->data);
ap->tx_ring[idx].size = skb->len;
ap->tx_ring[idx].flags = DESC_END;
addr = virt_to_bus(skb->data);
#if (BITS_PER_LONG == 64)
writel(addr >> 32, &ap->tx_ring[idx].addr.addrhi);
#endif
writel(addr & 0xffffffff, &ap->tx_ring[idx].addr.addrlo);
flagsize = (skb->len << 16) | (DESC_END) ;
writel(flagsize, &ap->tx_ring[idx].flagsize);
mb();
idx = (idx + 1) % TX_RING_ENTRIES;
ap->tx_prd = idx;
regs->TxPrd = idx;
writel(idx, &regs->TxPrd);
if ((idx + 1) % TX_RING_ENTRIES == ap->tx_ret_csm){
ap->tx_full = 1;
set_bit(0, (void*)&dev->tbusy);
/*
* Queue is full, add timer to detect whether the
* transmitter is stuck.
* transmitter is stuck. Use mod_timer as we can get
* into the situation where we risk adding several
* timers.
*/
ap->timer.expires = jiffies + (3 * HZ);
add_timer(&ap->timer);
mod_timer(&ap->timer, jiffies + (3 * HZ));
}
spin_unlock_irqrestore(&ap->lock, flags);
......@@ -1400,7 +1458,7 @@ static int ace_change_mtu(struct device *dev, int new_mtu)
if ((new_mtu < 68) || (new_mtu > ACE_JUMBO_MTU))
return -EINVAL;
regs->IfMtu = new_mtu + ETH_HLEN + 4;
writel(new_mtu + ETH_HLEN + 4, &regs->IfMtu);
dev->mtu = new_mtu;
if (new_mtu > ACE_STD_MTU){
......@@ -1442,8 +1500,8 @@ static int ace_set_mac_addr(struct device *dev, void *p)
da = (u16 *)dev->dev_addr;
regs = ((struct ace_private *)dev->priv)->regs;
regs->MacAddrHi = da[0];
regs->MacAddrLo = (da[1] << 16) | da[2];
writel(da[0], &regs->MacAddrHi);
writel((da[1] << 16) | da[2], &regs->MacAddrLo);
cmd.evt = C_SET_MAC_ADDR;
cmd.code = 0;
......@@ -1460,21 +1518,51 @@ static void ace_set_multicast_list(struct device *dev)
struct ace_regs *regs = ap->regs;
struct cmd cmd;
if ((dev->flags & IFF_ALLMULTI) && !(ap->mcast_all)) {
cmd.evt = C_SET_MULTICAST_MODE;
cmd.code = C_C_MCAST_ENABLE;
cmd.idx = 0;
ace_issue_cmd(regs, &cmd);
ap->mcast_all = 1;
} else if (ap->mcast_all){
cmd.evt = C_SET_MULTICAST_MODE;
cmd.code = C_C_MCAST_ENABLE;
cmd.idx = 0;
ace_issue_cmd(regs, &cmd);
ap->mcast_all = 0;
}
if ((dev->flags & IFF_PROMISC) && !(ap->promisc)) {
cmd.evt = C_SET_PROMISC_MODE;
cmd.code = C_C_PROMISC_ENABLE;
cmd.idx = 0;
ace_issue_cmd(regs, &cmd);
ap->promisc = 1;
}else if (!(dev->flags & IFF_PROMISC) && (ap->promisc)){
cmd.evt = C_SET_PROMISC_MODE;
cmd.code = C_C_PROMISC_DISABLE;
cmd.idx = 0;
ace_issue_cmd(regs, &cmd);
ap->promisc = 0;
}
/*
* For the time being multicast relies on the upper layers
* filtering it properly. The Firmware does not allow one to
* set the entire multicast list at a time and keeping track of
* it here is going to be messy.
*/
if ((dev->mc_count) && !(ap->mcast_all)) {
cmd.evt = C_SET_MULTICAST_MODE;
cmd.code = C_C_MCAST_ENABLE;
cmd.idx = 0;
ace_issue_cmd(regs, &cmd);
}else if (!ap->mcast_all) {
cmd.evt = C_SET_MULTICAST_MODE;
cmd.code = C_C_MCAST_DISABLE;
cmd.idx = 0;
ace_issue_cmd(regs, &cmd);
}
}
......@@ -1488,24 +1576,29 @@ static struct net_device_stats *ace_get_stats(struct device *dev)
__initfunc(void ace_copy(struct ace_regs *regs, void *src, u32 dest, int size))
{
int tsize;
u32 tdest;
unsigned long tdest;
u32 *wsrc;
short tsize, i;
if (size <= 0)
return;
while(size > 0){
while (size > 0){
tsize = min(((~dest & (ACE_WINDOW_SIZE - 1)) + 1),
min(size, ACE_WINDOW_SIZE));
tdest = dest & (ACE_WINDOW_SIZE - 1);
regs->WinBase = dest & ~(ACE_WINDOW_SIZE - 1);
tdest = (unsigned long)&regs->Window +
(dest & (ACE_WINDOW_SIZE - 1));
writel(dest & ~(ACE_WINDOW_SIZE - 1), &regs->WinBase);
#ifdef __BIG_ENDIAN
#error "data must be swapped here"
#else
#if 0
printk("copying %04x from %08x to %06x (Window addr %08x), winbase %02x\n", tsize, (unsigned)src, dest, (unsigned) ((void *)regs->Window + tdest), regs->WinBase);
#endif
memcpy((void *)((void *)regs->Window + tdest), src, tsize);
/*
* XXX - special memcpy needed here!!!
*/
wsrc = src;
for (i = 0; i < (tsize / 4); i++){
writel(wsrc[i], tdest + i*4);
}
#endif
dest += tsize;
src += tsize;
......@@ -1518,19 +1611,22 @@ __initfunc(void ace_copy(struct ace_regs *regs, void *src, u32 dest, int size))
__initfunc(void ace_clear(struct ace_regs *regs, u32 dest, int size))
{
int tsize = 0;
u32 tdest;
unsigned long tdest;
short tsize = 0, i;
if (size <= 0)
return;
while(size > 0){
while (size > 0){
tsize = min(((~dest & (ACE_WINDOW_SIZE - 1)) + 1),
min(size, ACE_WINDOW_SIZE));
tdest = dest & (ACE_WINDOW_SIZE - 1);
regs->WinBase = dest & ~(ACE_WINDOW_SIZE - 1);
tdest = (unsigned long)&regs->Window +
(dest & (ACE_WINDOW_SIZE - 1));
writel(dest & ~(ACE_WINDOW_SIZE - 1), &regs->WinBase);
memset((void *)((void *)regs->Window + tdest), 0, tsize);
for (i = 0; i < (tsize / 4); i++){
writel(0, tdest + i*4);
}
dest += tsize;
size -= tsize;
......@@ -1554,13 +1650,17 @@ __initfunc(int ace_load_firmware(struct device *dev))
ap = (struct ace_private *)dev->priv;
regs = ap->regs;
if (!(regs->CpuCtrl & CPU_HALTED)){
if (!(readl(&regs->CpuCtrl) & CPU_HALTED)){
printk(KERN_ERR "%s: trying to download firmware while the "
"CPU is running!\n", dev->name);
return -EFAULT;
}
ace_clear(regs, 0x2000, 0x100000-0x2000);
/*
* Do not try to clear more than 512KB or we end up seeing
* funny things on NICs with only 512KB SRAM
*/
ace_clear(regs, 0x2000, 0x80000-0x2000);
if (ap->version == 1){
ace_copy(regs, tigonFwText, tigonFwTextAddr, tigonFwTextLen);
ace_copy(regs, tigonFwData, tigonFwDataAddr, tigonFwDataLen);
......@@ -1595,36 +1695,56 @@ __initfunc(int ace_load_firmware(struct device *dev))
*/
static void eeprom_start(struct ace_regs *regs)
{
u32 local = readl(&regs->LocalCtrl);
udelay(1);
regs->LocalCtrl |= (EEPROM_DATA_OUT | EEPROM_WRITE_ENABLE);
local |= EEPROM_DATA_OUT | EEPROM_WRITE_ENABLE;
writel(local, &regs->LocalCtrl);
mb();
udelay(1);
regs->LocalCtrl |= EEPROM_CLK_OUT;
local |= EEPROM_CLK_OUT;
writel(local, &regs->LocalCtrl);
mb();
udelay(1);
regs->LocalCtrl &= ~EEPROM_DATA_OUT;
local &= ~EEPROM_DATA_OUT;
writel(local, &regs->LocalCtrl);
mb();
udelay(1);
regs->LocalCtrl &= ~EEPROM_CLK_OUT;
local &= ~EEPROM_CLK_OUT;
writel(local, &regs->LocalCtrl);
mb();
}
static void eeprom_prep(struct ace_regs *regs, u8 magic)
{
short i;
u32 local;
udelay(2);
regs->LocalCtrl &= ~EEPROM_DATA_OUT;
regs->LocalCtrl |= EEPROM_WRITE_ENABLE;
local = readl(&regs->LocalCtrl);
local &= ~EEPROM_DATA_OUT;
local |= EEPROM_WRITE_ENABLE;
writel(local, &regs->LocalCtrl);
mb();
for (i = 0; i < 8; i++, magic <<= 1) {
udelay(2);
if (magic & 0x80)
regs->LocalCtrl |= EEPROM_DATA_OUT;
local |= EEPROM_DATA_OUT;
else
regs->LocalCtrl &= ~EEPROM_DATA_OUT;
local &= ~EEPROM_DATA_OUT;
writel(local, &regs->LocalCtrl);
mb();
udelay(1);
regs->LocalCtrl |= EEPROM_CLK_OUT;
local |= EEPROM_CLK_OUT;
writel(local, &regs->LocalCtrl);
mb();
udelay(1);
regs->LocalCtrl &= ~(EEPROM_CLK_OUT | EEPROM_DATA_OUT);
local &= ~(EEPROM_CLK_OUT | EEPROM_DATA_OUT);
writel(local, &regs->LocalCtrl);
mb();
}
}
......@@ -1632,15 +1752,23 @@ static void eeprom_prep(struct ace_regs *regs, u8 magic)
static int eeprom_check_ack(struct ace_regs *regs)
{
int state;
regs->LocalCtrl &= ~EEPROM_WRITE_ENABLE;
u32 local;
local = readl(&regs->LocalCtrl);
local &= ~EEPROM_WRITE_ENABLE;
writel(local, &regs->LocalCtrl);
mb();
udelay(2);
regs->LocalCtrl |= EEPROM_CLK_OUT;
local |= EEPROM_CLK_OUT;
writel(local, &regs->LocalCtrl);
mb();
udelay(1);
/* sample data in middle of high clk */
state = (regs->LocalCtrl & EEPROM_DATA_IN) != 0;
state = (readl(&regs->LocalCtrl) & EEPROM_DATA_IN) != 0;
udelay(1);
regs->LocalCtrl &= ~EEPROM_CLK_OUT;
mb();
writel(readl(&regs->LocalCtrl) & ~EEPROM_CLK_OUT, &regs->LocalCtrl);
mb();
return state;
}
......@@ -1648,15 +1776,28 @@ static int eeprom_check_ack(struct ace_regs *regs)
static void eeprom_stop(struct ace_regs *regs)
{
regs->LocalCtrl |= EEPROM_WRITE_ENABLE;
u32 local;
local = readl(&regs->LocalCtrl);
local |= EEPROM_WRITE_ENABLE;
writel(local, &regs->LocalCtrl);
mb();
udelay(1);
regs->LocalCtrl &= ~EEPROM_DATA_OUT;
local &= ~EEPROM_DATA_OUT;
writel(local, &regs->LocalCtrl);
mb();
udelay(1);
regs->LocalCtrl |= EEPROM_CLK_OUT;
local |= EEPROM_CLK_OUT;
writel(local, &regs->LocalCtrl);
mb();
udelay(1);
regs->LocalCtrl |= EEPROM_DATA_OUT;
local |= EEPROM_DATA_OUT;
writel(local, &regs->LocalCtrl);
mb();
udelay(2);
regs->LocalCtrl &= ~EEPROM_CLK_OUT;
local &= ~EEPROM_CLK_OUT;
writel(local, &regs->LocalCtrl);
mb();
}
......@@ -1665,7 +1806,8 @@ static void eeprom_stop(struct ace_regs *regs)
*/
static u8 read_eeprom_byte(struct ace_regs *regs, unsigned long offset)
{
u32 i;
u32 local;
short i;
u8 result = 0;
if (!regs){
......@@ -1695,24 +1837,37 @@ static u8 read_eeprom_byte(struct ace_regs *regs, unsigned long offset)
return 0;
for (i = 0; i < 8; i++) {
regs->LocalCtrl &= ~EEPROM_WRITE_ENABLE;
local = readl(&regs->LocalCtrl);
local &= ~EEPROM_WRITE_ENABLE;
writel(local, &regs->LocalCtrl);
udelay(2);
regs->LocalCtrl |= EEPROM_CLK_OUT;
mb();
local |= EEPROM_CLK_OUT;
writel(local, &regs->LocalCtrl);
udelay(1);
mb();
/* sample data mid high clk */
result = (result << 1) |
((regs->LocalCtrl & EEPROM_DATA_IN) != 0);
((readl(&regs->LocalCtrl) & EEPROM_DATA_IN) != 0);
udelay(1);
regs->LocalCtrl &= ~EEPROM_CLK_OUT;
if (i == 7)
regs->LocalCtrl |= EEPROM_WRITE_ENABLE;
mb();
local = readl(&regs->LocalCtrl);
local &= ~EEPROM_CLK_OUT;
writel(local, &regs->LocalCtrl);
mb();
if (i == 7){
local |= EEPROM_WRITE_ENABLE;
writel(local, &regs->LocalCtrl);
mb();
}
}
regs->LocalCtrl |= EEPROM_DATA_OUT;
local |= EEPROM_DATA_OUT;
writel(local, &regs->LocalCtrl);
udelay(1);
regs->LocalCtrl |= EEPROM_CLK_OUT;
writel(readl(&regs->LocalCtrl) | EEPROM_CLK_OUT, &regs->LocalCtrl);
udelay(2);
regs->LocalCtrl &= ~EEPROM_CLK_OUT;
writel(readl(&regs->LocalCtrl) & ~EEPROM_CLK_OUT, &regs->LocalCtrl);
eeprom_stop(regs);
return result;
......@@ -1721,6 +1876,6 @@ static u8 read_eeprom_byte(struct ace_regs *regs, unsigned long offset)
/*
* Local variables:
* compile-command: "gcc -D__KERNEL__ -D__SMP__ -I/data/home/jes/linux/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 -DCPU=686 -DMODULE -DMODVERSIONS -include /data/home/jes/linux/include/linux/modversions.h -c -o acenic.o acenic.c"
* compile-command: "gcc -D__KERNEL__ -D__SMP__ -DMODULE -I/data/home/jes/linux/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -DMODVERSIONS -include /data/home/jes/linux/include/linux/modversions.h -c -o acenic.o acenic.c"
* End:
*/
#ifndef _ACENIC_H_
#define _ACENIC_H_
#if ((BITS_PER_LONG != 32) && (BITS_PER_LONG != 64))
#error "BITS_PER_LONG not defined or not valid"
/*
* Addressing:
*
* The Tigon uses 64-bit host addresses, regardless of their actual
* length, and it expects a big-endian format. For 32 bit systems the
* upper 32 bits of the address are simply ignored (zero), however for
* little endian 64 bit systems (Alpha) this looks strange with the
* two parts of the address word being swapped.
*
* The addresses are split in two 32 bit words for all architectures
* as some of them are in PCI shared memory and it is necessary to use
* readl/writel to access them.
*
* The addressing code is derived from Pete Beckman's work, but
* modified to deal properly with readl/writel usage.
*/
typedef struct {
u32 addrhi;
u32 addrlo;
} aceaddr;
static inline void set_aceaddr(aceaddr *aa, volatile void *addr)
{
unsigned long baddr = virt_to_bus((void *)addr);
#if (BITS_PER_LONG == 64)
aa->addrlo = baddr & 0xffffffff;
aa->addrhi = baddr >> 32;
#else
/* Don't bother setting zero every time */
aa->addrlo = baddr;
#endif
mb();
}
struct ace_regs {
static inline void set_aceaddr_bus(aceaddr *aa, volatile void *addr)
{
unsigned long baddr = (unsigned long)addr;
#if (BITS_PER_LONG == 64)
aa->addrlo = baddr & 0xffffffff;
aa->addrhi = baddr >> 32;
#else
/* Don't bother setting zero every time */
aa->addrlo = baddr;
#endif
mb();
}
static inline void *get_aceaddr(aceaddr *aa)
{
unsigned long addr;
mb();
#if (BITS_PER_LONG == 64)
addr = (u64)aa->addrhi << 32 | aa->addrlo;
#else
addr = aa->addrlo;
#endif
return bus_to_virt(addr);
}
static inline void *get_aceaddr_bus(aceaddr *aa)
{
unsigned long addr;
mb();
#if (BITS_PER_LONG == 64)
addr = (u64)aa->addrhi << 32 | aa->addrlo;
#else
addr = aa->addrlo;
#endif
return (void *)addr;
}
struct ace_regs {
u32 pad0[16]; /* PCI control registers */
u32 HostCtrl; /* 0x40 */
......@@ -109,7 +180,7 @@ struct ace_regs {
u32 ModeStat;
u32 DmaReadCfg;
u32 DmaWriteCfg; /* 0x620 */
u32 pad15;
u32 TxBufRat;
u32 EvtCsm;
u32 CmdCsm;
u32 TuneRxCoalTicks;/* 0x630 */
......@@ -220,6 +291,7 @@ struct ace_regs {
#define ACE_BYTE_SWAP_DATA 0x10
#define ACE_WARN 0x08
#define ACE_WORD_SWAP 0x04
#define ACE_NO_JUMBO_FRAG 0x200
#define ACE_FATAL 0x40000000
......@@ -227,7 +299,7 @@ struct ace_regs {
* DMA config
*/
#define DMA_THRESH_8W 0x80;
#define DMA_THRESH_8W 0x80
/*
......@@ -366,19 +438,19 @@ struct cmd {
#define DESC_MORE 0x08
/*
* RX control block flags
* Control block flags
*/
#define RX_TCP_UDP_SUM 0x01
#define RX_IP_SUM 0x02
#define RX_SPLIT_HDRS 0x04
#define RX_NO_PSEUDO_HDR_SUM 0x08
#define FLG_RX_TCP_UDP_SUM 0x01
#define FLG_RX_IP_SUM 0x02
#define FLG_RX_SPLIT_HDRS 0x04
#define FLG_RX_NO_PSDO_HDR_SUM 0x08
#define FLG_RNG_DISABLED 0x200
/*
* Descriptor flags
*/
#define JUMBO_FLAG 0x10
#define DFLG_RX_JUMBO 0x10
/*
* TX ring
......@@ -389,18 +461,20 @@ struct cmd {
#define TX_RING_BASE 0x3800
struct tx_desc{
#if (BITS_PER_LONG == 64)
u64 addr;
#else
u32 zero;
u32 addr;
#endif
aceaddr addr;
u32 flagsize;
#if 0
/*
* This is in PCI shared mem and must be accessed with readl/writel
* real layout is:
*/
#if __LITTLE_ENDIAN
u16 flags;
u16 size;
#else
u16 size;
u16 flags;
#endif
#endif
u32 nic_addr;
};
......@@ -412,19 +486,18 @@ struct tx_desc{
#define RX_JUMBO_RING_ENTRIES 256
#define RX_JUMBO_RING_SIZE (RX_JUMBO_RING_ENTRIES *sizeof(struct rx_desc))
#define RX_RETURN_RING_ENTRIES (2 * RX_STD_RING_ENTRIES)
#define RX_RETURN_RING_SIZE (RX_RETURN_RING_ENTRIES * \
#define RX_MINI_RING_ENTRIES 1024
#define RX_MINI_RING_SIZE (RX_MINI_RING_ENTRIES *sizeof(struct rx_desc))
#define RX_RETURN_RING_ENTRIES 2048
#define RX_RETURN_RING_SIZE (RX_MAX_RETURN_RING_ENTRIES * \
sizeof(struct rx_desc))
#define RX_RING_THRESH 32
#define RX_RING_THRESH 64
#define RX_RING_JUMBO_THRESH 48
struct rx_desc{
#if (BITS_PER_LONG == 64)
u64 addr;
#else
u32 zero;
u32 addr;
#endif
aceaddr addr;
#ifdef __LITTLE_ENDIAN
u16 size;
u16 idx;
......@@ -462,12 +535,7 @@ struct rx_desc{
* This struct is shared with the NIC firmware.
*/
struct ring_ctrl {
#if (BITS_PER_LONG == 64)
u64 rngptr;
#else
u32 zero;
u32 rngptr;
#endif
aceaddr rngptr;
#ifdef __LITTLE_ENDIAN
u16 flags;
u16 max_len;
......@@ -522,22 +590,12 @@ struct ace_info {
struct ring_ctrl tx_ctrl;
struct ring_ctrl rx_std_ctrl;
struct ring_ctrl rx_jumbo_ctrl;
struct ring_ctrl rx_mini_ctrl;
struct ring_ctrl rx_return_ctrl;
#if (BITS_PER_LONG == 64)
u64 evt_prd_ptr;
u64 rx_ret_prd_ptr;
u64 tx_csm_ptr;
u64 stats2_ptr;
#else
u32 evt_prd_ptr_hi;
u32 evt_prd_ptr;
u32 rx_ret_prd_ptr_hi;
u32 rx_ret_prd_ptr;
u32 tx_csm_ptr_hi;
u32 tx_csm_ptr;
u32 stats2_ptr_hi;
u32 stats2_ptr;
#endif
aceaddr evt_prd_ptr;
aceaddr rx_ret_prd_ptr;
aceaddr tx_csm_ptr;
aceaddr stats2_ptr;
};
/*
......@@ -555,6 +613,9 @@ struct ace_private
struct tx_desc *tx_ring;
struct rx_desc rx_std_ring[RX_STD_RING_ENTRIES];
struct rx_desc rx_jumbo_ring[RX_JUMBO_RING_ENTRIES];
#if 0
struct rx_desc rx_mini_ring[RX_MINI_RING_ENTRIES];
#endif
struct rx_desc rx_return_ring[RX_RETURN_RING_ENTRIES];
struct event evt_ring[EVT_RING_ENTRIES];
struct ace_info *info;
......@@ -576,7 +637,7 @@ struct ace_private
struct device *next
__attribute__ ((aligned (L1_CACHE_BYTES)));
unsigned char *trace_buf;
int fw_running, fw_up, jumbo, promisc;
int fw_running, fw_up, jumbo, promisc, mcast_all;
int version;
int flags;
u16 vendor;
......@@ -598,7 +659,7 @@ static int ace_load_std_rx_ring(struct device *dev);
static int ace_load_jumbo_rx_ring(struct device *dev);
static int ace_flush_jumbo_rx_ring(struct device *dev);
static void ace_interrupt(int irq, void *dev_id, struct pt_regs *regs);
static int ace_load_firmware(struct device *dev);
static int ace_open(struct device *dev);
static int ace_start_xmit(struct sk_buff *skb, struct device *dev);
static int ace_close(struct device *dev);
......
This source diff could not be displayed because it is too large. You can view the blob instead.
/*+M*************************************************************************
* Perceptive Solutions, Inc. PCI-2000 device driver proc support for Linux.
*
* Copyright (c) 1997 Perceptive Solutions, Inc.
* Copyright (c) 1999 Perceptive Solutions, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -20,13 +20,24 @@
*
* File Name: pci2000i.c
*
* Revisions 1.10 Jan-21-1999
* - Fixed sign on message to reflect proper controller name.
* - Added support for RAID status monitoring and control.
*
* Revisions 1.11 Mar-22-1999
* - Fixed control timeout to not lock up the entire system if
* controller goes offline completely.
*
*-M*************************************************************************/
#define PCI2000_VERSION "1.11"
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/head.h>
#include <linux/types.h>
#include <linux/string.h>
#include <linux/bios32.h>
#include <linux/pci.h>
#include <linux/ioport.h>
#include <linux/delay.h>
......@@ -34,7 +45,6 @@
#include <linux/proc_fs.h>
#include <asm/dma.h>
#include <asm/system.h>
#include <asm/spinlock.h>
#include <asm/io.h>
#include <linux/blk.h>
#include "scsi.h"
......@@ -89,7 +99,6 @@ typedef struct
static struct Scsi_Host *PsiHost[MAXADAPTER] = {NULL,}; // One for each adapter
static int NumAdapters = 0;
/****************************************************************
* Name: WaitReady :LOCAL
*
......@@ -102,13 +111,14 @@ static int NumAdapters = 0;
****************************************************************/
static int WaitReady (PADAPTER2000 padapter)
{
ULONG timer;
ULONG z;
timer = jiffies + TIMEOUT_COMMAND; // calculate the timeout value
do {
for ( z = 0; z < (TIMEOUT_COMMAND * 4); z++ )
{
if ( !inb_p (padapter->cmd) )
return FALSE;
} while ( timer > jiffies ); // test for timeout
udelay (250);
};
return TRUE;
}
/****************************************************************
......@@ -180,6 +190,26 @@ static int BuildSgList (Scsi_Cmnd *SCpnt, PADAPTER2000 padapter, PDEV2000 pdev)
outl (SCpnt->request_bufflen, padapter->mb3);
return TRUE;
}
/*********************************************************************
* Name: PsiRaidCmd
*
* Description: Execute a simple command.
*
* Parameters: padapter - Pointer to adapter control structure.
* cmd - Roy command byte.
*
* Returns: Return error status.
*
********************************************************************/
static int PsiRaidCmd (PADAPTER2000 padapter, char cmd)
{
if ( WaitReady (padapter) ) // test for command register ready
return DID_TIME_OUT;
outb_p (cmd, padapter->cmd); // issue command
if ( WaitReady (padapter) ) // wait for adapter ready
return DID_TIME_OUT;
return DID_OK;
}
/****************************************************************
* Name: Irq_Handler :LOCAL
*
......@@ -366,7 +396,35 @@ int Pci2000_QueueCommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
switch ( *cdb )
{
case SCSIOP_INQUIRY: // inquiry CDB
{
if ( cdb[2] == SC_MY_RAID )
{
switch ( cdb[3] )
{
case MY_SCSI_REBUILD:
OpDone (SCpnt, PsiRaidCmd (padapter, CMD_RAID_REBUILD) << 16);
return 0;
case MY_SCSI_ALARMMUTE:
OpDone (SCpnt, PsiRaidCmd (padapter, CMD_RAID_MUTE) << 16);
return 0;
case MY_SCSI_DEMOFAIL:
OpDone (SCpnt, PsiRaidCmd (padapter, CMD_RAID_FAIL) << 16);
return 0;
default:
if ( SCpnt->use_sg )
{
rc = DID_ERROR;
goto finished;
}
else
outl (virt_to_bus (SCpnt->request_buffer), padapter->mb2);
outl (cdb[5], padapter->mb0);
outl (cdb[3], padapter->mb3);
cmd = CMD_DASD_RAID_RQ;
break;
}
break;
}
if ( SCpnt->use_sg )
{
outl (virt_to_bus (((struct scatterlist *)(SCpnt->request_buffer))->address), padapter->mb2);
......@@ -378,7 +436,6 @@ int Pci2000_QueueCommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
outl (SCpnt->request_bufflen, padapter->mb3);
cmd = CMD_DASD_SCSI_INQ;
break;
}
case SCSIOP_TEST_UNIT_READY: // test unit ready CDB
outl (virt_to_bus (SCpnt->sense_buffer), padapter->mb2);
......@@ -466,14 +523,6 @@ finished:;
OpDone (SCpnt, rc << 16);
return 0;
}
static void do_Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
{
unsigned long flags;
spin_lock_irqsave(&io_request_lock, flags);
Irq_Handler(irq, dev_id, regs);
spin_unlock_irqrestore(&io_request_lock, flags);
}
/****************************************************************
* Name: internal_done :LOCAL
*
......@@ -524,17 +573,23 @@ int Pci2000_Detect (Scsi_Host_Template *tpnt)
int pci_index = 0;
struct Scsi_Host *pshost;
PADAPTER2000 padapter;
int z;
int z, zz;
int setirq;
struct pci_dev *pdev = NULL;
if ( pci_present () )
while ((pdev = pci_find_device(VENDOR_PSI, DEVICE_ROY_1, pdev)))
if ( pcibios_present () )
{
for ( pci_index = 0; pci_index <= MAXADAPTER; ++pci_index )
{
UCHAR pci_bus, pci_device_fn;
if ( pcibios_find_device (VENDOR_PSI, DEVICE_ROY_1, pci_index, &pci_bus, &pci_device_fn) != 0 )
break;
pshost = scsi_register (tpnt, sizeof(ADAPTER2000));
padapter = HOSTDATA(pshost);
padapter->basePort = pdev->base_address[1] & PCI_BASE_ADDRESS_IO_MASK;
pcibios_read_config_word (pci_bus, pci_device_fn, PCI_BASE_ADDRESS_1, &padapter->basePort);
padapter->basePort &= 0xFFFE;
DEB (printk ("\nBase Regs = %#04X", padapter->basePort)); // get the base I/O port address
padapter->mb0 = padapter->basePort + RTR_MAILBOX; // get the 32 bit mail boxes
padapter->mb1 = padapter->basePort + RTR_MAILBOX + 4;
......@@ -551,35 +606,40 @@ int Pci2000_Detect (Scsi_Host_Template *tpnt)
if ( WaitReady (padapter) )
goto unregister;
pshost->irq = pdev->irq;
pcibios_read_config_byte (pci_bus, pci_device_fn, PCI_INTERRUPT_LINE, &pshost->irq);
setirq = 1;
for ( z = 0; z < pci_index; z++ ) // scan for shared interrupts
for ( z = 0; z < pci_index; z++ ) // scan for shared interrupts
{
if ( PsiHost[z]->irq == pshost->irq ) // if shared then, don't posses
if ( PsiHost[z]->irq == pshost->irq ) // if shared then, don't posses
setirq = 0;
}
if ( setirq ) // if not shared, posses
if ( setirq ) // if not shared, posses
{
if ( request_irq (pshost->irq, do_Irq_Handler, 0, "pci2000", NULL) )
if ( request_irq (pshost->irq, Irq_Handler, 0, "pci2000", NULL) )
{
printk ("Unable to allocate IRQ for PSI-2000 controller.\n");
goto unregister;
}
}
PsiHost[pci_index] = pshost; // save SCSI_HOST pointer
PsiHost[pci_index] = pshost; // save SCSI_HOST pointer
pshost->unique_id = padapter->basePort;
pshost->max_id = 16;
pshost->max_channel = 1;
printk("\nPSI-2000 EIDE CONTROLLER: at I/O = %X IRQ = %d\n", padapter->basePort, pshost->irq);
printk("(C) 1997 Perceptive Solutions, Inc. All rights reserved\n\n");
NumAdapters++;
for ( zz = 0; zz < MAX_BUS; zz++ )
for ( z = 0; z < MAX_UNITS; z++ )
padapter->dev[zz][z].tag = 0;
printk("\nPSI-2000 Intelligent Storage SCSI CONTROLLER: at I/O = %X IRQ = %d\n", padapter->basePort, pshost->irq);
printk("Version %s, Compiled %s %s\n\n", PCI2000_VERSION, __DATE__, __TIME__);
continue;
unregister:;
scsi_unregister (pshost);
}
return NumAdapters;
}
NumAdapters = pci_index;
return pci_index;
}
/****************************************************************
* Name: Pci2220i_Abort
......@@ -653,7 +713,7 @@ int Pci2000_BiosParam (Scsi_Disk *disk, kdev_t dev, int geom[])
#ifdef MODULE
/* Eventually this will go into an include file, but this will be later */
Scsi_Host_Template driver_template = PCI2000;
Scsi_Host_Template driver_template = PCI2220I;
#include "scsi_module.c"
#endif
......
......@@ -202,18 +202,25 @@ int Pci2000_BiosParam (Disk *disk, kdev_t dev, int geom[]);
extern struct proc_dir_entry Proc_Scsi_Pci2000;
#define PCI2000 { proc_dir: &Proc_Scsi_Pci2000,/* proc_dir_entry */ \
name: "PCI-2000 SCSI Intelligent Disk Controller",\
detect: Pci2000_Detect, \
command: Pci2000_Command, \
queuecommand: Pci2000_QueueCommand, \
abort: Pci2000_Abort, \
reset: Pci2000_Reset, \
bios_param: Pci2000_BiosParam, \
can_queue: 16, \
this_id: -1, \
sg_tablesize: 16, \
cmd_per_lun: 1, \
use_clustering: DISABLE_CLUSTERING }
#define PCI2000 { NULL, NULL, \
&Proc_Scsi_Pci2000,/* proc_dir_entry */ \
NULL, \
"PCI-2000 SCSI Intelligent Disk Controller",\
Pci2000_Detect, \
NULL, \
NULL, \
Pci2000_Command, \
Pci2000_QueueCommand, \
Pci2000_Abort, \
Pci2000_Reset, \
NULL, \
Pci2000_BiosParam, \
16, \
-1, \
16, \
1, \
0, \
0, \
DISABLE_CLUSTERING }
#endif
/*+M*************************************************************************
* Perceptive Solutions, Inc. PCI-2000 device driver proc support for Linux.
* Perceptive Solutions, Inc. PCI-22220I device driver proc support for Linux.
*
* Copyright (c) 1997 Perceptive Solutions, Inc.
* Copyright (c) 1999 Perceptive Solutions, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -25,56 +25,51 @@
*-M*************************************************************************/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/head.h>
#include <linux/types.h>
#include <linux/string.h>
#include <linux/bios32.h>
#include <linux/pci.h>
#include <linux/ioport.h>
#include <linux/delay.h>
#include <linux/sched.h>
#include <linux/proc_fs.h>
#include <linux/stat.h>
#include <linux/kdev_t.h>
#include <linux/blk.h>
#include <linux/timer.h>
#include <asm/dma.h>
#include <asm/system.h>
#include <asm/spinlock.h>
#include <asm/io.h>
#include <linux/blk.h>
#include "scsi.h"
#include "hosts.h"
#include "pci2220i.h"
#include "psi_dale.h"
#include<linux/stat.h>
#define PCI2220I_VERSION "1.10"
//#define READ_CMD IDE_COMMAND_READ
//#define WRITE_CMD IDE_COMMAND_WRITE
//#define MAX_BUS_MASTER_BLOCKS 1 // This is the maximum we can bus master
#define READ_CMD IDE_CMD_READ_MULTIPLE
#define WRITE_CMD IDE_CMD_WRITE_MULTIPLE
#define MAX_BUS_MASTER_BLOCKS SECTORSXFER // This is the maximum we can bus master
struct proc_dir_entry Proc_Scsi_Pci2220i =
{ PROC_SCSI_PCI2220I, 7, "pci2220i", S_IFDIR | S_IRUGO | S_IXUGO, 2 };
{ PROC_SCSI_PCI2220I, 8, "pci2220i", S_IFDIR | S_IRUGO | S_IXUGO, 2 };
//#define DEBUG 1
#ifdef DEBUG
#define DEB(x) x
#define STOP_HERE {int st;for(st=0;st<100;st++){st=1;}}
#define STOP_HERE() {int st;for(st=0;st<100;st++){st=1;}}
#else
#define DEB(x)
#define STOP_HERE
#define STOP_HERE()
#endif
#define MAXADAPTER 4 /* Increase this and the sizes of the arrays below, if you need more. */
#define MAX_BUS_MASTER_BLOCKS 1 // This is the maximum we can bus master for (1024 bytes)
#define MAXADAPTER 4 // Increase this and the sizes of the arrays below, if you need more.
#define PORT_DATA 0
#define PORT_ERROR 1
#define PORT_SECTOR_COUNT 2
#define PORT_LBA_0 3
#define PORT_LBA_8 4
#define PORT_LBA_16 5
#define PORT_LBA_24 6
#define PORT_STAT_CMD 7
#define PORT_STAT_SEL 8
#define PORT_FAIL 9
#define PORT_ALT_STAT 10
typedef struct
{
......@@ -87,44 +82,245 @@ typedef struct
USHORT cylinders; // number of cylinders for this device
USHORT spareword; // placeholder
ULONG blocks; // number of blocks on device
} OUR_DEVICE, *POUR_DEVICE;
DISK_MIRROR DiskMirror[2]; // RAID status and control
ULONG lastsectorlba[2]; // last addressable sector on the drive
USHORT raid; // RAID active flag
USHORT mirrorRecon;
UCHAR hotRecon;
USHORT reconCount;
} OUR_DEVICE, *POUR_DEVICE;
typedef struct
{
USHORT ports[12];
USHORT regDmaDesc; // address of the DMA discriptor register for direction of transfer
USHORT regDmaCmdStat; // Byte #1 of DMA command status register
USHORT regDmaAddrPci; // 32 bit register for PCI address of DMA
USHORT regDmaAddrLoc; // 32 bit register for local bus address of DMA
USHORT regDmaCount; // 32 bit register for DMA transfer count
USHORT regDmaMode; // 32 bit register for DMA mode control
USHORT regRemap; // 32 bit local space remap
USHORT regDesc; // 32 bit local region descriptor
USHORT regRange; // 32 bit local range
USHORT regIrqControl; // 16 bit Interrupt enable/disable and status
USHORT regScratchPad; // scratch pad I/O base address
USHORT regBase; // Base I/O register for data space
USHORT basePort; // PLX base I/O port
USHORT timingMode; // timing mode currently set for adapter
ULONG timingAddress; // address to use on adapter for current timing mode
OUR_DEVICE device[4];
IDE_STRUCT ide;
USHORT regDmaDesc; // address of the DMA discriptor register for direction of transfer
USHORT regDmaCmdStat; // Byte #1 of DMA command status register
USHORT regDmaAddrPci; // 32 bit register for PCI address of DMA
USHORT regDmaAddrLoc; // 32 bit register for local bus address of DMA
USHORT regDmaCount; // 32 bit register for DMA transfer count
USHORT regDmaMode; // 32 bit register for DMA mode control
USHORT regRemap; // 32 bit local space remap
USHORT regDesc; // 32 bit local region descriptor
USHORT regRange; // 32 bit local range
USHORT regIrqControl; // 16 bit Interrupt enable/disable and status
USHORT regScratchPad; // scratch pad I/O base address
USHORT regBase; // Base I/O register for data space
USHORT regData; // data register I/O address
USHORT regError; // error register I/O address
USHORT regSectCount; // sector count register I/O address
USHORT regLba0; // least significant byte of LBA
USHORT regLba8; // next least significant byte of LBA
USHORT regLba16; // next most significan byte of LBA
USHORT regLba24; // head and most 4 significant bits of LBA
USHORT regStatCmd; // status on read and command on write register
USHORT regStatSel; // board status on read and spigot select on write register
USHORT regFail; // fail bits control register
USHORT regAltStat; // alternate status and drive control register
USHORT basePort; // PLX base I/O port
USHORT timingMode; // timing mode currently set for adapter
USHORT timingPIO; // TRUE if PIO timing is active
ULONG timingAddress; // address to use on adapter for current timing mode
OUR_DEVICE device[DALE_MAXDRIVES];
DISK_MIRROR *raidData[8];
ULONG startSector;
USHORT sectorCount;
UCHAR cmd;
Scsi_Cmnd *SCpnt;
VOID *buffer;
POUR_DEVICE pdev; // current device opearating on
USHORT expectingIRQ;
USHORT readPhase;
USHORT reconIsStarting; // indicate hot reconstruct is starting
USHORT reconOn; // Hot reconstruct is to be done.
USHORT reconPhase; // Hot reconstruct operation is in progress.
ULONG reconSize;
USHORT demoFail; // flag for RAID failure demonstration
USHORT survivor;
USHORT failinprog;
USHORT timeoutReconRetry;
struct timer_list reconTimer;
struct timer_list timer;
} ADAPTER2220I, *PADAPTER2220I;
#define HOSTDATA(host) ((PADAPTER2220I)&host->hostdata)
#define RECON_PHASE_READY 0x01
#define RECON_PHASE_COPY 0x02
#define RECON_PHASE_UPDATE 0x03
#define RECON_PHASE_LAST 0x04
#define RECON_PHASE_END 0x07
#define RECON_PHASE_MARKING 0x80
#define RECON_PHASE_FAILOVER 0xFF
static struct Scsi_Host *PsiHost[MAXADAPTER] = {NULL,}; // One for each adapter
static int NumAdapters = 0;
static IDENTIFY_DATA identifyData;
static SETUP DaleSetup;
static DISK_MIRROR DiskMirror[2];
static ULONG ModeArray[] = {DALE_DATA_MODE2, DALE_DATA_MODE3, DALE_DATA_MODE4, DALE_DATA_MODE4P};
static UCHAR Buffer[SECTORSXFER * BYTES_PER_SECTOR];
static void ReconTimerExpiry (unsigned long data);
/****************************************************************
* Name: MuteAlarm :LOCAL
*
* Description: Mute the audible alarm.
*
* Parameters: padapter - Pointer adapter data structure.
*
* Returns: TRUE if drive does not assert DRQ in time.
*
****************************************************************/
static void MuteAlarm (PADAPTER2220I padapter)
{
UCHAR old;
old = (inb_p (padapter->regStatSel) >> 3) | (inb_p (padapter->regStatSel) & 0x83);
outb_p (old | 0x40, padapter->regFail);
}
/****************************************************************
* Name: WaitReady :LOCAL
*
* Description: Wait for device ready.
*
* Parameters: padapter - Pointer adapter data structure.
*
* Returns: TRUE if drive does not assert DRQ in time.
*
****************************************************************/
static int WaitReady (PADAPTER2220I padapter)
{
ULONG z;
UCHAR status;
for ( z = 0; z < (TIMEOUT_READY * 4); z++ )
{
status = inb_p (padapter->regStatCmd);
if ( (status & (IDE_STATUS_DRDY | IDE_STATUS_BUSY)) == IDE_STATUS_DRDY )
return 0;
udelay (250);
}
return status;
}
/****************************************************************
* Name: WaitReadyReset :LOCAL
*
* Description: Wait for device ready.
*
* Parameters: padapter - Pointer adapter data structure.
*
* Returns: TRUE if drive does not assert DRQ in time.
*
****************************************************************/
static int WaitReadyReset (PADAPTER2220I padapter)
{
ULONG z;
UCHAR status;
for ( z = 0; z < (250 * 4); z++ ) // wait up to 1/4 second
{
status = inb_p (padapter->regStatCmd);
if ( (status & (IDE_STATUS_DRDY | IDE_STATUS_BUSY)) == IDE_STATUS_DRDY )
{
DEB (printk ("\nPCI2220I: Reset took %ld mSec to be ready", z / 4));
return 0;
}
udelay (250);
}
DEB (printk ("\nPCI2220I: Reset took more than 1 Second to come ready, Disk Failure"));
return status;
}
/****************************************************************
* Name: WaitDrq :LOCAL
*
* Description: Wait for device ready for data transfer.
*
* Parameters: padapter - Pointer adapter data structure.
*
* Returns: TRUE if drive does not assert DRQ in time.
*
****************************************************************/
static int WaitDrq (PADAPTER2220I padapter)
{
ULONG z;
UCHAR status;
for ( z = 0; z < (TIMEOUT_DRQ * 4); z++ )
{
status = inb_p (padapter->regStatCmd);
if ( status & IDE_STATUS_DRQ )
return 0;
udelay (250);
}
return status;
}
/****************************************************************
* Name: HardReset :LOCAL
*
* Description: Wait for device ready for data transfer.
*
* Parameters: padapter - Pointer adapter data structure.
* pdev - Pointer to device.
* spigot - Spigot number.
*
* Returns: TRUE if drive does not assert DRQ in time.
*
****************************************************************/
static int HardReset (PADAPTER2220I padapter, POUR_DEVICE pdev, UCHAR spigot)
{
SelectSpigot (padapter, spigot | 0x80);
outb_p (0x0E, padapter->regAltStat); // reset the suvivor
udelay (100); // wait a little
outb_p (0x08, padapter->regAltStat); // clear the reset
udelay (100);
outb_p (0xA0, padapter->regLba24); //Specify drive
outb_p (pdev->byte6, padapter->regLba24); // select the drive
if ( WaitReadyReset (padapter) )
return TRUE;
outb_p (SECTORSXFER, padapter->regSectCount);
WriteCommand (padapter, IDE_CMD_SET_MULTIPLE);
if ( WaitReady (padapter) )
return TRUE;
return FALSE;
}
/****************************************************************
* Name: BusMaster :LOCAL
*
* Description: Do a bus master I/O.
*
* Parameters: padapter - Pointer adapter data structure.
* datain - TRUE if data read.
* irq - TRUE if bus master interrupt expected.
*
* Returns: TRUE if drive does not assert DRQ in time.
*
****************************************************************/
static void BusMaster (PADAPTER2220I padapter, UCHAR datain, UCHAR irq)
{
ULONG zl;
outl (padapter->timingAddress, padapter->regDmaAddrLoc);
outl (virt_to_bus (padapter->buffer), padapter->regDmaAddrPci);
zl = (padapter->sectorCount > MAX_BUS_MASTER_BLOCKS) ? MAX_BUS_MASTER_BLOCKS : padapter->sectorCount;
padapter->sectorCount -= zl;
zl *= (ULONG)BYTES_PER_SECTOR;
padapter->buffer += zl;
outl (zl, padapter->regDmaCount);
if ( datain )
{
outb_p (8, padapter->regDmaDesc); // read operation
if ( irq && !padapter->sectorCount )
outb_p (5, padapter->regDmaMode); // interrupt on
else
outb_p (1, padapter->regDmaMode); // no interrupt
}
else
{
outb_p (0, padapter->regDmaDesc); // write operation
outb_p (1, padapter->regDmaMode); // no interrupt
}
outb_p (0x03, padapter->regDmaCmdStat); // kick the DMA engine in gear
}
/****************************************************************
* Name: WriteData :LOCAL
*
......@@ -137,114 +333,224 @@ static SETUP DaleSetup;
****************************************************************/
static int WriteData (PADAPTER2220I padapter)
{
ULONG timer;
USHORT *pports = padapter->ports;
ULONG zl;
if ( !WaitDrq (padapter) )
{
if ( padapter->timingPIO )
{
zl = (padapter->sectorCount > MAX_BUS_MASTER_BLOCKS) ? MAX_BUS_MASTER_BLOCKS : padapter->sectorCount;
outsw (padapter->regData, padapter->buffer, zl * (BYTES_PER_SECTOR / 2));
padapter->sectorCount -= zl;
padapter->buffer += zl * BYTES_PER_SECTOR;
}
else
BusMaster (padapter, 0, 0);
return 0;
}
padapter->cmd = 0; // null out the command byte
return 1;
}
/****************************************************************
* Name: WriteDataBoth :LOCAL
*
* Description: Write data to device.
*
* Parameters: padapter - Pointer adapter data structure.
*
* Returns: TRUE if drive does not assert DRQ in time.
*
****************************************************************/
static int WriteDataBoth (PADAPTER2220I padapter)
{
ULONG zl;
UCHAR status0, status1;
timer = jiffies + TIMEOUT_DRQ; // calculate the timeout value
do {
if ( inb_p (pports[PORT_STAT_CMD]) & IDE_STATUS_DRQ )
SelectSpigot (padapter, 1);
status0 = WaitDrq (padapter);
if ( !status0 )
{
SelectSpigot (padapter, 2);
status1 = WaitDrq (padapter);
if ( !status1 )
{
outb_p (0, padapter->regDmaDesc); // write operation
outl (padapter->timingAddress, padapter->regDmaAddrLoc);
outl (virt_to_bus (padapter->buffer), padapter->regDmaAddrPci);
outl ((ULONG)padapter->ide.ide.ide[2] * (ULONG)512, padapter->regDmaCount);
outb_p (1, padapter->regDmaMode); // interrupts off
outb_p (0x03, padapter->regDmaCmdStat); // kick the DMA engine in gear
SelectSpigot (padapter, 3);
if ( padapter->timingPIO )
{
zl = (padapter->sectorCount > MAX_BUS_MASTER_BLOCKS) ? MAX_BUS_MASTER_BLOCKS : padapter->sectorCount;
outsw (padapter->regData, padapter->buffer, zl * (BYTES_PER_SECTOR / 2));
padapter->sectorCount -= zl;
padapter->buffer += zl * BYTES_PER_SECTOR;
}
else
BusMaster (padapter, 0, 0);
return 0;
}
} while ( timer > jiffies ); // test for timeout
padapter->ide.ide.ides.cmd = 0; // null out the command byte
return 1;
}
padapter->cmd = 0; // null out the command byte
if ( status0 )
return 1;
return 2;
}
/****************************************************************
* Name: IdeCmd :LOCAL
*
* Description: Process a queued command from the SCSI manager.
* Description: Process an IDE command.
*
* Parameters: padapter - Pointer adapter data structure.
* pdev - Pointer to device.
*
* Returns: Zero if no error or status register contents on error.
*
****************************************************************/
static UCHAR IdeCmd (PADAPTER2220I padapter)
static UCHAR IdeCmd (PADAPTER2220I padapter, POUR_DEVICE pdev)
{
ULONG timer;
USHORT *pports = padapter->ports;
UCHAR status;
outb_p (padapter->ide.ide.ides.spigot, pports[PORT_STAT_SEL]); // select the spigot
outb_p (padapter->ide.ide.ide[6], pports[PORT_LBA_24]); // select the drive
timer = jiffies + TIMEOUT_READY; // calculate the timeout value
DEB(printk ("\npci2220i Issueing new command: 0x%X",padapter->ide.ide.ides.cmd));
do {
status = inb_p (padapter->ports[PORT_STAT_CMD]);
if ( status & IDE_STATUS_DRDY )
{
outb_p (padapter->ide.ide.ide[2], pports[PORT_SECTOR_COUNT]);
outb_p (padapter->ide.ide.ide[3], pports[PORT_LBA_0]);
outb_p (padapter->ide.ide.ide[4], pports[PORT_LBA_8]);
outb_p (padapter->ide.ide.ide[5], pports[PORT_LBA_16]);
padapter->expectingIRQ = 1;
outb_p (padapter->ide.ide.ide[7], pports[PORT_STAT_CMD]);
if ( padapter->ide.ide.ides.cmd == IDE_CMD_WRITE_MULTIPLE )
return (WriteData (padapter));
return 0;
}
} while ( timer > jiffies ); // test for timeout
SelectSpigot (padapter, pdev->spigot); // select the spigot
outb_p (pdev->byte6 | ((UCHAR *)(&padapter->startSector))[3], padapter->regLba24); // select the drive
status = WaitReady (padapter);
if ( !status )
{
outb_p (padapter->sectorCount, padapter->regSectCount);
outb_p (((UCHAR *)(&padapter->startSector))[0], padapter->regLba0);
outb_p (((UCHAR *)(&padapter->startSector))[1], padapter->regLba8);
outb_p (((UCHAR *)(&padapter->startSector))[2], padapter->regLba16);
padapter->expectingIRQ = TRUE;
WriteCommand (padapter, padapter->cmd);
return 0;
}
padapter->ide.ide.ides.cmd = 0; // null out the command byte
padapter->cmd = 0; // null out the command byte
return status;
}
/****************************************************************
* Name: SetupTransfer :LOCAL
* Name: IdeCmdBoth :LOCAL
*
* Description: Setup a data transfer command.
* Description: Process an IDE command to both drivers.
*
* Parameters: padapter - Pointer adapter data structure.
* drive - Drive/head register upper nibble only.
*
* Returns: TRUE if no data to transfer.
* Returns: Zero if no error or spigot of error.
*
****************************************************************/
static int SetupTransfer (PADAPTER2220I padapter, UCHAR drive)
static UCHAR IdeCmdBoth (PADAPTER2220I padapter)
{
if ( padapter->sectorCount )
{
*(ULONG *)padapter->ide.ide.ides.lba = padapter->startSector;
padapter->ide.ide.ide[6] |= drive;
// padapter->ide.ide.ides.sectors = ( padapter->sectorCount > SECTORSXFER ) ? SECTORSXFER : padapter->sectorCount;
padapter->ide.ide.ides.sectors = ( padapter->sectorCount > MAX_BUS_MASTER_BLOCKS ) ? MAX_BUS_MASTER_BLOCKS : padapter->sectorCount;
padapter->sectorCount -= padapter->ide.ide.ides.sectors; // bump the start and count for next xfer
padapter->startSector += padapter->ide.ide.ides.sectors;
return 0;
UCHAR status0;
UCHAR status1;
SelectSpigot (padapter, 3); // select the spigots
outb_p (padapter->pdev->byte6 | ((UCHAR *)(&padapter->startSector))[3], padapter->regLba24);// select the drive
SelectSpigot (padapter, 1);
status0 = WaitReady (padapter);
if ( !status0 )
{
SelectSpigot (padapter, 2);
status1 = WaitReady (padapter);
if ( !status1 )
{
SelectSpigot (padapter, 3);
outb_p (padapter->sectorCount, padapter->regSectCount);
outb_p (((UCHAR *)(&padapter->startSector))[0], padapter->regLba0);
outb_p (((UCHAR *)(&padapter->startSector))[1], padapter->regLba8);
outb_p (((UCHAR *)(&padapter->startSector))[2], padapter->regLba16);
padapter->expectingIRQ = TRUE;
WriteCommand (padapter, padapter->cmd);
return 0;
}
}
padapter->cmd = 0; // null out the command byte
if ( status0 )
return 1;
return 2;
}
/****************************************************************
* Name: OpDone :LOCAL
*
* Description: Complete an operatoin done sequence.
*
* Parameters: padapter - Pointer to host data block.
* spigot - Spigot select code.
* device - Device byte code.
*
* Returns: Nothing.
*
****************************************************************/
static void OpDone (PADAPTER2220I padapter, ULONG result)
{
Scsi_Cmnd *SCpnt = padapter->SCpnt;
if ( padapter->reconPhase )
{
padapter->reconPhase = 0;
if ( padapter->SCpnt )
{
Pci2220i_QueueCommand (SCpnt, SCpnt->scsi_done);
}
else
{
if ( padapter->reconOn )
{
ReconTimerExpiry ((unsigned long)padapter);
}
}
}
else
{
padapter->ide.ide.ides.cmd = 0; // null out the command byte
padapter->SCpnt = NULL;
return 1;
padapter->cmd = 0;
padapter->SCpnt = NULL;
SCpnt->result = result;
SCpnt->scsi_done (SCpnt);
if ( padapter->reconOn && !padapter->reconTimer.data )
{
padapter->reconTimer.expires = jiffies + (HZ / 4); // start in 1/4 second
padapter->reconTimer.data = (unsigned long)padapter;
add_timer (&padapter->reconTimer);
}
}
}
/****************************************************************
* Name: InlineIdentify :LOCAL
*
* Description: Do an intline inquiry on a drive.
*
* Parameters: padapter - Pointer to host data block.
* spigot - Spigot select code.
* device - Device byte code.
*
* Returns: Last addressable sector or zero if none.
*
****************************************************************/
static ULONG InlineIdentify (PADAPTER2220I padapter, UCHAR spigot, UCHAR device)
{
PIDENTIFY_DATA pid = (PIDENTIFY_DATA)Buffer;
SelectSpigot (padapter, spigot | 0x80); // select the spigot
outb_p (device << 4, padapter->regLba24); // select the drive
if ( WaitReady (padapter) )
return 0;
WriteCommand (padapter, IDE_COMMAND_IDENTIFY);
if ( WaitDrq (padapter) )
return 0;
insw (padapter->regData, Buffer, sizeof (IDENTIFY_DATA) >> 1);
return (pid->LBATotalSectors - 1);
}
/****************************************************************
* Name: DecodeError :LOCAL
*
* Description: Decode and process device errors.
*
* Parameters: pshost - Pointer to host data block.
* Parameters: padapter - Pointer to adapter data.
* status - Status register code.
*
* Returns: The driver status code.
*
****************************************************************/
static ULONG DecodeError (struct Scsi_Host *pshost, UCHAR status)
static ULONG DecodeError (PADAPTER2220I padapter, UCHAR status)
{
PADAPTER2220I padapter = HOSTDATA(pshost);
UCHAR error;
padapter->expectingIRQ = 0;
padapter->SCpnt = NULL;
if ( status & IDE_STATUS_WRITE_FAULT )
{
return DID_PARITY << 16;
......@@ -252,7 +558,7 @@ static ULONG DecodeError (struct Scsi_Host *pshost, UCHAR status)
if ( status & IDE_STATUS_BUSY )
return DID_BUS_BUSY << 16;
error = inb_p (padapter->ports[PORT_ERROR]);
error = inb_p (padapter->regError);
DEB(printk ("\npci2220i error register: %x", error));
switch ( error )
{
......@@ -267,6 +573,483 @@ static ULONG DecodeError (struct Scsi_Host *pshost, UCHAR status)
}
return DID_ERROR << 16;
}
/****************************************************************
* Name: StartTimer :LOCAL
*
* Description: Start the timer.
*
* Parameters: ipadapter - Pointer adapter data structure.
*
* Returns: Nothing.
*
****************************************************************/
static void StartTimer (PADAPTER2220I padapter)
{
padapter->timer.expires = jiffies + TIMEOUT_DATA;
add_timer (&padapter->timer);
}
/****************************************************************
* Name: WriteSignature :LOCAL
*
* Description: Start the timer.
*
* Parameters: padapter - Pointer adapter data structure.
* pdev - Pointer to our device.
* spigot - Selected spigot.
* index - index of mirror signature on device.
*
* Returns: TRUE on any error.
*
****************************************************************/
static int WriteSignature (PADAPTER2220I padapter, POUR_DEVICE pdev, UCHAR spigot, int index)
{
ULONG zl;
SelectSpigot (padapter, spigot);
zl = pdev->lastsectorlba[index];
outb_p (pdev->byte6 | ((UCHAR *)&zl)[3], padapter->regLba24);
outb_p (((UCHAR *)&zl)[2], padapter->regLba16);
outb_p (((UCHAR *)&zl)[1], padapter->regLba8);
outb_p (((UCHAR *)&zl)[0], padapter->regLba0);
outb_p (1, padapter->regSectCount);
WriteCommand (padapter, IDE_COMMAND_WRITE);
if ( WaitDrq (padapter) )
return TRUE;
StartTimer (padapter);
padapter->expectingIRQ = TRUE;
outsw (padapter->regData, Buffer, DISK_MIRROR_POSITION / 2);
outsw (padapter->regData, &pdev->DiskMirror[index], sizeof (DISK_MIRROR) / 2);
outsw (padapter->regData, Buffer, ((512 - (DISK_MIRROR_POSITION + sizeof (DISK_MIRROR))) / 2));
return FALSE;
}
/*******************************************************************************************************
* Name: InitFailover
*
* Description: This is the beginning of the failover routine
*
* Parameters: SCpnt - Pointer to SCSI command structure.
* padapter - Pointer adapter data structure.
* pdev - Pointer to our device.
*
* Returns: TRUE on error.
*
******************************************************************************************************/
static int InitFailover (PADAPTER2220I padapter, POUR_DEVICE pdev)
{
UCHAR spigot;
DEB (printk ("\npci2000i: Initialize failover process - survivor = %d", padapter->survivor));
pdev->raid = FALSE; //initializes system for non raid mode
pdev->hotRecon = 0;
padapter->reconOn = FALSE;
spigot = (padapter->survivor) ? 2 : 1;
if ( pdev->DiskMirror[padapter->survivor].status & UCBF_REBUILD )
return (TRUE);
if ( HardReset (padapter, pdev, spigot) )
return TRUE;
outb_p (0x3C | spigot, padapter->regFail); // sound alarm and set fail light
pdev->DiskMirror[padapter->survivor].status = UCBF_MIRRORED | UCBF_SURVIVOR; //clear present status
if ( WriteSignature (padapter, pdev, spigot, padapter->survivor) )
return TRUE;
padapter->failinprog = TRUE;
return FALSE;
}
/****************************************************************
* Name: TimerExpiry :LOCAL
*
* Description: Timer expiry routine.
*
* Parameters: data - Pointer adapter data structure.
*
* Returns: Nothing.
*
****************************************************************/
static void TimerExpiry (unsigned long data)
{
PADAPTER2220I padapter = (PADAPTER2220I)data;
POUR_DEVICE pdev = padapter->pdev;
ULONG flags;
UCHAR status = IDE_STATUS_BUSY;
UCHAR temp, temp1;
DEB (printk ("\nPCI2220I: Timeout expired "));
save_flags (flags);
cli ();
if ( padapter->failinprog )
{
DEB (printk ("in failover process"));
restore_flags (flags);
OpDone (padapter, DecodeError (padapter, inb_p (padapter->regStatCmd)));
return;
}
while ( padapter->reconPhase )
{
DEB (printk ("in recon phase %X", padapter->reconPhase));
if ( --padapter->timeoutReconRetry )
{
StartTimer (padapter);
return;
}
switch ( padapter->reconPhase )
{
case RECON_PHASE_MARKING:
case RECON_PHASE_LAST:
padapter->survivor = (pdev->spigot ^ 3) >> 1;
restore_flags (flags);
DEB (printk ("\npci2220i: FAILURE 1"));
if ( InitFailover (padapter, pdev) )
OpDone (padapter, DID_ERROR << 16);
return;
case RECON_PHASE_READY:
OpDone (padapter, DID_ERROR << 16);
return;
case RECON_PHASE_COPY:
padapter->survivor = (pdev->spigot) >> 1;
restore_flags (flags);
DEB (printk ("\npci2220i: FAILURE 2"));
if ( InitFailover (padapter, pdev) )
OpDone (padapter, DID_ERROR << 16);
return;
case RECON_PHASE_UPDATE:
padapter->survivor = (pdev->spigot) >> 1;
restore_flags (flags);
DEB (printk ("\npci2220i: FAILURE 3"));
if ( InitFailover (padapter, pdev) )
OpDone (padapter, DID_ERROR << 16);
return;
case RECON_PHASE_END:
padapter->survivor = (pdev->spigot) >> 1;
restore_flags (flags);
DEB (printk ("\npci2220i: FAILURE 4"));
if ( InitFailover (padapter, pdev) )
OpDone (padapter, DID_ERROR << 16);
return;
default:
return;
}
}
while ( padapter->cmd )
{
outb_p (0x08, padapter->regDmaCmdStat); // cancel interrupt from DMA engine
if ( pdev->raid )
{
if ( padapter->cmd == WRITE_CMD )
{
DEB (printk ("in RAID write operation"));
if ( inb_p (padapter->regStatSel) & 1 )
{
SelectSpigot (padapter, 0x81 ); // Masking the interrupt during spigot select
temp = inb_p (padapter->regStatCmd);
}
else
temp = IDE_STATUS_BUSY;
if ( inb (padapter->regStatSel) & 2 )
{
SelectSpigot (padapter, 0x82 ); // Masking the interrupt during spigot select
temp1 = inb_p (padapter->regStatCmd);
}
else
temp1 = IDE_STATUS_BUSY;
if ( (temp & IDE_STATUS_BUSY) || (temp1 & IDE_STATUS_BUSY) )
{
if ( (temp & IDE_STATUS_BUSY) && (temp1 & IDE_STATUS_BUSY) )
{
status = temp;
break;
}
else
{
if (temp & IDE_STATUS_BUSY)
padapter->survivor = 1;
else
padapter->survivor = 0;
restore_flags (flags);
DEB (printk ("\npci2220i: FAILURE 5"));
if ( InitFailover (padapter, pdev) )
{
status = inb_p (padapter->regStatCmd);
break;
}
return;
}
}
}
else
{
DEB (printk ("in RAID read operation"));
padapter->survivor = (pdev->spigot ^ 3) >> 1;
restore_flags (flags);
DEB (printk ("\npci2220i: FAILURE 6"));
if ( InitFailover (padapter, pdev) )
{
status = inb_p (padapter->regStatCmd);
break;
}
return;
}
}
else
{
DEB (printk ("in I/O operation"));
status = inb_p (padapter->regStatCmd);
}
break;
}
restore_flags (flags);
OpDone (padapter, DecodeError (padapter, status));
}
/****************************************************************
* Name: SetReconstruct :LOCAL
*
* Description: Set the reconstruct up.
*
* Parameters: pdev - Pointer to device structure.
* index - Mirror index number.
*
* Returns: Number of sectors on new disk required.
*
****************************************************************/
static LONG SetReconstruct (POUR_DEVICE pdev, int index)
{
pdev->DiskMirror[index].status = UCBF_MIRRORED; // setup the flags
pdev->DiskMirror[index ^ 1].status = UCBF_MIRRORED | UCBF_REBUILD;
pdev->DiskMirror[index ^ 1].reconstructPoint = 0; // start the reconstruct
pdev->reconCount = 1990; // mark target drive early
pdev->hotRecon = 1 >> index;
return pdev->DiskMirror[index].reconstructPoint;
}
/****************************************************************
* Name: ReconTimerExpiry :LOCAL
*
* Description: Reconstruct timer expiry routine.
*
* Parameters: data - Pointer adapter data structure.
*
* Returns: Nothing.
*
****************************************************************/
static void ReconTimerExpiry (unsigned long data)
{
PADAPTER2220I padapter;
POUR_DEVICE pdev;
ULONG testsize = 0;
PIDENTIFY_DATA pid;
USHORT minmode;
ULONG zl;
UCHAR zc;
padapter = (PADAPTER2220I)data;
if ( padapter->SCpnt )
return;
pdev = padapter->device;
pid = (PIDENTIFY_DATA)Buffer;
padapter->reconTimer.data = 0;
padapter->timeoutReconRetry = 2;
padapter->pdev = pdev;
if ( padapter->reconIsStarting )
{
padapter->reconIsStarting = FALSE;
padapter->reconOn = FALSE;
pdev->hotRecon = FALSE;
if ( (pdev->DiskMirror[0].signature == SIGNATURE) && (pdev->DiskMirror[1].signature == SIGNATURE) &&
(pdev->DiskMirror[0].pairIdentifier == (pdev->DiskMirror[1].pairIdentifier ^ 1)) )
{
if ( (pdev->DiskMirror[0].status & UCBF_MATCHED) && (pdev->DiskMirror[1].status & UCBF_MATCHED) )
{
return;
}
if ( pdev->DiskMirror[0].status & UCBF_SURVIVOR ) // is first drive survivor?
testsize = SetReconstruct (pdev, 0);
else
if ( pdev->DiskMirror[1].status & UCBF_SURVIVOR ) // is second drive survivor?
testsize = SetReconstruct (pdev, 1);
if ( (pdev->DiskMirror[0].status & UCBF_REBUILD) || (pdev->DiskMirror[1].status & UCBF_REBUILD) )
{
if ( pdev->DiskMirror[0].status & UCBF_REBUILD )
{
pdev->hotRecon = 1;
pdev->mirrorRecon = 0;
}
else
{
pdev->hotRecon = 2;
pdev->mirrorRecon = 1;
}
}
}
if ( !pdev->hotRecon )
return;
zc = ((inb_p (padapter->regStatSel) >> 3) | inb_p (padapter->regStatSel)) & 0x83; // mute the alarm
outb_p (zc | pdev->hotRecon | 0x40, padapter->regFail);
while ( 1 )
{
if ( HardReset (padapter, pdev, pdev->hotRecon) )
{
DEB (printk ("\npci2220i: sub 1"));
break;
}
pdev->lastsectorlba[pdev->mirrorRecon] = InlineIdentify (padapter, pdev->hotRecon, 0);
if ( pdev->lastsectorlba[pdev->mirrorRecon] < testsize )
{
DEB (printk ("\npci2220i: sub 2 %ld %ld", pdev->lastsectorlba[pdev->mirrorRecon], testsize));
break;
}
// test LBA and multiper sector transfer compatability
if (!pid->SupportLBA || (pid->NumSectorsPerInt < SECTORSXFER) || !pid->Valid_64_70 )
{
DEB (printk ("\npci2220i: sub 3"));
break;
}
// test PIO/bus matering mode compatability
if ( (pid->MinPIOCycleWithoutFlow > 240) && !pid->SupportIORDYDisable && !padapter->timingPIO )
{
DEB (printk ("\npci2220i: sub 4"));
break;
}
if ( pid->MinPIOCycleWithoutFlow <= 120 ) // setup timing mode of drive
minmode = 5;
else
{
if ( pid->MinPIOCylceWithFlow <= 150 )
minmode = 4;
else
{
if ( pid->MinPIOCylceWithFlow <= 180 )
minmode = 3;
else
{
if ( pid->MinPIOCylceWithFlow <= 240 )
minmode = 2;
else
{
DEB (printk ("\npci2220i: sub 5"));
break;
}
}
}
}
if ( padapter->timingMode > minmode ) // set minimum timing mode
padapter->timingMode = minmode;
if ( padapter->timingMode >= 2 )
padapter->timingAddress = ModeArray[padapter->timingMode - 2];
else
padapter->timingPIO = TRUE;
padapter->reconOn = TRUE;
break;
}
if ( !padapter->reconOn )
{
pdev->hotRecon = FALSE;
padapter->survivor = pdev->mirrorRecon ^ 1;
padapter->reconPhase = RECON_PHASE_FAILOVER;
DEB (printk ("\npci2220i: FAILURE 7"));
InitFailover (padapter, pdev);
return;
}
pdev->raid = TRUE;
if ( WriteSignature (padapter, pdev, pdev->spigot, pdev->mirrorRecon ^ 1) )
return;
padapter->reconPhase = RECON_PHASE_MARKING;
return;
}
//**********************************
// reconstruct copy starts here
//**********************************
if ( pdev->reconCount++ > 2000 )
{
pdev->reconCount = 0;
if ( WriteSignature (padapter, pdev, pdev->hotRecon, pdev->mirrorRecon) )
{
padapter->survivor = pdev->mirrorRecon ^ 1;
padapter->reconPhase = RECON_PHASE_FAILOVER;
DEB (printk ("\npci2220i: FAILURE 8"));
InitFailover (padapter, pdev);
return;
}
padapter->reconPhase = RECON_PHASE_UPDATE;
return;
}
zl = pdev->DiskMirror[pdev->mirrorRecon].reconstructPoint;
padapter->reconSize = pdev->DiskMirror[pdev->mirrorRecon ^ 1].reconstructPoint - zl;
if ( padapter->reconSize > MAX_BUS_MASTER_BLOCKS )
padapter->reconSize = MAX_BUS_MASTER_BLOCKS;
if ( padapter->reconSize )
{
SelectSpigot (padapter, 3); // select the spigots
outb_p (pdev->byte6 | ((UCHAR *)(&zl))[3], padapter->regLba24);// select the drive
SelectSpigot (padapter, pdev->spigot);
if ( WaitReady (padapter) )
return;
SelectSpigot (padapter, pdev->hotRecon);
if ( WaitReady (padapter) )
{
padapter->survivor = pdev->mirrorRecon ^ 1;
padapter->reconPhase = RECON_PHASE_FAILOVER;
DEB (printk ("\npci2220i: FAILURE 9"));
InitFailover (padapter, pdev);
return;
}
SelectSpigot (padapter, 3);
outb_p (padapter->reconSize & 0xFF, padapter->regSectCount);
outb_p (((UCHAR *)(&zl))[0], padapter->regLba0);
outb_p (((UCHAR *)(&zl))[1], padapter->regLba8);
outb_p (((UCHAR *)(&zl))[2], padapter->regLba16);
padapter->expectingIRQ = TRUE;
padapter->reconPhase = RECON_PHASE_READY;
SelectSpigot (padapter, pdev->hotRecon);
WriteCommand (padapter, WRITE_CMD);
StartTimer (padapter);
SelectSpigot (padapter, pdev->spigot);
WriteCommand (padapter, READ_CMD);
return;
}
pdev->DiskMirror[pdev->mirrorRecon].status = UCBF_MIRRORED | UCBF_MATCHED;
pdev->DiskMirror[pdev->mirrorRecon ^ 1].status = UCBF_MIRRORED | UCBF_MATCHED;
if ( WriteSignature (padapter, pdev, pdev->spigot, pdev->mirrorRecon ^ 1) )
return;
padapter->reconPhase = RECON_PHASE_LAST;
return;
}
/****************************************************************
* Name: Irq_Handler :LOCAL
*
......@@ -283,12 +1066,14 @@ static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
{
struct Scsi_Host *shost = NULL; // Pointer to host data block
PADAPTER2220I padapter; // Pointer to adapter control structure
USHORT *pports; // I/O port array
POUR_DEVICE pdev;
Scsi_Cmnd *SCpnt;
UCHAR status;
UCHAR status1;
int z;
ULONG zl;
// DEB(printk ("\npci2220i recieved interrupt\n"));
// DEB (printk ("\npci2220i recieved interrupt\n"));
for ( z = 0; z < NumAdapters; z++ ) // scan for interrupt to process
{
......@@ -309,82 +1094,264 @@ static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
}
padapter = HOSTDATA(shost);
pports = padapter->ports;
pdev = padapter->pdev;
SCpnt = padapter->SCpnt;
if ( !padapter->expectingIRQ )
if ( !padapter->expectingIRQ || !(SCpnt || padapter->reconPhase) )
{
DEB(printk ("\npci2220i Unsolicited interrupt\n"));
STOP_HERE ();
return;
}
padapter->expectingIRQ = 0;
outb_p (0x08, padapter->regDmaCmdStat); // cancel interrupt from DMA engine
status = inb_p (padapter->ports[PORT_STAT_CMD]); // read the device status
if ( status & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT) )
goto irqerror;
if ( padapter->failinprog )
{
DEB (printk ("\npci2220i interrupt failover complete"));
padapter->failinprog = FALSE;
status = inb_p (padapter->regStatCmd); // read the device status
if ( status & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT) )
{
DEB (printk ("\npci2220i: interrupt failover error from drive %X", status));
padapter->cmd = 0;
}
else
{
DEB (printk ("\npci2220i: restarting failed opertation."));
pdev->spigot = (padapter->survivor) ? 2 : 1;
del_timer (&padapter->timer);
if ( padapter->reconPhase )
OpDone (padapter, DID_OK << 16);
else
Pci2220i_QueueCommand (SCpnt, SCpnt->scsi_done);
return;
}
}
switch ( padapter->ide.ide.ides.cmd ) // decide how to handle the interrupt
if ( padapter->reconPhase )
{
case IDE_CMD_READ_MULTIPLE:
if ( padapter->readPhase == 1 ) // is this a bus master channel complete?
{
DEB(printk ("\npci2220i processing read interrupt cleanup"));
outb_p (0x08, padapter->regDmaCmdStat); // cancel interrupt from DMA engine
padapter->buffer += padapter->ide.ide.ides.sectors * 512;
if ( SetupTransfer (padapter, padapter->ide.ide.ide[6] & 0xF0) )
switch ( padapter->reconPhase )
{
case RECON_PHASE_MARKING:
case RECON_PHASE_LAST:
status = inb_p (padapter->regStatCmd); // read the device status
del_timer (&padapter->timer);
if ( padapter->reconPhase == RECON_PHASE_LAST )
{
if ( status & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT) )
{
padapter->survivor = (pdev->spigot ^ 3) >> 1;
DEB (printk ("\npci2220i: FAILURE 10"));
if ( InitFailover (padapter, pdev) )
OpDone (padapter, DecodeError (padapter, status));
return;
}
if ( WriteSignature (padapter, pdev, pdev->hotRecon, pdev->mirrorRecon) )
{
padapter->survivor = (pdev->spigot) >> 1;
DEB (printk ("\npci2220i: FAILURE 11"));
if ( InitFailover (padapter, pdev) )
OpDone (padapter, DecodeError (padapter, status));
return;
}
padapter->reconPhase = RECON_PHASE_END;
return;
}
OpDone (padapter, DID_OK << 16);
return;
case RECON_PHASE_READY:
status = inb_p (padapter->regStatCmd); // read the device status
if ( status & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT) )
{
SCpnt->result = DID_OK << 16;
padapter->SCpnt = NULL;
SCpnt->scsi_done (SCpnt);
del_timer (&padapter->timer);
OpDone (padapter, DecodeError (padapter, status));
return;
}
padapter->readPhase = 0;
if ( !(status = IdeCmd (padapter)) )
SelectSpigot (padapter, pdev->hotRecon);
if ( WaitDrq (padapter) )
{
DEB (printk ("\npci2220i interrupt complete, waiting for another"));
del_timer (&padapter->timer);
padapter->survivor = (pdev->spigot) >> 1;
DEB (printk ("\npci2220i: FAILURE 12"));
if ( InitFailover (padapter, pdev) )
OpDone (padapter, DecodeError (padapter, status));
return;
}
}
if ( status & IDE_STATUS_DRQ )
SelectSpigot (padapter, pdev->spigot | 0x40);
padapter->reconPhase = RECON_PHASE_COPY;
padapter->expectingIRQ = TRUE;
if ( padapter->timingPIO )
{
insw (padapter->regData, Buffer, padapter->reconSize * (BYTES_PER_SECTOR / 2));
}
else
{
outl (padapter->timingAddress, padapter->regDmaAddrLoc);
outl (virt_to_bus (Buffer), padapter->regDmaAddrPci);
outl (padapter->reconSize * BYTES_PER_SECTOR, padapter->regDmaCount);
outb_p (8, padapter->regDmaDesc); // read operation
outb_p (1, padapter->regDmaMode); // no interrupt
outb_p (0x03, padapter->regDmaCmdStat); // kick the DMA engine in gear
}
return;
case RECON_PHASE_COPY:
pdev->DiskMirror[pdev->mirrorRecon].reconstructPoint += padapter->reconSize;
case RECON_PHASE_UPDATE:
SelectSpigot (padapter, pdev->hotRecon | 0x80);
status = inb_p (padapter->regStatCmd); // read the device status
del_timer (&padapter->timer);
if ( status & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT) )
{
padapter->survivor = (pdev->spigot) >> 1;
DEB (printk ("\npci2220i: FAILURE 13"));
DEB (printk (" status = %X error = %X", status, inb_p (padapter->regError)));
if ( InitFailover (padapter, pdev) )
OpDone (padapter, DecodeError (padapter, status));
return;
}
OpDone (padapter, DID_OK << 16);
return;
case RECON_PHASE_END:
status = inb_p (padapter->regStatCmd); // read the device status
del_timer (&padapter->timer);
if ( status & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT) )
{
padapter->survivor = (pdev->spigot) >> 1;
DEB (printk ("\npci2220i: FAILURE 14"));
if ( InitFailover (padapter, pdev) )
OpDone (padapter, DecodeError (padapter, status));
return;
}
padapter->reconOn = FALSE;
pdev->hotRecon = 0;
OpDone (padapter, DID_OK << 16);
return;
default:
return;
}
}
switch ( padapter->cmd ) // decide how to handle the interrupt
{
case READ_CMD:
if ( padapter->sectorCount )
{
DEB(printk ("\npci2220i processing read interrupt start bus master cycle"));
outb_p (8, padapter->regDmaDesc); // read operation
padapter->readPhase = 1;
padapter->expectingIRQ = 1;
outl (padapter->timingAddress, padapter->regDmaAddrLoc);
outl (virt_to_bus (padapter->buffer), padapter->regDmaAddrPci);
outl ((ULONG)padapter->ide.ide.ides.sectors * (ULONG)512, padapter->regDmaCount);
outb_p (5, padapter->regDmaMode); // interrupt enable/disable
outb_p (0x03, padapter->regDmaCmdStat); // kick the DMA engine in gear
status = inb_p (padapter->regStatCmd); // read the device status
if ( status & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT) )
{
if ( pdev->raid )
{
padapter->survivor = (pdev->spigot ^ 3) >> 1;
del_timer (&padapter->timer);
DEB (printk ("\npci2220i: FAILURE 15"));
if ( !InitFailover (padapter, pdev) )
return;
}
break;
}
if ( padapter->timingPIO )
{
zl = (padapter->sectorCount > MAX_BUS_MASTER_BLOCKS) ? MAX_BUS_MASTER_BLOCKS : padapter->sectorCount;
insw (padapter->regData, padapter->buffer, zl * (BYTES_PER_SECTOR / 2));
padapter->sectorCount -= zl;
padapter->buffer += zl * BYTES_PER_SECTOR;
if ( !padapter->sectorCount )
{
status = 0;
break;
}
}
else
BusMaster (padapter, 1, 1);
padapter->expectingIRQ = TRUE;
return;
}
status = 0;
break;
case IDE_CMD_WRITE_MULTIPLE:
DEB(printk ("\npci2220i processing write interrupt cleanup"));
padapter->buffer += padapter->ide.ide.ides.sectors * 512;
if ( SetupTransfer (padapter, padapter->ide.ide.ide[6] & 0xF0) )
case WRITE_CMD:
SelectSpigot (padapter, pdev->spigot | 0x80);
status = inb_p (padapter->regStatCmd); // read the device status
if ( pdev->raid )
{
SCpnt->result = DID_OK << 16;
padapter->SCpnt = NULL;
SCpnt->scsi_done (SCpnt);
return;
SelectSpigot (padapter, (pdev->spigot ^ 3) | 0x80);
status1 = inb_p (padapter->regStatCmd); // read the device status
}
else
status1 = 0;
if ( status & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT) )
{
if ( pdev->raid && !(status1 & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT)) )
{
padapter->survivor = (pdev->spigot ^ 3) >> 1;
del_timer (&padapter->timer);
SelectSpigot (padapter, pdev->spigot | 0x80);
DEB (printk ("\npci2220i: FAILURE 16 status = %X error = %X", status, inb_p (padapter->regError)));
if ( !InitFailover (padapter, pdev) )
return;
}
break;
}
if ( !(status = IdeCmd (padapter)) )
if ( pdev->raid )
{
DEB (printk ("\npci2220i interrupt complete, waiting for another"));
if ( status1 & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT) )
{
padapter->survivor = pdev->spigot >> 1;
del_timer (&padapter->timer);
DEB (printk ("\npci2220i: FAILURE 17 status = %X error = %X", status1, inb_p (padapter->regError)));
if ( !InitFailover (padapter, pdev) )
return;
status = status1;
break;
}
if ( padapter->sectorCount )
{
status = WriteDataBoth (padapter);
if ( status )
{
padapter->survivor = (status ^ 3) >> 1;
del_timer (&padapter->timer);
DEB (printk ("\npci2220i: FAILURE 18"));
if ( !InitFailover (padapter, pdev) )
return;
SelectSpigot (padapter, status | 0x80);
status = inb_p (padapter->regStatCmd); // read the device status
break;
}
padapter->expectingIRQ = TRUE;
return;
}
status = 0;
break;
}
if ( padapter->sectorCount )
{
SelectSpigot (padapter, pdev->spigot);
status = WriteData (padapter);
if ( status )
break;
padapter->expectingIRQ = TRUE;
return;
}
status = 0;
break;
case IDE_COMMAND_IDENTIFY:
{
PINQUIRYDATA pinquiryData = SCpnt->request_buffer;
PIDENTIFY_DATA pid = (PIDENTIFY_DATA)Buffer;
DEB(printk ("\npci2220i processing verify interrupt cleanup"));
status = inb_p (padapter->regStatCmd);
if ( status & IDE_STATUS_DRQ )
{
insw (pports[PORT_DATA], &identifyData, sizeof (identifyData) >> 1);
insw (padapter->regData, pid, sizeof (IDENTIFY_DATA) >> 1);
memset (pinquiryData, 0, SCpnt->request_bufflen); // Zero INQUIRY data structure.
pinquiryData->DeviceType = 0;
......@@ -394,8 +1361,8 @@ static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
// Fill in vendor identification fields.
for ( z = 0; z < 20; z += 2 )
{
pinquiryData->VendorId[z] = ((UCHAR *)identifyData.ModelNumber)[z + 1];
pinquiryData->VendorId[z + 1] = ((UCHAR *)identifyData.ModelNumber)[z];
pinquiryData->VendorId[z] = ((UCHAR *)pid->ModelNumber)[z + 1];
pinquiryData->VendorId[z + 1] = ((UCHAR *)pid->ModelNumber)[z];
}
// Initialize unused portion of product id.
......@@ -406,38 +1373,32 @@ static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
// product revision in INQUIRY data.
for ( z = 0; z < 4; z += 2 )
{
pinquiryData->ProductRevisionLevel[z] = ((UCHAR *)identifyData.FirmwareRevision)[z + 1];
pinquiryData->ProductRevisionLevel[z + 1] = ((UCHAR *)identifyData.FirmwareRevision)[z];
pinquiryData->ProductRevisionLevel[z] = ((UCHAR *)pid->FirmwareRevision)[z + 1];
pinquiryData->ProductRevisionLevel[z + 1] = ((UCHAR *)pid->FirmwareRevision)[z];
}
SCpnt->result = DID_OK << 16;
padapter->SCpnt = NULL;
SCpnt->scsi_done (SCpnt);
return;
if ( pdev == padapter->device )
*((USHORT *)(&pinquiryData->VendorSpecific)) = DEVICE_DALE_1;
status = 0;
}
break;
}
default:
DEB(printk ("\npci2220i no real process here!"));
SCpnt->result = DID_OK << 16;
padapter->SCpnt = NULL;
SCpnt->scsi_done (SCpnt);
return;
status = 0;
break;
}
irqerror:;
DEB(printk ("\npci2220i error Device Status: %X\n", status));
SCpnt->result = DecodeError (shost, status);
SCpnt->scsi_done (SCpnt);
}
static void do_Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
{
unsigned long flags;
del_timer (&padapter->timer);
if ( status )
{
DEB (printk ("\npci2220i Interupt hanlder return error"));
zl = DecodeError (padapter, status);
}
else
zl = DID_OK << 16;
spin_lock_irqsave(&io_request_lock, flags);
Irq_Handler(irq, dev_id, regs);
spin_unlock_irqrestore(&io_request_lock, flags);
OpDone (padapter, zl);
}
/****************************************************************
* Name: Pci2220i_QueueCommand
......@@ -456,121 +1417,182 @@ int Pci2220i_QueueCommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
PADAPTER2220I padapter = HOSTDATA(SCpnt->host); // Pointer to adapter control structure
POUR_DEVICE pdev = &padapter->device[SCpnt->target];// Pointer to device information
UCHAR rc; // command return code
int z;
PDEVICE_RAID1 pdr;
SCpnt->scsi_done = done;
padapter->ide.ide.ides.spigot = pdev->spigot;
padapter->buffer = SCpnt->request_buffer;
if (done)
padapter->SCpnt = SCpnt; // Save this command data
if ( !done )
{
if ( !pdev->device )
{
SCpnt->result = DID_BAD_TARGET << 16;
done (SCpnt);
return 0;
}
printk("pci2220i_queuecommand: %02X: done can't be NULL\n", *cdb);
return 0;
}
else
if ( padapter->reconPhase )
return 0;
if ( padapter->reconTimer.data )
{
printk("pci2220i_queuecommand: %02X: done can't be NULL\n", *cdb);
del_timer (&padapter->reconTimer);
padapter->reconTimer.data = 0;
}
if ( !pdev->device || SCpnt->lun )
{
OpDone (padapter, DID_BAD_TARGET << 16);
return 0;
}
DEB (if(*cdb) printk ("\nCDB: %X- %X %X %X %X %X %X %X %X %X %X ", SCpnt->cmd_len, cdb[0], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5], cdb[6], cdb[7], cdb[8], cdb[9]));
switch ( *cdb )
{
case SCSIOP_INQUIRY: // inquiry CDB
{
padapter->ide.ide.ide[6] = pdev->byte6;
padapter->ide.ide.ides.cmd = IDE_COMMAND_IDENTIFY;
if ( cdb[2] == SC_MY_RAID )
{
switch ( cdb[3] )
{
case MY_SCSI_REBUILD:
padapter->reconOn = padapter->reconIsStarting = TRUE;
OpDone (padapter, DID_OK << 16);
break;
case MY_SCSI_ALARMMUTE:
MuteAlarm (padapter);
OpDone (padapter, DID_OK << 16);
break;
case MY_SCSI_DEMOFAIL:
padapter->demoFail = TRUE;
OpDone (padapter, DID_OK << 16);
break;
default:
z = cdb[5]; // get index
pdr = (PDEVICE_RAID1)SCpnt->request_buffer;
if ( padapter->raidData[z] )
{
memcpy (&pdr->DiskRaid1, padapter->raidData[z], sizeof (DISK_MIRROR));
pdr->TotalSectors = padapter->device[0].blocks;
}
else
memset (pdr, 0, sizeof (DEVICE_RAID1));
OpDone (padapter, DID_OK << 16);
break;
}
return 0;
}
padapter->cmd = IDE_COMMAND_IDENTIFY;
break;
}
case SCSIOP_TEST_UNIT_READY: // test unit ready CDB
SCpnt->result = DID_OK << 16;
done (SCpnt);
OpDone (padapter, DID_OK << 16);
return 0;
case SCSIOP_READ_CAPACITY: // read capctiy CDB
{
PREAD_CAPACITY_DATA pdata = (PREAD_CAPACITY_DATA)SCpnt->request_buffer;
pdata->blksiz = 0x20000;
XANY2SCSI ((UCHAR *)&pdata->blks, pdev->blocks);
SCpnt->result = DID_OK << 16;
done (SCpnt);
OpDone (padapter, DID_OK << 16);
return 0;
}
case SCSIOP_VERIFY: // verify CDB
*(ULONG *)padapter->ide.ide.ides.lba = XSCSI2LONG (&cdb[2]);
padapter->ide.ide.ide[6] |= pdev->byte6;
padapter->ide.ide.ide[2] = (UCHAR)((USHORT)cdb[8] | ((USHORT)cdb[7] << 8));
padapter->ide.ide.ides.cmd = IDE_COMMAND_VERIFY;
padapter->startSector = XSCSI2LONG (&cdb[2]);
padapter->sectorCount = (UCHAR)((USHORT)cdb[8] | ((USHORT)cdb[7] << 8));
padapter->cmd = IDE_COMMAND_VERIFY;
break;
case SCSIOP_READ: // read10 CDB
padapter->startSector = XSCSI2LONG (&cdb[2]);
padapter->sectorCount = (USHORT)cdb[8] | ((USHORT)cdb[7] << 8);
SetupTransfer (padapter, pdev->byte6);
padapter->ide.ide.ides.cmd = IDE_CMD_READ_MULTIPLE;
padapter->readPhase = 0;
padapter->cmd = READ_CMD;
break;
case SCSIOP_READ6: // read6 CDB
padapter->startSector = SCSI2LONG (&cdb[1]);
padapter->sectorCount = cdb[4];
SetupTransfer (padapter, pdev->byte6);
padapter->ide.ide.ides.cmd = IDE_CMD_READ_MULTIPLE;
padapter->readPhase = 0;
padapter->cmd = READ_CMD;
break;
case SCSIOP_WRITE: // write10 CDB
padapter->startSector = XSCSI2LONG (&cdb[2]);
padapter->sectorCount = (USHORT)cdb[8] | ((USHORT)cdb[7] << 8);
SetupTransfer (padapter, pdev->byte6);
padapter->ide.ide.ides.cmd = IDE_CMD_WRITE_MULTIPLE;
padapter->cmd = WRITE_CMD;
break;
case SCSIOP_WRITE6: // write6 CDB
padapter->startSector = SCSI2LONG (&cdb[1]);
padapter->sectorCount = cdb[4];
SetupTransfer (padapter, pdev->byte6);
padapter->ide.ide.ides.cmd = IDE_CMD_WRITE_MULTIPLE;
padapter->cmd = WRITE_CMD;
break;
default:
DEB (printk ("pci2220i_queuecommand: Unsupported command %02X\n", *cdb));
SCpnt->result = DID_ERROR << 16;
done (SCpnt);
OpDone (padapter, DID_ERROR << 16);
return 0;
}
padapter->SCpnt = SCpnt; // Save this command data
if ( padapter->reconPhase )
return 0;
padapter->pdev = pdev;
rc = IdeCmd (padapter);
if ( rc )
while ( padapter->demoFail )
{
padapter->expectingIRQ = 0;
DEB (printk ("pci2220i_queuecommand: %02X, %02X: Device failed to respond for command\n", *cdb, padapter->ide.ide.ides.cmd));
SCpnt->result = DID_ERROR << 16;
done (SCpnt);
padapter->demoFail = FALSE;
if ( !pdev->raid ||
(pdev->DiskMirror[0].status & UCBF_SURVIVOR) ||
(pdev->DiskMirror[1].status & UCBF_SURVIVOR) )
{
break;
}
if ( pdev->DiskMirror[0].status & UCBF_REBUILD )
padapter->survivor = 1;
else
padapter->survivor = 0;
DEB (printk ("\npci2220i: FAILURE 19"));
if ( InitFailover (padapter, pdev ) )
break;
return 0;
}
if ( padapter->ide.ide.ides.cmd == IDE_CMD_WRITE_MULTIPLE )
StartTimer (padapter);
if ( pdev->raid && (padapter->cmd == WRITE_CMD) )
{
rc = IdeCmdBoth (padapter);
if ( !rc )
rc = WriteDataBoth (padapter);
if ( rc )
{
del_timer (&padapter->timer);
padapter->expectingIRQ = 0;
padapter->survivor = (rc ^ 3) >> 1;
DEB (printk ("\npci2220i: FAILURE 20"));
if ( InitFailover (padapter, pdev) )
{
OpDone (padapter, DID_ERROR << 16);
return 0;
}
}
}
else
{
if ( WriteData (padapter) )
rc = IdeCmd (padapter, pdev);
if ( (padapter->cmd == WRITE_CMD) && !rc )
rc = WriteData (padapter);
if ( rc )
{
del_timer (&padapter->timer);
padapter->expectingIRQ = 0;
DEB (printk ("pci2220i_queuecommand: %02X, %02X: Device failed to accept data\n", *cdb, padapter->ide.ide.ides.cmd));
SCpnt->result = DID_ERROR << 16;
done (SCpnt);
if ( pdev->raid )
{
padapter->survivor = (pdev->spigot ^ 3) >> 1;
DEB (printk ("\npci2220i: FAILURE 21"));
if ( !InitFailover (padapter, pdev) )
return 0;
}
OpDone (padapter, DID_ERROR << 16);
return 0;
}
}
DEB (printk(" now waiting for initial interrupt "));
return 0;
}
static void internal_done(Scsi_Cmnd * SCpnt)
static void internal_done(Scsi_Cmnd *SCpnt)
{
SCpnt->SCp.Status++;
}
......@@ -586,10 +1608,7 @@ static void internal_done(Scsi_Cmnd * SCpnt)
****************************************************************/
int Pci2220i_Command (Scsi_Cmnd *SCpnt)
{
DEB(printk("pci2220i_command: ..calling pci2220i_queuecommand\n"));
Pci2220i_QueueCommand (SCpnt, internal_done);
SCpnt->SCp.Status = 0;
while (!SCpnt->SCp.Status)
barrier ();
......@@ -600,7 +1619,7 @@ int Pci2220i_Command (Scsi_Cmnd *SCpnt)
*
* Description: Read information from controller Flash memory.
*
* Parameters: hostdata - Pointer to host interface data structure.
* Parameters: padapter - Pointer to host interface data structure.
* pdata - Pointer to data structures.
* base - base address in Flash.
* length - lenght of data space in bytes.
......@@ -608,25 +1627,24 @@ int Pci2220i_Command (Scsi_Cmnd *SCpnt)
* Returns: Nothing.
*
****************************************************************/
VOID ReadFlash (PADAPTER2220I hostdata, VOID *pdata, ULONG base, ULONG length)
VOID ReadFlash (PADAPTER2220I padapter, VOID *pdata, ULONG base, ULONG length)
{
ULONG oldremap;
UCHAR olddesc;
ULONG z;
UCHAR *pd = (UCHAR *)pdata;
oldremap = inl (hostdata->regRemap); // save values to restore later
olddesc = inb_p (hostdata->regDesc);
oldremap = inl (padapter->regRemap); // save values to restore later
olddesc = inb_p (padapter->regDesc);
outl (base | 1, hostdata->regRemap); // remap to Flash space as specified
outb_p (0x40, hostdata->regDesc); // describe remap region as 8 bit
outl (base | 1, padapter->regRemap); // remap to Flash space as specified
outb_p (0x40, padapter->regDesc); // describe remap region as 8 bit
for ( z = 0; z < length; z++) // get "length" data count
*pd++ = inb_p (hostdata->regBase + z); // read in the data
*pd++ = inb_p (padapter->regBase + z); // read in the data
outl (oldremap, hostdata->regRemap); // restore remap register values
outb_p (olddesc, hostdata->regDesc);
outl (oldremap, padapter->regRemap); // restore remap register values
outb_p (olddesc, padapter->regDesc);
}
/****************************************************************
* Name: Pci2220i_Detect
*
......@@ -639,109 +1657,183 @@ VOID ReadFlash (PADAPTER2220I hostdata, VOID *pdata, ULONG base, ULONG length)
****************************************************************/
int Pci2220i_Detect (Scsi_Host_Template *tpnt)
{
struct pci_dev *pdev = NULL;
int pci_index = 0;
struct Scsi_Host *pshost;
PADAPTER2220I hostdata;
ULONG modearray[] = {DALE_DATA_MODE2, DALE_DATA_MODE3, DALE_DATA_MODE4, DALE_DATA_MODE4P};
PADAPTER2220I padapter;
int unit;
int z;
USHORT zs;
USHORT raidon = FALSE;
int setirq;
UCHAR spigot1 = FALSE;
UCHAR spigot2 = FALSE;
if ( pci_present () )
while ((pdev = pci_find_device(VENDOR_PSI, DEVICE_DALE_1, pdev)))
if ( pcibios_present () )
{
for ( pci_index = 0; pci_index <= MAXADAPTER; ++pci_index )
{
UCHAR pci_bus, pci_device_fn;
if ( pcibios_find_device (VENDOR_PSI, DEVICE_DALE_1, pci_index, &pci_bus, &pci_device_fn) != 0 )
break;
pshost = scsi_register (tpnt, sizeof(ADAPTER2220I));
hostdata = HOSTDATA(pshost);
hostdata->basePort = pdev->base_address[1] & PCI_BASE_ADDRESS_IO_MASK;
DEB (printk ("\nBase Regs = %#04X", hostdata->basePort));
hostdata->regRemap = hostdata->basePort + RTR_LOCAL_REMAP; // 32 bit local space remap
DEB (printk (" %#04X", hostdata->regRemap));
hostdata->regDesc = hostdata->basePort + RTR_REGIONS; // 32 bit local region descriptor
DEB (printk (" %#04X", hostdata->regDesc));
hostdata->regRange = hostdata->basePort + RTR_LOCAL_RANGE; // 32 bit local range
DEB (printk (" %#04X", hostdata->regRange));
hostdata->regIrqControl = hostdata->basePort + RTR_INT_CONTROL_STATUS; // 16 bit interupt control and status
DEB (printk (" %#04X", hostdata->regIrqControl));
hostdata->regScratchPad = hostdata->basePort + RTR_MAILBOX; // 16 byte scratchpad I/O base address
DEB (printk (" %#04X", hostdata->regScratchPad));
hostdata->regBase = pdev->base_address[2] & PCI_BASE_ADDRESS_IO_MASK;
for ( z = 0; z < 9; z++ ) // build regester address array
hostdata->ports[z] = hostdata->regBase + 0x80 + (z * 4);
hostdata->ports[PORT_FAIL] = hostdata->regBase + REG_FAIL;
hostdata->ports[PORT_ALT_STAT] = hostdata->regBase + REG_ALT_STAT;
DEB (printk ("\nPorts ="));
DEB (for (z=0;z<11;z++) printk(" %#04X", hostdata->ports[z]););
hostdata->regDmaDesc = hostdata->regBase + RTL_DMA1_DESC_PTR; // address of the DMA discriptor register for direction of transfer
DEB (printk ("\nDMA Regs = %#04X", hostdata->regDmaDesc));
hostdata->regDmaCmdStat = hostdata->regBase + RTL_DMA_COMMAND_STATUS + 1; // Byte #1 of DMA command status register
DEB (printk (" %#04X", hostdata->regDmaCmdStat));
hostdata->regDmaAddrPci = hostdata->regBase + RTL_DMA1_PCI_ADDR; // 32 bit register for PCI address of DMA
DEB (printk (" %#04X", hostdata->regDmaAddrPci));
hostdata->regDmaAddrLoc = hostdata->regBase + RTL_DMA1_LOCAL_ADDR; // 32 bit register for local bus address of DMA
DEB (printk (" %#04X", hostdata->regDmaAddrLoc));
hostdata->regDmaCount = hostdata->regBase + RTL_DMA1_COUNT; // 32 bit register for DMA transfer count
DEB (printk (" %#04X", hostdata->regDmaCount));
hostdata->regDmaMode = hostdata->regBase + RTL_DMA1_MODE + 1; // 32 bit register for DMA mode control
DEB (printk (" %#04X", hostdata->regDmaMode));
if ( !inb_p (hostdata->regScratchPad + DALE_NUM_DRIVES) ) // if no devices on this board
padapter = HOSTDATA(pshost);
memset (padapter, 0, sizeof (ADAPTER2220I));
pcibios_read_config_word (pci_bus, pci_device_fn, PCI_BASE_ADDRESS_1, &zs);
zs &= 0xFFFE;
padapter->basePort = zs;
padapter->regRemap = zs + RTR_LOCAL_REMAP; // 32 bit local space remap
padapter->regDesc = zs + RTR_REGIONS; // 32 bit local region descriptor
padapter->regRange = zs + RTR_LOCAL_RANGE; // 32 bit local range
padapter->regIrqControl = zs + RTR_INT_CONTROL_STATUS; // 16 bit interupt control and status
padapter->regScratchPad = zs + RTR_MAILBOX; // 16 byte scratchpad I/O base address
pcibios_read_config_word (pci_bus, pci_device_fn, PCI_BASE_ADDRESS_2, &zs);
zs &= 0xFFFE;
padapter->regBase = zs;
padapter->regData = zs + REG_DATA; // data register I/O address
padapter->regError = zs + REG_ERROR; // error register I/O address
padapter->regSectCount = zs + REG_SECTOR_COUNT; // sector count register I/O address
padapter->regLba0 = zs + REG_LBA_0; // least significant byte of LBA
padapter->regLba8 = zs + REG_LBA_8; // next least significant byte of LBA
padapter->regLba16 = zs + REG_LBA_16; // next most significan byte of LBA
padapter->regLba24 = zs + REG_LBA_24; // head and most 4 significant bits of LBA
padapter->regStatCmd = zs + REG_STAT_CMD; // status on read and command on write register
padapter->regStatSel = zs + REG_STAT_SEL; // board status on read and spigot select on write register
padapter->regFail = zs + REG_FAIL;
padapter->regAltStat = zs + REG_ALT_STAT;
padapter->regDmaDesc = zs + RTL_DMA1_DESC_PTR; // address of the DMA discriptor register for direction of transfer
padapter->regDmaCmdStat = zs + RTL_DMA_COMMAND_STATUS + 1; // Byte #1 of DMA command status register
padapter->regDmaAddrPci = zs + RTL_DMA1_PCI_ADDR; // 32 bit register for PCI address of DMA
padapter->regDmaAddrLoc = zs + RTL_DMA1_LOCAL_ADDR; // 32 bit register for local bus address of DMA
padapter->regDmaCount = zs + RTL_DMA1_COUNT; // 32 bit register for DMA transfer count
padapter->regDmaMode = zs + RTL_DMA1_MODE + 1; // 32 bit register for DMA mode control
if ( !inb_p (padapter->regScratchPad + DALE_NUM_DRIVES) ) // if no devices on this board
goto unregister;
pshost->irq = pdev->irq;
pcibios_read_config_byte (pci_bus, pci_device_fn, PCI_INTERRUPT_LINE, &pshost->irq);
setirq = 1;
for ( z = 0; z < NumAdapters; z++ ) // scan for shared interrupts
for ( z = 0; z < pci_index; z++ ) // scan for shared interrupts
{
if ( PsiHost[z]->irq == pshost->irq ) // if shared then, don't posses
if ( PsiHost[z]->irq == pshost->irq ) // if shared then, don't posses
setirq = 0;
}
if ( setirq ) // if not shared, posses
if ( setirq ) // if not shared, posses
{
if ( request_irq (pshost->irq, do_Irq_Handler, 0, "pci2220i", NULL) )
if ( request_irq (pshost->irq, Irq_Handler, 0, "pci2220i", NULL) )
{
printk ("Unable to allocate IRQ for PSI-2220I controller.\n");
goto unregister;
}
}
PsiHost[NumAdapters] = pshost; // save SCSI_HOST pointer
PsiHost[pci_index] = pshost; // save SCSI_HOST pointer
pshost->unique_id = hostdata->regBase;
pshost->unique_id = padapter->regBase;
pshost->max_id = 4;
outb_p (0x01, hostdata->regRange); // fix our range register because other drivers want to tromp on it
hostdata->timingMode = inb_p (hostdata->regScratchPad + DALE_TIMING_MODE);
hostdata->timingAddress = modearray[hostdata->timingMode - 2];
ReadFlash (hostdata, &DaleSetup, DALE_FLASH_SETUP, sizeof (SETUP));
outb_p (0x01, padapter->regRange); // fix our range register because other drivers want to tromp on it
for ( z = 0; z < inb_p (hostdata->regScratchPad + DALE_NUM_DRIVES); ++z )
padapter->timingMode = inb_p (padapter->regScratchPad + DALE_TIMING_MODE);
if ( padapter->timingMode >= 2 )
padapter->timingAddress = ModeArray[padapter->timingMode - 2];
else
padapter->timingPIO = TRUE;
ReadFlash (padapter, &DaleSetup, DALE_FLASH_SETUP, sizeof (SETUP));
for ( z = 0; z < inb_p (padapter->regScratchPad + DALE_NUM_DRIVES); ++z )
{
unit = inb_p (hostdata->regScratchPad + DALE_CHANNEL_DEVICE_0 + z) & 0x0F;
hostdata->device[unit].device = inb_p (hostdata->regScratchPad + DALE_SCRATH_DEVICE_0 + unit);
hostdata->device[unit].byte6 = (UCHAR)(((unit & 1) << 4) | 0xE0);
hostdata->device[unit].spigot = (UCHAR)(1 << (unit >> 1));
hostdata->device[unit].sectors = DaleSetup.setupDevice[unit].sectors;
hostdata->device[unit].heads = DaleSetup.setupDevice[unit].heads;
hostdata->device[unit].cylinders = DaleSetup.setupDevice[unit].cylinders;
hostdata->device[unit].blocks = DaleSetup.setupDevice[unit].blocks;
DEB (printk ("\nHOSTDATA->device = %X", hostdata->device[unit].device));
DEB (printk ("\n byte6 = %X", hostdata->device[unit].byte6));
DEB (printk ("\n spigot = %X", hostdata->device[unit].spigot));
DEB (printk ("\n sectors = %X", hostdata->device[unit].sectors));
DEB (printk ("\n heads = %X", hostdata->device[unit].heads));
DEB (printk ("\n cylinders = %X", hostdata->device[unit].cylinders));
DEB (printk ("\n blocks = %lX", hostdata->device[unit].blocks));
unit = inb_p (padapter->regScratchPad + DALE_CHANNEL_DEVICE_0 + z) & 0x0F;
padapter->device[z].device = inb_p (padapter->regScratchPad + DALE_SCRATH_DEVICE_0 + unit);
padapter->device[z].byte6 = (UCHAR)(((unit & 1) << 4) | 0xE0);
padapter->device[z].spigot = (UCHAR)(1 << (unit >> 1));
padapter->device[z].sectors = DaleSetup.setupDevice[unit].sectors;
padapter->device[z].heads = DaleSetup.setupDevice[unit].heads;
padapter->device[z].cylinders = DaleSetup.setupDevice[unit].cylinders;
padapter->device[z].blocks = DaleSetup.setupDevice[unit].blocks;
if ( !z )
{
ReadFlash (padapter, &DiskMirror, DALE_FLASH_RAID, sizeof (DiskMirror));
DiskMirror[0].status = inb_p (padapter->regScratchPad + DALE_RAID_0_STATUS);
DiskMirror[1].status = inb_p (padapter->regScratchPad + DALE_RAID_1_STATUS);
if ( (DiskMirror[0].signature == SIGNATURE) && (DiskMirror[1].signature == SIGNATURE) &&
(DiskMirror[0].pairIdentifier == (DiskMirror[1].pairIdentifier ^ 1)) )
{
raidon = TRUE;
}
memcpy (padapter->device[z].DiskMirror, DiskMirror, sizeof (DiskMirror));
padapter->raidData[0] = &padapter->device[z].DiskMirror[0];
padapter->raidData[2] = &padapter->device[z].DiskMirror[1];
if ( raidon )
{
padapter->device[z].lastsectorlba[0] = InlineIdentify (padapter, 1, 0);
padapter->device[z].lastsectorlba[1] = InlineIdentify (padapter, 2, 0);
if ( !(DiskMirror[1].status & UCBF_SURVIVOR) && padapter->device[z].lastsectorlba[0] )
spigot1 = TRUE;
if ( !(DiskMirror[0].status & UCBF_SURVIVOR) && padapter->device[z].lastsectorlba[1] )
spigot2 = TRUE;
if ( DiskMirror[0].status & UCBF_SURVIVOR & DiskMirror[1].status & UCBF_SURVIVOR )
spigot1 = TRUE;
if ( spigot1 && spigot2 )
{
padapter->device[z].raid = 1;
if ( DiskMirror[0].status & UCBF_REBUILD )
padapter->device[z].spigot = 2;
else
padapter->device[z].spigot = 1;
if ( (DiskMirror[0].status & UCBF_REBUILD) || (DiskMirror[1].status & UCBF_REBUILD) )
{
padapter->reconOn = padapter->reconIsStarting = TRUE;
}
}
else
{
if ( spigot1 )
{
if ( DiskMirror[0].status & UCBF_REBUILD )
goto unregister;
DiskMirror[0].status = UCBF_MIRRORED | UCBF_SURVIVOR;
padapter->device[z].spigot = 1;
}
else
{
if ( DiskMirror[1].status & UCBF_REBUILD )
goto unregister;
DiskMirror[1].status = UCBF_MIRRORED | UCBF_SURVIVOR;
padapter->device[z].spigot = 2;
}
if ( DaleSetup.rebootRebuil )
padapter->reconOn = padapter->reconIsStarting = TRUE;
}
break;
}
}
}
printk("\nPSI-2220I EIDE CONTROLLER: at I/O = %X/%X IRQ = %d\n", hostdata->basePort, hostdata->regBase, pshost->irq);
printk("(C) 1997 Perceptive Solutions, Inc. All rights reserved\n\n");
init_timer (&padapter->timer);
padapter->timer.function = TimerExpiry;
padapter->timer.data = (unsigned long)padapter;
init_timer (&padapter->reconTimer);
padapter->reconTimer.function = ReconTimerExpiry;
padapter->reconTimer.data = (unsigned long)padapter;
printk("\nPCI-2220I EIDE CONTROLLER: at I/O = %X/%X IRQ = %d\n", padapter->basePort, padapter->regBase, pshost->irq);
printk("Version %s, Compiled %s %s\n\n", PCI2220I_VERSION, __DATE__, __TIME__);
NumAdapters++;
continue;
unregister:
unregister:;
scsi_unregister (pshost);
NumAdapters++;
}
}
return NumAdapters;
}
/****************************************************************
......@@ -756,7 +1848,6 @@ int Pci2220i_Detect (Scsi_Host_Template *tpnt)
****************************************************************/
int Pci2220i_Abort (Scsi_Cmnd *SCpnt)
{
DEB (printk ("pci2220i_abort\n"));
return SCSI_ABORT_SNOOZE;
}
/****************************************************************
......
/*+M*************************************************************************
* Perceptive Solutions, Inc. PCI-2000 device driver proc support for Linux.
*
* Copyright (c) 1997 Perceptive Solutions, Inc.
* Copyright (c) 1999 Perceptive Solutions, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -25,12 +25,6 @@
*
*-M*************************************************************************/
#ifndef _PCI2220I_H
#define _PCI2220I_H
#include <linux/types.h>
#include <linux/kdev_t.h>
#ifndef PSI_EIDE_SCSIOP
#define PSI_EIDE_SCSIOP 1
......@@ -46,11 +40,14 @@
#define ULONG unsigned long
#define VOID void
#include "psi_dale.h"
/************************************************/
/* Timeout konstants */
/************************************************/
#define TIMEOUT_READY 10 // 100 mSec
#define TIMEOUT_DRQ 40 // 400 mSec
#define TIMEOUT_READY 100 // 100 mSec
#define TIMEOUT_DRQ 300 // 300 mSec
#define TIMEOUT_DATA (3 * HZ) // 3 seconds
/************************************************/
/* Misc. macros */
......@@ -76,6 +73,9 @@
+ (((long)(((UCHAR *)up)[2])) << 8) \
+ ((long)(((UCHAR *)up)[3])) )
#define SelectSpigot(padapter,spigot) outb_p (spigot, padapter->regStatSel)
#define WriteCommand(padapter,cmd) outb_p (cmd, padapter->regStatCmd)
/************************************************/
/* SCSI CDB operation codes */
/************************************************/
......@@ -163,8 +163,6 @@
#define IDE_CMD_READ_MULTIPLE 0xC4
#define IDE_CMD_WRITE_MULTIPLE 0xC5
#define IDE_CMD_SET_MULTIPLE 0xC6
#define IDE_COMMAND_WRITE_DMA 0xCA
#define IDE_COMMAND_READ_DMA 0xC8
#define IDE_COMMAND_IDENTIFY 0xEC
// IDE status definitions
......@@ -187,23 +185,6 @@
#define IDE_ERROR_UNC 0x40
#define IDE_ERROR_BBK 0x80
// IDE interface structure
typedef struct _IDE_STRUCT
{
union
{
UCHAR ide[9];
struct
{
USHORT data;
UCHAR sectors;
UCHAR lba[4];
UCHAR cmd;
UCHAR spigot;
} ides;
} ide;
} IDE_STRUCT;
// SCSI read capacity structure
typedef struct _READ_CAPACITY_DATA
{
......@@ -238,73 +219,64 @@ typedef struct _INQUIRYDATA
} INQUIRYDATA, *PINQUIRYDATA;
// IDE IDENTIFY data
#pragma pack (1)
#pragma align 1
typedef struct _IDENTIFY_DATA
{
USHORT GeneralConfiguration; // 00
USHORT NumberOfCylinders; // 02
USHORT Reserved1; // 04
USHORT NumberOfHeads; // 06
USHORT UnformattedBytesPerTrack; // 08
USHORT UnformattedBytesPerSector; // 0A
USHORT SectorsPerTrack; // 0C
USHORT VendorUnique1[3]; // 0E
USHORT SerialNumber[10]; // 14
USHORT BufferType; // 28
USHORT BufferSectorSize; // 2A
USHORT NumberOfEccBytes; // 2C
USHORT FirmwareRevision[4]; // 2E
USHORT ModelNumber[20]; // 36
UCHAR MaximumBlockTransfer; // 5E
UCHAR VendorUnique2; // 5F
USHORT DoubleWordIo; // 60
USHORT Capabilities; // 62
USHORT Reserved2; // 64
UCHAR VendorUnique3; // 66
UCHAR PioCycleTimingMode; // 67
UCHAR VendorUnique4; // 68
UCHAR DmaCycleTimingMode; // 69
USHORT TranslationFieldsValid:1; // 6A
USHORT Reserved3:15;
USHORT NumberOfCurrentCylinders; // 6C
USHORT NumberOfCurrentHeads; // 6E
USHORT CurrentSectorsPerTrack; // 70
ULONG CurrentSectorCapacity; // 72
USHORT Reserved4[197]; // 76
USHORT GeneralConfiguration; // 0
USHORT NumberOfCylinders; // 1
USHORT Reserved1; // 2
USHORT NumberOfHeads; // 3
USHORT UnformattedBytesPerTrack; // 4
USHORT UnformattedBytesPerSector; // 5
USHORT SectorsPerTrack; // 6
USHORT NumBytesISG; // 7 Byte Len - inter-sector gap
USHORT NumBytesSync; // 8 - sync field
USHORT NumWordsVUS; // 9 Len - Vendor Unique Info
USHORT SerialNumber[10]; // 10
USHORT BufferType; // 20
USHORT BufferSectorSize; // 21
USHORT NumberOfEccBytes; // 22
USHORT FirmwareRevision[4]; // 23
USHORT ModelNumber[20]; // 27
USHORT NumSectorsPerInt :8; // 47 Multiple Mode - Sec/Blk
USHORT Reserved2 :8; // 47
USHORT DoubleWordMode; // 48 flag for double word mode capable
USHORT VendorUnique1 :8; // 49
USHORT SupportDMA :1; // 49 DMA supported
USHORT SupportLBA :1; // 49 LBA supported
USHORT SupportIORDYDisable :1; // 49 IORDY can be disabled
USHORT SupportIORDY :1; // 49 IORDY supported
USHORT ReservedPsuedoDMA :1; // 49 reserved for pseudo DMA mode support
USHORT Reserved3 :3; // 49
USHORT Reserved4; // 50
USHORT Reserved5 :8; // 51 Transfer Cycle Timing - PIO
USHORT PIOCycleTime :8; // 51 Transfer Cycle Timing - PIO
USHORT Reserved6 :8; // 52 - DMA
USHORT DMACycleTime :8; // 52 - DMA
USHORT Valid_54_58 :1; // 53 words 54 - 58 are vaild
USHORT Valid_64_70 :1; // 53 words 64 - 70 are valid
USHORT Reserved7 :14; // 53
USHORT LogNumCyl; // 54 Current Translation - Num Cyl
USHORT LogNumHeads; // 55 Num Heads
USHORT LogSectorsPerTrack; // 56 Sec/Trk
ULONG LogTotalSectors; // 57 Total Sec
USHORT CurrentNumSecPerInt :8; // 59 current setting for number of sectors per interrupt
USHORT ValidNumSecPerInt :1; // 59 Current setting is valid for number of sectors per interrupt
USHORT Reserved8 :7; // 59
ULONG LBATotalSectors; // 60 LBA Mode - Sectors
USHORT DMASWordFlags; // 62
USHORT DMAMWordFlags; // 63
USHORT AdvancedPIOSupport :8; // 64 Flow control PIO transfer modes supported
USHORT Reserved9 :8; // 64
USHORT MinMultiDMACycle; // 65 minimum multiword DMA transfer cycle time per word
USHORT RecomendDMACycle; // 66 Manufacturer's recommende multiword DMA transfer cycle time
USHORT MinPIOCycleWithoutFlow; // 67 Minimum PIO transfer cycle time without flow control
USHORT MinPIOCylceWithFlow; // 68 Minimum PIO transfer cycle time with IORDY flow control
USHORT ReservedSpace[256-69]; // 69
} IDENTIFY_DATA, *PIDENTIFY_DATA;
// Identify data without the Reserved4.
typedef struct _IDENTIFY_DATA2 {
USHORT GeneralConfiguration; // 00
USHORT NumberOfCylinders; // 02
USHORT Reserved1; // 04
USHORT NumberOfHeads; // 06
USHORT UnformattedBytesPerTrack; // 08
USHORT UnformattedBytesPerSector; // 0A
USHORT SectorsPerTrack; // 0C
USHORT VendorUnique1[3]; // 0E
USHORT SerialNumber[10]; // 14
USHORT BufferType; // 28
USHORT BufferSectorSize; // 2A
USHORT NumberOfEccBytes; // 2C
USHORT FirmwareRevision[4]; // 2E
USHORT ModelNumber[20]; // 36
UCHAR MaximumBlockTransfer; // 5E
UCHAR VendorUnique2; // 5F
USHORT DoubleWordIo; // 60
USHORT Capabilities; // 62
USHORT Reserved2; // 64
UCHAR VendorUnique3; // 66
UCHAR PioCycleTimingMode; // 67
UCHAR VendorUnique4; // 68
UCHAR DmaCycleTimingMode; // 69
USHORT TranslationFieldsValid:1; // 6A
USHORT Reserved3:15;
USHORT NumberOfCurrentCylinders; // 6C
USHORT NumberOfCurrentHeads; // 6E
USHORT CurrentSectorsPerTrack; // 70
ULONG CurrentSectorCapacity; // 72
} IDENTIFY_DATA2, *PIDENTIFY_DATA2;
#pragma pack ()
#pragma align 0
#endif // PSI_EIDE_SCSIOP
// function prototypes
......@@ -321,18 +293,24 @@ int Pci2220i_BiosParam (Disk *disk, kdev_t dev, int geom[]);
extern struct proc_dir_entry Proc_Scsi_Pci2220i;
#define PCI2220I { proc_dir: &Proc_Scsi_Pci2220i,/* proc_dir_entry */ \
name: "PCI-2220I EIDE Disk Controller",\
detect: Pci2220i_Detect, \
command: Pci2220i_Command, \
queuecommand: Pci2220i_QueueCommand, \
abort: Pci2220i_Abort, \
reset: Pci2220i_Reset, \
bios_param: Pci2220i_BiosParam, \
can_queue: 1, \
this_id: -1, \
sg_tablesize: SG_NONE, \
cmd_per_lun: 1, \
use_clustering: DISABLE_CLUSTERING }
#define PCI2220I { NULL, NULL, \
&Proc_Scsi_Pci2220i,/* proc_dir_entry */\
NULL, \
"PCI-2220I EIDE Disk Controller", \
Pci2220i_Detect, \
NULL, \
NULL, \
Pci2220i_Command, \
Pci2220i_QueueCommand, \
Pci2220i_Abort, \
Pci2220i_Reset, \
NULL, \
Pci2220i_BiosParam, \
1, \
-1, \
SG_NONE, \
1, \
0, \
0, \
DISABLE_CLUSTERING }
#endif
/*+M*************************************************************************
* Perceptive Solutions, Inc. PCI-2000 device driver proc support for Linux.
*
* Copyright (c) 1997 Perceptive Solutions, Inc.
* Copyright (c) 1999 Perceptive Solutions, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -25,9 +25,6 @@
*
*-M*************************************************************************/
#ifndef PSI_DALE
#define PSI_DALE
/************************************************/
/* Dale PCI setup */
/************************************************/
......@@ -58,24 +55,24 @@
/************************************************/
/* DALE Register address offsets */
/************************************************/
#define REG_DATA 0x80
#define REG_ERROR 0x84
#define REG_SECTOR_COUNT 0x88
#define REG_LBA_0 0x8C
#define REG_LBA_8 0x90
#define REG_LBA_16 0x94
#define REG_LBA_24 0x98
#define REG_STAT_CMD 0x9C
#define REG_STAT_SEL 0xA0
#define REG_FAIL 0xB0
#define REG_ALT_STAT 0xB8
#define REG_DRIVE_ADRS 0xBC
#define DALE_DATA_SLOW 0x00040000L
#define DALE_DATA_MODE2 0x00040000L
#define DALE_DATA_MODE3 0x00050000L
#define DALE_DATA_MODE4 0x00060000L
#define DALE_DATA_MODE4P 0x00070000L
#define REG_DATA 0x80
#define REG_ERROR 0x84
#define REG_SECTOR_COUNT 0x88
#define REG_LBA_0 0x8C
#define REG_LBA_8 0x90
#define REG_LBA_16 0x94
#define REG_LBA_24 0x98
#define REG_STAT_CMD 0x9C
#define REG_STAT_SEL 0xA0
#define REG_FAIL 0xB0
#define REG_ALT_STAT 0xB8
#define REG_DRIVE_ADRS 0xBC
#define DALE_DATA_SLOW 0x00040000L
#define DALE_DATA_MODE2 0x00040000L
#define DALE_DATA_MODE3 0x00050000L
#define DALE_DATA_MODE4 0x00060000L
#define DALE_DATA_MODE4P 0x00070000L
#define RTR_LOCAL_RANGE 0x000
#define RTR_LOCAL_REMAP 0x004
......@@ -110,52 +107,52 @@
/************************************************/
/* Dale Scratchpad locations */
/************************************************/
#define DALE_CHANNEL_DEVICE_0 0 // device channel locations
#define DALE_CHANNEL_DEVICE_1 1
#define DALE_CHANNEL_DEVICE_2 2
#define DALE_CHANNEL_DEVICE_3 3
#define DALE_CHANNEL_DEVICE_0 0 // device channel locations
#define DALE_CHANNEL_DEVICE_1 1
#define DALE_CHANNEL_DEVICE_2 2
#define DALE_CHANNEL_DEVICE_3 3
#define DALE_SCRATH_DEVICE_0 4 // device type codes
#define DALE_SCRATH_DEVICE_1 5
#define DALE_SCRATH_DEVICE_2 6
#define DALE_SCRATH_DEVICE_3 7
#define DALE_SCRATH_DEVICE_0 4 // device type codes
#define DALE_SCRATH_DEVICE_1 5
#define DALE_SCRATH_DEVICE_2 6
#define DALE_SCRATH_DEVICE_3 7
#define DALE_RAID_0_STATUS 8
#define DALE_RAID_1_STATUS 9
#define DALE_RAID_0_STATUS 8
#define DALE_RAID_1_STATUS 9
#define DALE_TIMING_MODE 12 // bus master timing mode (2, 3, 4, 5)
#define DALE_NUM_DRIVES 13 // number of addressable drives on this board
#define DALE_RAID_ON 14 // RAID status On
#define DALE_LAST_ERROR 15 // Last error code from BIOS
#define DALE_TIMING_MODE 12 // bus master timing mode (2, 3, 4, 5)
#define DALE_NUM_DRIVES 13 // number of addressable drives on this board
#define DALE_RAID_ON 14 // RAID status On
#define DALE_LAST_ERROR 15 // Last error code from BIOS
/************************************************/
/* Dale cable select bits */
/************************************************/
#define SEL_NONE 0x00
#define SEL_1 0x01
#define SEL_2 0x02
#define SEL_NONE 0x00
#define SEL_1 0x01
#define SEL_2 0x02
/************************************************/
/* Programmable Interrupt Controller */
/************************************************/
#define PIC1 0x20 // first 8259 base port address
#define PIC2 0xA0 // second 8259 base port address
#define INT_OCW1 1 // Operation Control Word 1: IRQ mask
#define EOI 0x20 // non-specific end-of-interrupt
#define PIC1 0x20 // first 8259 base port address
#define PIC2 0xA0 // second 8259 base port address
#define INT_OCW1 1 // Operation Control Word 1: IRQ mask
#define EOI 0x20 // non-specific end-of-interrupt
/************************************************/
/* Device/Geometry controls */
/************************************************/
#define GEOMETRY_NONE 0x0 // No device
#define GEOMETRY_SET 0x1 // Geometry set
#define GEOMETRY_LBA 0x2 // Geometry set in default LBA mode
#define GEOMETRY_PHOENIX 0x3 // Geometry set in Pheonix BIOS compatibility mode
#define GEOMETRY_NONE 0x0 // No device
#define GEOMETRY_SET 0x1 // Geometry set
#define GEOMETRY_LBA 0x2 // Geometry set in default LBA mode
#define GEOMETRY_PHOENIX 0x3 // Geometry set in Pheonix BIOS compatibility mode
#define DEVICE_NONE 0x0 // No device present
#define DEVICE_INACTIVE 0x1 // device present but not registered active
#define DEVICE_ATAPI 0x2 // ATAPI device (CD_ROM, Tape, Etc...)
#define DEVICE_DASD_NONLBA 0x3 // Non LBA incompatible device
#define DEVICE_DASD_LBA 0x4 // LBA compatible device
#define DEVICE_NONE 0x0 // No device present
#define DEVICE_INACTIVE 0x1 // device present but not registered active
#define DEVICE_ATAPI 0x2 // ATAPI device (CD_ROM, Tape, Etc...)
#define DEVICE_DASD_NONLBA 0x3 // Non LBA incompatible device
#define DEVICE_DASD_LBA 0x4 // LBA compatible device
/************************************************/
/* Setup Structure Definitions */
......@@ -184,4 +181,38 @@ typedef struct // master setup structure
SETUP_DEVICE setupDevice[4];
} SETUP, *PSETUP;
#endif
/************************************************/
/* RAID Structure Definitions */
/************************************************/
typedef struct
{
UCHAR signature; // 0x55 our mirror signature
UCHAR status; // current status bits
UCHAR pairIdentifier; // unique identifier for pair
ULONG reconstructPoint; // recontruction point for hot reconstruct
} DISK_MIRROR;
typedef struct DEVICE_RAID1
{
long TotalSectors;
DISK_MIRROR DiskRaid1;
} DEVICE_RAID1, *PDEVICE_RAID1;
#define DISK_MIRROR_POSITION 0x01A8
#define SIGNATURE 0x55
#define MASK_SERIAL_NUMBER 0x0FFE // mask for serial number matching
#define MASK_SERIAL_UNIT 0x0001 // mask for unit portion of serial number
// Status bits
#define UCBF_MIRRORED 0x0010 // drive has a pair
#define UCBF_MATCHED 0x0020 // drive pair is matched
#define UCBF_SURVIVOR 0x0040 // this unit is a survivor of a pair
#define UCBF_REBUILD 0x0080 // rebuild in progress on this device
// SCSI controls for RAID
#define SC_MY_RAID 0xBF // our special CDB command byte for Win95... interface
#define MY_SCSI_QUERY1 0x32 // byte 1 subcommand to query driver for RAID 1 informatation
#define MY_SCSI_REBUILD 0x40 // byte 1 subcommand to reconstruct a mirrored pair
#define MY_SCSI_DEMOFAIL 0x54 // byte 1 subcommand for RAID failure demonstration
#define MY_SCSI_ALARMMUTE 0x60 // byte 1 subcommand to mute any alarm currently on
......@@ -40,7 +40,7 @@
#define MAXADAPTER 4 // Increase this and the sizes of the arrays below, if you need more.
#define MAX_BUS 2
#define MAX_UNITS 16
#define TIMEOUT_COMMAND 30 // number of jiffies for command busy timeout
#define TIMEOUT_COMMAND 400 // number of milliSecondos for command busy timeout
/************************************************/
/* I/O address offsets */
......@@ -64,6 +64,8 @@
#define CMD_WRITE_CHS_SG 0x08 /* write sectors using scatter/gather list (CHS mode) */
#define CMD_VERIFY_CHS 0x09 /* verify data on sectors as specified (CHS mode) */
#define CMD_VERIFY 0x0A /* verify data on sectors as specified (RBA mode) */
#define CMD_DASD_CDB 0x0B /* process CDB for a DASD device */
#define CMD_DASD_CDB_SG 0x0C /* process CDB for a DASD device with scatter/gather */
#define CMD_READ_ABS 0x10 /* read absolute disk */
#define CMD_WRITE_ABS 0x11 /* write absolute disk */
......@@ -80,9 +82,14 @@
#define CMD_SCSI_THRU_SG 0x31 /* SCSI pass through CDB with scatter/gather */
#define CMD_SCSI_REQ_SENSE 0x32 /* SCSI pass through request sense after check condition */
#define CMD_DASD_SCSI_INQ 0x36 /* to DASD inquire for DASD info in SCSI inquiry format */
#define CMD_DASD_RAID_RQ 0x35 /* request DASD RAID drive data */
#define CMD_DASD_RAID_RQ0 0x31 /* byte 1 subcommand to query for RAID 0 informatation */
#define CMD_DASD_RAID_RQ1 0x32 /* byte 1 subcommand to query for RAID 1 informatation */
#define CMD_DASD_RAID_RQ5 0x33 /* byte 1 subcommand to query for RAID 5 informatation */
#define CMD_DASD_SCSI_INQ 0x36 /* do DASD inquire and return in SCSI format */
#define CMD_DASD_CAP 0x37 /* read DASD capacity */
#define CMD_DASD_INQ 0x38 /* do DASD inquire for type data */
#define CMD_DASD_INQ 0x38 /* do DASD inquire for type data and return SCSI/EIDE inquiry */
#define CMD_SCSI_INQ 0x39 /* do SCSI inquire */
#define CMD_READ_SETUP 0x3A /* Get setup structures from controller */
#define CMD_WRITE_SETUP 0x3B /* Put setup structures in controller and burn in flash */
......@@ -121,6 +128,12 @@
#define CMD_RAID_STATUS 0x57 /* get status of RAID pair */
#define CMD_RAID_STOP 0x58 /* stop any reconstruct in progress */
#define CMD_RAID_START 0x59 /* start reconstruct */
#define CMD_RAID0_READ 0x5A /* read RAID 0 parameter block */
#define CMD_RAID0_WRITE 0x5B /* write RAID 0 parameter block */
#define CMD_RAID5_READ 0x5C /* read RAID 5 parameter block */
#define CMD_RAID5_WRITE 0x5D /* write RAID 5 parameter block */
#define CMD_ERASE_TABLES 0x5F /* erase partition table and RAID signatutures */
#define CMD_SCSI_GET 0x60 /* get SCSI pass through devices */
#define CMD_SCSI_TIMEOUT 0x61 /* set SCSI pass through timeout */
......@@ -223,13 +236,13 @@
/* Host Operating System specification codes */
/* */
/************************************************/
#define SPEC_INTERRUPT 0x80 /* specification requires host interrupt */
#define SPEC_BACKWARD_SG 0x40 /* specification requires scatter/gather items reversed */
#define SPEC_DOS_BLOCK 0x01 /* DOS DASD blocking on pass through */
#define SPEC_OS2_V3 0x02 /* OS/2 Warp */
#define SPCE_SCO_3242 0x04 /* SCO 3.4.2.2 */
#define SPEC_QNX_4X 0x05 /* QNX 4.XX */
#define SPEC_NOVELL_NWPA 0x08 /* Novell NWPA scatter/gather support */
/************************************************/
/* */
......@@ -310,5 +323,15 @@ typedef struct _DASD_INQUIRE
#define DEVC_DASD_REMOVABLE 0x80 /* Direct-access storage device, Removable */
#define DEVC_NONE 0xFF /* no device */
// SCSI controls for RAID
#define SC_MY_RAID 0xBF // our special CDB command byte for Win95... interface
#define MY_SCSI_QUERY0 0x31 // byte 1 subcommand to query driver for RAID 0 informatation
#define MY_SCSI_QUERY1 0x32 // byte 1 subcommand to query driver for RAID 1 informatation
#define MY_SCSI_QUERY5 0x33 // byte 1 subcommand to query driver for RAID 5 informatation
#define MY_SCSI_REBUILD 0x40 // byte 1 subcommand to reconstruct a mirrored pair
#define MY_SCSI_DEMOFAIL 0x54 // byte 1 subcommand for RAID failure demonstration
#define MY_SCSI_ALARMMUTE 0x60 // byte 1 subcommand to mute any alarm currently on
#endif
......@@ -206,7 +206,7 @@ do_aout_core_dump(long signr, struct pt_regs * regs)
set_fs(KERNEL_DS);
DUMP_WRITE(current,sizeof(*current));
close_coredump:
close_fp(file, NULL);
filp_close(file, NULL);
end_coredump:
set_fs(fs);
return has_dumped;
......@@ -318,6 +318,8 @@ static inline int do_load_aout_binary(struct linux_binprm * bprm, struct pt_regs
}
if (N_MAGIC(ex) == ZMAGIC && ex.a_text &&
bprm->dentry->d_inode->i_op &&
bprm->dentry->d_inode->i_op->bmap &&
(fd_offset < bprm->dentry->d_inode->i_sb->s_blocksize)) {
printk(KERN_NOTICE "N_TXTOFF < BLOCK_SIZE. Please convert binary.\n");
return -ENOEXEC;
......
......@@ -1324,7 +1324,7 @@ static int elf_core_dump(long signr, struct pt_regs * regs)
}
close_coredump:
close_fp(file, NULL);
filp_close(file, NULL);
end_coredump:
set_fs(fs);
......
......@@ -759,7 +759,7 @@ int bmap(struct inode * inode, int block)
* Initialize the hash tables and default
* value for max inodes
*/
#define MAX_INODE (8192)
#define MAX_INODE (12288)
void __init inode_init(void)
{
......
......@@ -776,7 +776,7 @@ void __fput(struct file *filp)
* "id" is the POSIX thread ID. We use the
* files pointer for this..
*/
int close_fp(struct file *filp, fl_owner_t id)
int filp_close(struct file *filp, fl_owner_t id)
{
int retval;
struct dentry *dentry = filp->f_dentry;
......@@ -812,7 +812,7 @@ asmlinkage int sys_close(unsigned int fd)
files->fd[fd] = NULL;
put_unused_fd(fd);
FD_CLR(fd, &files->close_on_exec);
error = close_fp(filp, files);
error = filp_close(filp, files);
}
unlock_kernel();
return error;
......
......@@ -576,7 +576,7 @@ int sysv_link(struct dentry * old_dentry, struct inode * dir,
oldinode->i_nlink++;
oldinode->i_ctime = CURRENT_TIME;
mark_inode_dirty(oldinode);
inode->i_count++;
oldinode->i_count++;
d_instantiate(dentry, oldinode);
return 0;
}
......
......@@ -141,8 +141,8 @@ extern inline int down_trylock(struct semaphore * sem)
" subq %1,1,%1\n"
" blt %2,2f\n"
" blt %1,2f\n"
" ldah %1,0x8000(%1)\n"
" ldah %1,0x8000(%1)\n"
" ldah %1,-32768(%1)\n"
" ldah %1,-32768(%1)\n"
" lda %0,1\n"
" stq_c %1,%3\n"
" beq %1,3f\n"
......
......@@ -11,6 +11,8 @@
#define GSI_UACPROC 8
#define GSI_IEEE_FP_CONTROL 45
#define GSI_IEEE_STATE_AT_SIGNAL 46
#define GSI_PROC_TYPE 60
#define GSI_GET_HWRPB 101
#define SSI_NVPAIRS 1
#define SSI_IEEE_FP_CONTROL 14
......
......@@ -112,7 +112,7 @@ do { unsigned long flags; \
_do_read_unlock(lock, "read_unlock"); \
__restore_flags(flags); \
} while(0)
#define read_unlock_irq(lock) do { _do_read_unlock(lock, "read_unlock_irq"); __sti() } while(0)
#define read_unlock_irq(lock) do { _do_read_unlock(lock, "read_unlock_irq"); __sti(); } while(0)
#define read_unlock_irqrestore(lock, flags) do { _do_read_unlock(lock, "read_unlock_irqrestore"); __restore_flags(flags); } while(0)
#define write_lock(lock) \
......
......@@ -695,8 +695,9 @@ asmlinkage int sys_close(unsigned int); /* yes, it's really unsigned */
extern int do_truncate(struct dentry *, unsigned long);
extern int get_unused_fd(void);
extern void put_unused_fd(unsigned int);
extern int close_fp(struct file *, fl_owner_t id);
extern struct file *filp_open(const char *, int, int);
extern int filp_close(struct file *, fl_owner_t id);
extern char * getname(const char * filename);
#define __getname() ((char *) __get_free_page(GFP_KERNEL))
......
......@@ -55,7 +55,7 @@ extern __inline__ int DQUOT_PREALLOC_BLOCK(struct super_block *sb, const struct
{
if (sb->dq_op) {
if (sb->dq_op->alloc_block(inode, fs_to_dq_blocks(nr, sb->s_blocksize),
current->euid, 0) == NO_QUOTA)
current->fsuid, 0) == NO_QUOTA)
return 1;
}
return 0;
......@@ -65,7 +65,7 @@ extern __inline__ int DQUOT_ALLOC_BLOCK(struct super_block *sb, const struct ino
{
if (sb->dq_op) {
if (sb->dq_op->alloc_block(inode, fs_to_dq_blocks(nr, sb->s_blocksize),
current->euid, 1) == NO_QUOTA)
current->fsuid, 1) == NO_QUOTA)
return 1;
}
return 0;
......@@ -75,7 +75,7 @@ extern __inline__ int DQUOT_ALLOC_INODE(struct super_block *sb, struct inode *in
{
if (sb->dq_op) {
sb->dq_op->initialize (inode, -1);
if (sb->dq_op->alloc_inode (inode, 1, current->euid))
if (sb->dq_op->alloc_inode (inode, 1, current->fsuid))
return 1;
}
inode->i_flags |= S_QUOTA;
......@@ -101,11 +101,11 @@ extern __inline__ int DQUOT_TRANSFER(struct dentry *dentry, struct iattr *iattr)
if (dentry->d_inode->i_sb->dq_op) {
if (IS_QUOTAINIT(dentry->d_inode) == 0)
dentry->d_inode->i_sb->dq_op->initialize(dentry->d_inode, -1);
if (dentry->d_inode->i_sb->dq_op->transfer(dentry->d_inode, iattr, 0, current->euid))
if (dentry->d_inode->i_sb->dq_op->transfer(dentry->d_inode, iattr, 0, current->fsuid))
goto out;
error = notify_change(dentry, iattr);
if (error)
dentry->d_inode->i_sb->dq_op->transfer(dentry->d_inode, iattr, 1, current->euid);
dentry->d_inode->i_sb->dq_op->transfer(dentry->d_inode, iattr, 1, current->fsuid);
} else {
error = notify_change(dentry, iattr);
}
......
......@@ -59,7 +59,7 @@ extern task_queue tq_timer, tq_immediate, tq_scheduler, tq_disk;
*
* struct tq_struct *my_bh = NULL;
* struct tq_struct run_my_bh = {
* 0, 0, (void *)(void *) run_task_queue, &my_bh
* 0, 0, (void (*)(void *)) run_task_queue, &my_bh
* };
*
* To activate a bottom half on your list, use:
......
......@@ -194,13 +194,13 @@ asmlinkage int sys_acct(const char *name)
}
if (old_acct) {
do_acct_process(0,old_acct);
fput(old_acct);
filp_close(old_acct);
}
out:
unlock_kernel();
return error;
out_err:
fput(file);
filp_close(file);
goto out;
}
......
......@@ -169,7 +169,7 @@ static inline void close_files(struct files_struct * files)
struct file * file = files->fd[i];
if (file) {
files->fd[i] = NULL;
close_fp(file, files);
filp_close(file, files);
}
}
i++;
......
......@@ -136,6 +136,7 @@ EXPORT_SYMBOL(__mark_inode_dirty);
EXPORT_SYMBOL(get_empty_filp);
EXPORT_SYMBOL(init_private_file);
EXPORT_SYMBOL(filp_open);
EXPORT_SYMBOL(filp_close);
EXPORT_SYMBOL(fput);
EXPORT_SYMBOL(put_filp);
EXPORT_SYMBOL(check_disk_change);
......
......@@ -1326,7 +1326,8 @@ int generic_file_mmap(struct file * file, struct vm_area_struct * vma)
return -EINVAL;
} else {
ops = &file_private_mmap;
if (vma->vm_offset & (inode->i_sb->s_blocksize - 1))
if (inode->i_op && inode->i_op->bmap &&
(vma->vm_offset & (inode->i_sb->s_blocksize - 1)))
return -EINVAL;
}
if (!inode->i_sb || !S_ISREG(inode->i_mode))
......
......@@ -63,6 +63,8 @@ endif
ifeq ($(CONFIG_IPX),y)
SUB_DIRS += ipx
# SPX can be still a module
MOD_SUB_DIRS += ipx
else
ifeq ($(CONFIG_IPX),m)
MOD_SUB_DIRS += ipx
......
......@@ -5,7 +5,7 @@
*
* ROUTE - implementation of the IP router.
*
* Version: $Id: route.c,v 1.63 1999/03/21 05:22:45 davem Exp $
* Version: $Id: route.c,v 1.64 1999/03/23 21:21:13 davem Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
......@@ -1187,7 +1187,7 @@ int ip_route_input_slow(struct sk_buff *skb, u32 daddr, u32 saddr,
if (err)
flags |= RTCF_DIRECTSRC;
if (out_dev == in_dev && err && !(flags&RTCF_NAT) &&
if (out_dev == in_dev && err && !(flags&(RTCF_NAT|RTCF_MASQ)) &&
(IN_DEV_SHARED_MEDIA(out_dev)
|| inet_addr_onlink(out_dev, saddr, FIB_RES_GW(res))))
flags |= RTCF_DOREDIRECT;
......
......@@ -5,7 +5,7 @@
*
* Implementation of the Transmission Control Protocol(TCP).
*
* Version: $Id: tcp_timer.c,v 1.58 1999/03/14 19:48:30 davem Exp $
* Version: $Id: tcp_timer.c,v 1.59 1999/03/23 21:21:09 davem Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
......@@ -403,7 +403,7 @@ static void tcp_keepalive(unsigned long data)
for(i = chain_start; i < (chain_start + ((TCP_HTABLE_SIZE/2) >> 2)); i++) {
struct sock *sk = tcp_established_hash[i];
while(sk) {
if(sk->keepopen) {
if(!atomic_read(&sk->sock_readers) && sk->keepopen) {
count += tcp_keepopen_proc(sk);
if(count == sysctl_tcp_max_ka_probes)
goto out;
......
......@@ -10,8 +10,12 @@
# We only get in/to here if CONFIG_IPX = 'y' or 'm'
O_TARGET := ipx.o
M_OBJS := $(O_TARGET)
OX_OBJS += af_ipx.o
M_OBJS :=
OX_OBJS := af_ipx.o
ifeq ($(CONFIG_IPX),m)
M_OBJS += $(O_TARGET)
endif
ifeq ($(CONFIG_SYSCTL),y)
O_OBJS += sysctl_net_ipx.o
......
......@@ -12,6 +12,7 @@
#include <linux/net.h>
#include <linux/in.h>
#include <linux/netdevice.h>
#include <linux/inetdevice.h>
#include <linux/fddidevice.h>
#include <linux/trdevice.h>
#include <linux/ioport.h>
......@@ -239,6 +240,10 @@ EXPORT_SYMBOL(inet_dgram_ops);
EXPORT_SYMBOL(ip_cmsg_recv);
EXPORT_SYMBOL(__release_sock);
/* Route manipulation */
EXPORT_SYMBOL(ip_rt_ioctl);
EXPORT_SYMBOL(devinet_ioctl);
/* needed for ip_gre -cw */
EXPORT_SYMBOL(ip_statistics);
......@@ -435,6 +440,7 @@ EXPORT_SYMBOL(dev_get_by_index);
EXPORT_SYMBOL(eth_type_trans);
#ifdef CONFIG_FDDI
EXPORT_SYMBOL(fddi_type_trans);
EXPORT_SYMBOL(fddi_setup);
#endif /* CONFIG_FDDI */
EXPORT_SYMBOL(eth_copy_and_sum);
EXPORT_SYMBOL(alloc_skb);
......
......@@ -175,7 +175,8 @@ rpcauth_lookup_credcache(struct rpc_task *task)
if (!cred)
cred = auth->au_ops->crcreate(task);
rpcauth_insert_credcache(auth, cred);
if (cred)
rpcauth_insert_credcache(auth, cred);
return (struct rpc_cred *) cred;
}
......
......@@ -49,8 +49,11 @@ nul_create_cred(struct rpc_task *task)
{
struct rpc_cred *cred;
if (!(cred = (struct rpc_cred *) rpc_malloc(task, sizeof(*cred))))
if (!(cred = (struct rpc_cred *) rpc_malloc(task, sizeof(*cred)))) {
task->tk_status = -ENOMEM;
return NULL;
}
cred->cr_count = 0;
cred->cr_flags = RPCAUTH_CRED_UPTODATE;
......
......@@ -68,8 +68,10 @@ unx_create_cred(struct rpc_task *task)
dprintk("RPC: allocating UNIX cred for uid %d gid %d\n",
current->uid, current->gid);
if (!(cred = (struct unx_cred *) rpc_malloc(task, sizeof(*cred))))
if (!(cred = (struct unx_cred *) rpc_malloc(task, sizeof(*cred)))) {
task->tk_status = -ENOMEM;
return NULL;
}
cred->uc_count = 0;
cred->uc_flags = RPCAUTH_CRED_UPTODATE;
......
......@@ -1197,7 +1197,7 @@ xprt_request_init(struct rpc_task *task, struct rpc_xprt *xprt)
static u32 xid = 0;
if (!xid)
xid = jiffies;
xid = CURRENT_TIME << 12;
dprintk("RPC: %4d reserved req %p xid %08x\n", task->tk_pid, req, xid);
task->tk_status = 0;
......@@ -1206,6 +1206,8 @@ xprt_request_init(struct rpc_task *task, struct rpc_xprt *xprt)
req->rq_task = task;
req->rq_xprt = xprt;
req->rq_xid = xid++;
if (!xid)
xid++;
}
/*
......
......@@ -49,8 +49,8 @@
* such socket and closed it (descriptor). That would happen on
* each unix_gc() until the accept(). Since the struct file in
* question would go to the free list and might be reused...
* That might be the reason of random oopses on close_fp() in
* unrelated processes.
* That might be the reason of random oopses on filp_close()
* in unrelated processes.
*
* AV 28 Feb 1999
* Kill the explicit allocation of stack. Now we keep the tree
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment