From 0b49a591ff18e11417b0ba9ca5124b577e5c60bf Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Fri, 23 Nov 2007 15:11:30 -0500 Subject: [PATCH] Import 2.0.31pre6 --- CREDITS | 2 +- Documentation/Configure.help | 149 +- arch/alpha/kernel/traps.c | 2 +- drivers/char/random.c | 27 +- drivers/char/tty_io.c | 543 ++- drivers/char/tty_ioctl.c | 13 +- drivers/isdn/isdn_tty.c | 11 +- drivers/net/3c509.c | 11 +- drivers/net/3c59x.c | 6 - drivers/net/Config.in | 3 +- drivers/net/Makefile | 9 + drivers/net/Space.c | 4 + drivers/net/dgrs.c | 1 - drivers/net/eepro100.c | 1731 ++++++++ drivers/net/ne.c | 4 + drivers/net/smc-ultra32.c | 1 - drivers/scsi/ChangeLog.ncr53c8xx | 418 ++ drivers/scsi/Config.in | 28 +- drivers/scsi/Makefile | 11 + drivers/scsi/README.ncr53c8xx | 1259 +++++- drivers/scsi/aic7xxx.c | 21 +- drivers/scsi/aic7xxx/aic7xxx.reg | 15 + drivers/scsi/aic7xxx/aic7xxx.seq | 9 + drivers/scsi/aic7xxx_reg.h | 14 +- drivers/scsi/aic7xxx_seq.h | 262 +- drivers/scsi/dc390.h | 147 + drivers/scsi/hosts.c | 7 + drivers/scsi/ncr53c8xx.c | 6532 ++++++++++++++++++++---------- drivers/scsi/ncr53c8xx.h | 460 ++- drivers/scsi/scsiiom.c | 1540 +++++++ drivers/scsi/sd.c | 4 +- drivers/scsi/tmscsim.c | 1928 +++++++++ drivers/scsi/tmscsim.h | 680 ++++ drivers/scsi/ultrastor.c | 7 +- fs/isofs/inode.c | 10 +- fs/smbfs/dir.c | 26 +- fs/smbfs/inode.c | 40 +- fs/smbfs/proc.c | 2 + fs/smbfs/sock.c | 2 + include/asm-i386/shmparam.h | 2 +- include/linux/kernel.h | 10 + include/linux/proc_fs.h | 1 + init/main.c | 4 + kernel/sysctl.c | 2 +- net/ipv4/arp.c | 4 +- net/ipv4/icmp.c | 2 +- net/ipv4/ip_input.c | 4 +- net/ipv4/tcp_input.c | 3 +- scripts/ksymoops.cc | 34 +- 49 files changed, 13100 insertions(+), 2905 deletions(-) create mode 100644 drivers/net/eepro100.c create mode 100644 drivers/scsi/dc390.h create mode 100644 drivers/scsi/scsiiom.c create mode 100644 drivers/scsi/tmscsim.c create mode 100644 drivers/scsi/tmscsim.h diff --git a/CREDITS b/CREDITS index 9949277cbe65..c7a3a35a2ec8 100644 --- a/CREDITS +++ b/CREDITS @@ -413,7 +413,7 @@ S: Newtown 2042 S: Australia N: Ralf Flaxa -E: rfflaxa@immd4.informatik.uni-erlangen.de +E: rf@lst.de D: The Linux Support Team Erlangen D: Creator of LST distribution D: Author of installation tool LISA diff --git a/Documentation/Configure.help b/Documentation/Configure.help index 010e58df54a6..f35ccc47ebb0 100644 --- a/Documentation/Configure.help +++ b/Documentation/Configure.help @@ -472,7 +472,10 @@ CONFIG_SYN_COOKIES the same end. SYN cookies use less space than RST cookies, but have a small probability of introducing an non timed-out failure to connect in the remote TCP. You can use both options - simultatenously. + simultatenously. If you are SYN flooded, the source address + reported by the kernel is likely to have been forged by the attacker. + The source address is reported as an aid in tracing the packets to + their actual source. SYN flood protection CONFIG_RST_COOKIES @@ -486,7 +489,10 @@ CONFIG_RST_COOKIES The SYN_COOKIES option provides an alternative method to accomplish the same end. RST cookies use more space than SYN cookies on your machine, but never increase the probability of a frozen connection - in a remote TCP. You can use both options simultatenously. + in a remote TCP. You can use both options simultatenously. If you + are SYN flooded, the source address reported by the kernel is likely + to have been forged by the attacker. The source address is reported + as an aid in tracing the packets to their actual source. Sun floppy controller support CONFIG_BLK_DEV_SUNFD @@ -1554,24 +1560,41 @@ CONFIG_SCSI_NCR53C8XX of PCI-SCSI controllers. This driver supports parity checking, tagged command queuing, fast scsi II transfer up to 10 MB/s with narrow scsi devices and 20 MB/s with wide scsi devices. - This driver has been tested OK with linux/i386 and is currently - untested under linux/Alpha. If you intend to use this driver under - linux/Alpha, just try it first with read-only or mounted read-only - devices. Memory mapped io is currently not supported under - linux/Alpha. Please read drivers/scsi/README.ncr53c8xx for more - information. - -force normal IO + Support of Ultra SCSI data transfers with NCR53C860 and NCR53C875 + controllers has been recently added to the driver. + Please read drivers/scsi/README.ncr53c8xx for more information. + Linux/i386 and Linux/Alpha are supported by this driver. + +synchronous data transfers frequency +CONFIG_SCSI_NCR53C8XX_SYNC + SCSI-2 specifications allow scsi devices to negotiate a synchronous + transfer period of 25 nano-seconds or more. + The transfer period value is 4 times the agreed transfer period. + So, data can be transferred at a 10 MHz frequency, allowing 10 + MB/second throughput with 8 bits scsi-2 devices and 20 MB/second + with wide16 devices. This frequency can be used safely with + differential devices but may cause problems with singled-ended + devices. + Specify 0 if you want to only use asynchronous data transfers. + Otherwise, specify a value between 5 and 10. Commercial O/Ses + generally use 5 Mhz frequency for synchronous transfers. It is a + reasonable default value. + However, a flawless singled-ended scsi bus supports 10 MHz data + transfers. Regardless the value chosen in the Linux configuration, + the synchronous period can be changed after boot-up through the + /proc/scsi file system. The generic command is: + echo "setsync #target period" >/proc/scsi/ncr53c8xx/0 + Use a 25 ns period for 10 Mhz synchronous data transfers. + If you don't know what to do now, go with the default. + +use normal IO CONFIG_SCSI_NCR53C8XX_IOMAPPED - Under linux/Alpha only normal io is currently supported. - Under linux/i386, this option allows you to force the driver to use - normal IO. Memory mapped IO has less latency than normal IO. - During the initialization phase, the driver first tries to use - memory mapped io. If nothing seems wrong, it will use memory mapped - io. If a flaw is detected, it will use normal io. However, it's - possible that memory mapped does not work properly for you and the - driver has not detected the problem; then you would want to say Y - here. The normal answer therefore is N. + This option allows you to force the driver to use normal IO. + Memory mapped IO has less latency than normal IO and works for most + Intel-based hardware. + Under Linux/Alpha only normal IO is currently supported by the driver + and so, this option has no effect. + The normal answer therefore is N. not allow targets to disconnect CONFIG_SCSI_NCR53C8XX_NO_DISCONNECT @@ -1596,36 +1619,51 @@ CONFIG_SCSI_NCR53C8XX_TAGGED_QUEUE The safe answer therefore is N. The normal answer therefore is Y. -force asynchronous transfer mode -CONFIG_SCSI_NCR53C8XX_FORCE_ASYNCHRONOUS - This option allows you to force asynchronous transfer mode for all - devices at linux startup. You can enable synchronous negotiation - with the "setsync" control command after boot-up, for example: - echo "setsync 2 25" >/proc/scsi/ncr53c8xx/0 - asks the driver to set the period to 25 ns (10MB/sec) for target 2 - of controller 0 (please read drivers/scsi/README.ncr53c8xx for more - information). The safe answer therefore is Y. The normal answer - therefore is N. - -force synchronous negotiation -CONFIG_SCSI_NCR53C8XX_FORCE_SYNC_NEGO - Some scsi-2 devices support synchronous negotiations but do not - report this feature in byte 7 of inquiry data. - Answer Y only if you suspect some device to be so humble. - The normal answer therefore is N. - -disable master parity checking -CONFIG_SCSI_NCR53C8XX_DISABLE_MPARITY_CHECK - Some hardware may have problems with parity during master cycles on - PCI bus. Only seen once. Answer Y if you suspect such problem. The - normal answer therefore is N. - -disable scsi parity checking -CONFIG_SCSI_NCR53C8XX_DISABLE_PARITY_CHECK - Parity on scsi bus is a system option. If one device checks parity, - then all devices on the scsi bus must generate parity. However, the - parity can be ignored by the scsi devices. Answer Y only if you - know what you are doing. The normal answer therefore is N. +maximum number of queued commands +CONFIG_SCSI_NCR53C8XX_MAX_TAGS + This option allows you to specify the maximum number of commands + that can be queued to a device, when tagged command queuing is + possible. The default value is 4. Minimum is 2, maximum is 12. The + normal answer therefore is the default one. + +detect and read serial NVRAM +CONFIG_SCSI_NCR53C8XX_NVRAM_DETECT + Enable support for reading the serial NVRAM data on Symbios and + some Symbios compatible cards, and Tekram DC390W/U/F cards. Useful for + systems with more than one Symbios compatible controller where at least + one has a serial NVRAM, or for a system with a mixture of Symbios and + Tekram cards. Enables setting the boot order of host adaptors + to something other than the default order or "reverse probe" order. + Also enables Symbios and Tekram cards to be distinguished so + CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT may be set in a system with a + mixture of Symbios and Tekram cards so the Symbios cards can make use of + the full range of Symbios features, differential, led pin, without + causing problems for the Tekram card(s). + (added by Richard Waltham: dormouse@farsrobt.demon.co.uk) + Also enables setting host and targets SCSI features as defined in the + user setup for each host using a serial NVRAM (added by the maintainer). + The default answer is N, the normal answer should be Y. + Read drivers/scsi/README.ncr53c8xx for more information. + +assume boards are SYMBIOS compatible +CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT + This option allows you to enable some features depending on GPIO + wiring. These General Purpose Input/Output pins can be used for + vendor specific features or implementation of the standard SYMBIOS + features. Genuine SYMBIOS boards use GPIO0 in output for controller + LED and GPIO3 bit as a flag indicating singled-ended/differential + interface. + If all the boards of your system are genuine SYMBIOS boards or use + BIOS and drivers from SYMBIOS, you would want to enable this option. + The driver behaves correctly on my system with this option enabled. + (SDMS 4.0 + Promise SCSI ULTRA 875 rev 0x3 + ASUS SC200 810A rev + 0x12). This option must be set to N if your system has at least one + 53C8XX based scsi board with a vendor-specific BIOS (example: Tekram + DC-390/U/W/F). If unsure, say N. + However, if all your non Symbios compatible boards have NvRAM, setting + option CONFIG_SCSI_NCR53C8XX_NVRAM_DETECT allows the driver to + distinguish Symbios compatible boards from other ones. + So, you can answer Y if all non Symbios compatible boards have NVRAM. Always IN2000 SCSI support CONFIG_SCSI_IN2000 @@ -1742,6 +1780,13 @@ CONFIG_SCSI_NCR53C406A and removed from the running kernel whenever you want), say M here and read Documentation/modules.txt. +Tekram DC390(T) (AMD PCscsi) SCSI support +CONFIG_SCSI_DC390T + This driver supports the Tekram DC390(T) PCI SCSI Hostadapter with + the Am53C974A chip, and perhaps other cards using the same chip. + This driver does _not_ support the DC390W/U/F adaptor with the + NCR/Symbios chips. + AM53/79C974 PCI SCSI support CONFIG_SCSI_AM53C974 This is support for the AM53/79C974 SCSI host adapters. Please read @@ -2397,6 +2442,12 @@ CONFIG_FMV18X FMV-184 and it is not working, you may need to disable Plug & Play mode of the card. +Intel EtherExpress/Pro 100B support' +CONFIG_EEXPRESS_PRO100B + If you have an Intel EtherExpress Pro 100 10/100Mbps PCI Ethernet + card, answer yes. As of kernel release 2.0.31 this driver was + still experimental. + EtherExpressPro support CONFIG_EEXPRESS_PRO If you have a network (ethernet) card of this type, say Y and read diff --git a/arch/alpha/kernel/traps.c b/arch/alpha/kernel/traps.c index 2c54f580254e..694820c96ede 100644 --- a/arch/alpha/kernel/traps.c +++ b/arch/alpha/kernel/traps.c @@ -420,7 +420,7 @@ asmlinkage long do_entSys(unsigned long a0, unsigned long a1, unsigned long a2, unsigned long a3, unsigned long a4, unsigned long a5, struct pt_regs regs) { - if (regs.r0 != 112) + if (regs.r0 != 112 && regs.r0 < 300) printk("", regs.r0, a0, a1, a2); return -1; } diff --git a/drivers/char/random.c b/drivers/char/random.c index c65e286f49cf..2104168a27dc 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -1337,8 +1337,13 @@ __u32 secure_tcp_sequence_number(__u32 saddr, __u32 daddr, do_gettimeofday(&tv); seq = tmp[1] + tv.tv_usec+tv.tv_sec*1000000; #if 0 - printk("init_seq(%lx, %lx, %d, %d) = %d\n", - saddr, daddr, sport, dport, seq); + /* + ugh...we can only use in_ntoa once per printk, splitting + a single line of info into multiple printk's confuses klogd, + and Linus says in_ntoa sucks anyway :) + */ + printk("init_seq(%d.%d.%d.%d:%d, %d.%d.%d.%d:%d) = %d\n", + NIPQUAD(saddr), sport, NIPQUAD(daddr), dport, seq); #endif return (seq); } @@ -1361,7 +1366,7 @@ __u32 secure_tcp_probe_number(__u32 saddr, __u32 daddr, /* * Pick a random secret the first time we open a TCP - * connection, and expire secretes older than 5 minutes. + * connection, and expire secrets older than 5 minutes. */ if (is_init == 0 || jiffies-secret_timestamp[offset] > 600*HZ) { if (is_init == 0) valid_secret[0] = valid_secret[1] = 0; @@ -1386,14 +1391,14 @@ __u32 secure_tcp_probe_number(__u32 saddr, __u32 daddr, if (!validate) { if (seq == sseq) seq++; #if 0 - printk("init_seq(%lx, %lx, %d, %d, %d) = %d\n", - saddr, daddr, sport, dport, sseq, seq); + printk("init_seq(%d.%d.%d.%d:%d %d.%d.%d.%d:%d, %d) = %d\n", + NIPQUAD(saddr), sport, NIPQUAD(daddr), dport, sseq, seq); #endif return (seq); } else { if (seq == sseq || (seq+1) == sseq) { - printk("validated probe(%lx, %lx, %d, %d, %d)\n", - saddr, daddr, sport, dport, sseq); + printk("validated probe(%d.%d.%d.%d:%d, %d.%d.%d.%d:%d, %d)\n", + NIPQUAD(saddr), sport, NIPQUAD(daddr), dport, sseq); return 1; } if (jiffies-secret_timestamp[(offset+1)%2] <= 1200*HZ) { @@ -1405,15 +1410,15 @@ __u32 secure_tcp_probe_number(__u32 saddr, __u32 daddr, seq = tmp[1]; if (seq == sseq || (seq+1) == sseq) { #ifdef 0 - printk("validated probe(%lx, %lx, %d, %d, %d)\n", - saddr, daddr, sport, dport, sseq); + printk("validated probe(%d.%d.%d.%d:%d, %d.%d.%d.%d:%d, %d)\n", + NIPQUAD(saddr), sport, NIPQUAD(daddr), dport, sseq); #endif return 1; } } #ifdef 0 - printk("failed validation on probe(%lx, %lx, %d, %d, %d)\n", - saddr, daddr, sport, dport, sseq); + printk("failed validation on probe(%d.%d.%d.%d:%d, %d.%d.%d.%d:%d, %d)\n", + NIPQUAD(saddr), sport, NIPQUAD(daddr), dport, sseq); #endif return 0; } diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 2bccbc6a5f6e..7f53c7070492 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -11,7 +11,7 @@ * Kill-line thanks to John T Kohl, who also corrected VMIN = VTIME = 0. * * Modified by Theodore Ts'o, 9/14/92, to dynamically allocate the - * tty_struct and tty_queue structures. Previously there was a array + * tty_struct and tty_queue structures. Previously there was an array * of 256 tty_struct's which was statically allocated, and the * tty_queue structures were allocated at boot time. Both are now * dynamically allocated only when the tty is open. @@ -44,6 +44,9 @@ * * Restrict vt switching via ioctl() * -- grif@cs.ucr.edu, 5-Dec-95 + * + * Rewrote init_dev and release_dev to eliminate races. + * -- Bill Hawes , June 97 */ #include @@ -830,14 +833,27 @@ static int tty_write(struct inode * inode, struct file * file, const char * buf, (unsigned int)count); } +/* Semaphore to protect creating and releasing a tty */ +static struct semaphore tty_sem = MUTEX; +static void down_tty_sem(int index) +{ + down(&tty_sem); +} +static void up_tty_sem(int index) +{ + up(&tty_sem); +} +static void release_mem(struct tty_struct *tty, int idx); + /* - * This is so ripe with races that you should *really* not touch this - * unless you know exactly what you are doing. All the changes have to be - * made atomically, or there may be incorrect pointers all over the place. + * Rewritten to remove races and properly clean up after a failed open. + * The new code protects the open with a semaphore, so it's really + * quite straightforward. The semaphore locking can probably be + * relaxed for the (most common) case of reopening a tty. */ static int init_dev(kdev_t device, struct tty_struct **ret_tty) { - struct tty_struct *tty, **tty_loc, *o_tty, **o_tty_loc; + struct tty_struct *tty, *o_tty; struct termios *tp, **tp_loc, *o_tp, **o_tp_loc; struct termios *ltp, **ltp_loc, *o_ltp, **o_ltp_loc; struct tty_driver *driver; @@ -849,163 +865,221 @@ static int init_dev(kdev_t device, struct tty_struct **ret_tty) return -ENODEV; idx = MINOR(device) - driver->minor_start; - tty = o_tty = NULL; + + /* + * Check whether we need to acquire the tty semaphore to avoid + * race conditions. For now, play it safe. + */ + down_tty_sem(idx); + + /* check whether we're reopening an existing tty */ + tty = driver->table[idx]; + if(tty) goto fast_track; + + /* + * First time open is complex, especially for PTY devices. + * This code guarantees that either everything succeeds and the + * TTY is ready for operation, or else the table slots are vacated + * and the allocated memory released. (Except that the termios + * and locked termios may be retained.) + */ + + o_tty = NULL; tp = o_tp = NULL; ltp = o_ltp = NULL; - o_tty_loc = NULL; - o_tp_loc = o_ltp_loc = NULL; - tty_loc = &driver->table[idx]; - tp_loc = &driver->termios[idx]; - ltp_loc = &driver->termios_locked[idx]; + tty = (struct tty_struct*) get_free_page(GFP_KERNEL); + if(!tty) + goto fail_no_mem; + initialize_tty_struct(tty); + tty->device = device; + tty->driver = *driver; -repeat: - retval = -EIO; - if (driver->type == TTY_DRIVER_TYPE_PTY && - driver->subtype == PTY_TYPE_MASTER && - *tty_loc && (*tty_loc)->count) - goto end_init; - retval = -ENOMEM; - if (!*tty_loc && !tty) { - if (!(tty = (struct tty_struct*) get_free_page(GFP_KERNEL))) - goto end_init; - initialize_tty_struct(tty); - tty->device = device; - tty->driver = *driver; - goto repeat; - } - if (!*tp_loc && !tp) { + tp_loc = &driver->termios[idx]; + if (!*tp_loc) { tp = (struct termios *) kmalloc(sizeof(struct termios), GFP_KERNEL); if (!tp) - goto end_init; + goto free_mem_out; *tp = driver->init_termios; - goto repeat; } - if (!*ltp_loc && !ltp) { + + ltp_loc = &driver->termios_locked[idx]; + if (!*ltp_loc) { ltp = (struct termios *) kmalloc(sizeof(struct termios), GFP_KERNEL); if (!ltp) - goto end_init; + goto free_mem_out; memset(ltp, 0, sizeof(struct termios)); - goto repeat; } - if (driver->type == TTY_DRIVER_TYPE_PTY) { - o_tty_loc = &driver->other->table[idx]; - o_tp_loc = &driver->other->termios[idx]; - o_ltp_loc = &driver->other->termios_locked[idx]; - if (!*o_tty_loc && !o_tty) { - kdev_t o_device; - - o_tty = (struct tty_struct *) - get_free_page(GFP_KERNEL); - if (!o_tty) - goto end_init; - o_device = MKDEV(driver->other->major, - driver->other->minor_start + idx); - initialize_tty_struct(o_tty); - o_tty->device = o_device; - o_tty->driver = *driver->other; - goto repeat; - } - if (!*o_tp_loc && !o_tp) { + if (driver->type == TTY_DRIVER_TYPE_PTY) { + o_tty = (struct tty_struct *) get_free_page(GFP_KERNEL); + if (!o_tty) + goto free_mem_out; + initialize_tty_struct(o_tty); + o_tty->device = (kdev_t) MKDEV(driver->other->major, + driver->other->minor_start + idx); + o_tty->driver = *driver->other; + + o_tp_loc = &driver->other->termios[idx]; + if (!*o_tp_loc) { o_tp = (struct termios *) kmalloc(sizeof(struct termios), GFP_KERNEL); if (!o_tp) - goto end_init; + goto free_mem_out; *o_tp = driver->other->init_termios; - goto repeat; } - if (!*o_ltp_loc && !o_ltp) { + + o_ltp_loc = &driver->other->termios_locked[idx]; + if (!*o_ltp_loc) { o_ltp = (struct termios *) kmalloc(sizeof(struct termios), GFP_KERNEL); if (!o_ltp) - goto end_init; + goto free_mem_out; memset(o_ltp, 0, sizeof(struct termios)); - goto repeat; } - + + /* + * Everything allocated ... set up the o_tty structure. + */ + driver->other->table[idx] = o_tty; + if (!*o_tp_loc) + *o_tp_loc = o_tp; + if (!*o_ltp_loc) + *o_ltp_loc = o_ltp; + o_tty->termios = *o_tp_loc; + o_tty->termios_locked = *o_ltp_loc; + (*driver->other->refcount)++; + if (driver->subtype == PTY_TYPE_MASTER) + o_tty->count++; + + /* Establish the links in both directions */ + tty->link = o_tty; + o_tty->link = tty; } - /* Now we have allocated all the structures: update all the pointers.. */ - if (!*tp_loc) { + + /* + * All structures have been allocated, so now we install them. + * Failures after this point use release_mem to clean up, so + * there's no need to null out the local pointers. + */ + driver->table[idx] = tty; + if (!*tp_loc) *tp_loc = tp; - tp = NULL; - } - if (!*ltp_loc) { + if (!*ltp_loc) *ltp_loc = ltp; - ltp = NULL; + tty->termios = *tp_loc; + tty->termios_locked = *ltp_loc; + (*driver->refcount)++; + tty->count++; + + /* + * Structures all installed ... call the ldisc open routines. + * If we fail here just call release_mem to clean up. No need + * to decrement the use counts, as release_mem doesn't care. + */ + if (tty->ldisc.open) { + retval = (tty->ldisc.open)(tty); + if (retval) + goto release_mem_out; } - if (!*tty_loc) { - tty->termios = *tp_loc; - tty->termios_locked = *ltp_loc; - *tty_loc = tty; - (*driver->refcount)++; - (*tty_loc)->count++; - if (tty->ldisc.open) { - retval = (tty->ldisc.open)(tty); - if (retval < 0) { - (*tty_loc)->count--; - tty = NULL; - goto end_init; - } - } - tty = NULL; - } else { - if ((*tty_loc)->flags & (1 << TTY_CLOSING)) { - printk("Attempt to open closing tty %s.\n", - tty_name(*tty_loc)); - printk("Ack!!!! This should never happen!!\n"); - return -EINVAL; + if (o_tty && o_tty->ldisc.open) { + retval = (o_tty->ldisc.open)(o_tty); + if (retval) { + if (tty->ldisc.close) + (tty->ldisc.close)(tty); + goto release_mem_out; } - (*tty_loc)->count++; } - if (driver->type == TTY_DRIVER_TYPE_PTY) { - if (!*o_tp_loc) { - *o_tp_loc = o_tp; - o_tp = NULL; - } - if (!*o_ltp_loc) { - *o_ltp_loc = o_ltp; - o_ltp = NULL; - } - if (!*o_tty_loc) { - o_tty->termios = *o_tp_loc; - o_tty->termios_locked = *o_ltp_loc; - *o_tty_loc = o_tty; - (*driver->other->refcount)++; - if (o_tty->ldisc.open) { - retval = (o_tty->ldisc.open)(o_tty); - if (retval < 0) { - (*tty_loc)->count--; - o_tty = NULL; - goto end_init; - } - } - o_tty = NULL; - } - (*tty_loc)->link = *o_tty_loc; - (*o_tty_loc)->link = *tty_loc; - if (driver->subtype == PTY_TYPE_MASTER) - (*o_tty_loc)->count++; + goto success; + + /* + * This fast open can be used if the tty is already open. + * No memory is allocated, and the only failures are from + * attempting to open a closing tty or attempting multiple + * opens on a pty master. + */ +fast_track: + retval = -EIO; + if (test_bit(TTY_CLOSING, &tty->flags)) + goto end_init; + + if (driver->type == TTY_DRIVER_TYPE_PTY && + driver->subtype == PTY_TYPE_MASTER) { + /* + * special case for PTY masters: only one open permitted, + * and the slave side open count is incremented as well. + */ + if (tty->count) + goto end_init; + tty->link->count++; } - (*tty_loc)->driver = *driver; - *ret_tty = *tty_loc; + tty->count++; + tty->driver = *driver; /* N.B. why do this every time?? */ + +success: retval = 0; + *ret_tty = tty; + + /* All paths come through here to release the semaphore */ end_init: - if (tty) - free_page((unsigned long) tty); - if (o_tty) - free_page((unsigned long) o_tty); - if (tp) - kfree_s(tp, sizeof(struct termios)); + up_tty_sem(idx); + return retval; + + /* Release locally allocated memory ... nothing placed in slots */ +free_mem_out: if (o_tp) kfree_s(o_tp, sizeof(struct termios)); + if (o_tty) + free_page((unsigned long) o_tty); if (ltp) kfree_s(ltp, sizeof(struct termios)); - if (o_ltp) - kfree_s(o_ltp, sizeof(struct termios)); - return retval; + if (tp) + kfree_s(tp, sizeof(struct termios)); + free_page((unsigned long) tty); + +fail_no_mem: + retval = -ENOMEM; + goto end_init; + + /* call the tty release_mem routine to clean out this slot */ +release_mem_out: + printk("init_dev: ldisc open failed, clearing slot %d\n", idx); + release_mem(tty, idx); + goto end_init; +} + +/* + * Releases memory associated with a tty structure, and clears out the + * driver table slots. + */ +static void release_mem(struct tty_struct *tty, int idx) +{ + struct tty_struct *o_tty; + struct termios *tp; + + if ((o_tty = tty->link) != NULL) { + o_tty->driver.table[idx] = NULL; + if (o_tty->driver.flags & TTY_DRIVER_RESET_TERMIOS) { + tp = o_tty->driver.termios[idx]; + o_tty->driver.termios[idx] = NULL; + kfree_s(tp, sizeof(struct termios)); + } + o_tty->magic = 0; + (*o_tty->driver.refcount)--; + free_page((unsigned long) o_tty); + } + + tty->driver.table[idx] = NULL; + if (tty->driver.flags & TTY_DRIVER_RESET_TERMIOS) { + tp = tty->driver.termios[idx]; + tty->driver.termios[idx] = NULL; + kfree_s(tp, sizeof(struct termios)); + } + tty->magic = 0; + (*tty->driver.refcount)--; + free_page((unsigned long) tty); } /* @@ -1016,8 +1090,7 @@ end_init: static void release_dev(struct file * filp) { struct tty_struct *tty, *o_tty; - struct termios *tp, *o_tp, *ltp, *o_ltp; - struct task_struct **p; + int pty_master, tty_closing, o_tty_closing, do_sleep; int idx; tty = (struct tty_struct *)filp->private_data; @@ -1028,10 +1101,11 @@ static void release_dev(struct file * filp) tty_fasync(filp->f_inode, filp, 0); - tp = tty->termios; - ltp = tty->termios_locked; - idx = MINOR(tty->device) - tty->driver.minor_start; + pty_master = (tty->driver.type == TTY_DRIVER_TYPE_PTY && + tty->driver.subtype == PTY_TYPE_MASTER); + o_tty = tty->link; + #ifdef TTY_PARANOIA_CHECK if (idx < 0 || idx >= tty->driver.num) { printk("release_dev: bad idx when trying to free (%s)\n", @@ -1043,15 +1117,15 @@ static void release_dev(struct file * filp) idx, kdevname(tty->device)); return; } - if (tp != tty->driver.termios[idx]) { - printk("release_dev: driver.termios[%d] not termios for (" - "%s)\n", + if (tty->termios != tty->driver.termios[idx]) { + printk("release_dev: driver.termios[%d] not termios " + "for (%s)\n", idx, kdevname(tty->device)); return; } - if (ltp != tty->driver.termios_locked[idx]) { - printk("release_dev: driver.termios_locked[%d] not termios_locked for (" - "%s)\n", + if (tty->termios_locked != tty->driver.termios_locked[idx]) { + printk("release_dev: driver.termios_locked[%d] not " + "termios_locked for (%s)\n", idx, kdevname(tty->device)); return; } @@ -1062,10 +1136,6 @@ static void release_dev(struct file * filp) tty->count); #endif - o_tty = tty->link; - o_tp = (o_tty) ? o_tty->termios : NULL; - o_ltp = (o_tty) ? o_tty->termios_locked : NULL; - #ifdef TTY_PARANOIA_CHECK if (tty->driver.other) { if (o_tty != tty->driver.other->table[idx]) { @@ -1074,34 +1144,90 @@ static void release_dev(struct file * filp) idx, kdevname(tty->device)); return; } - if (o_tp != tty->driver.other->termios[idx]) { - printk("release_dev: other->termios[%d] not o_termios for (" - "%s)\n", + if (o_tty->termios != tty->driver.other->termios[idx]) { + printk("release_dev: other->termios[%d] not o_termios " + "for (%s)\n", idx, kdevname(tty->device)); return; } - if (o_ltp != tty->driver.other->termios_locked[idx]) { - printk("release_dev: other->termios_locked[%d] not o_termios_locked for (" - "%s)\n", + if (o_tty->termios_locked != + tty->driver.other->termios_locked[idx]) { + printk("release_dev: other->termios_locked[%d] not " + "o_termios_locked for (%s)\n", idx, kdevname(tty->device)); return; } - if (o_tty->link != tty) { printk("release_dev: bad pty pointers\n"); return; } } #endif - + /* + * Sanity check: if tty->count is going to zero, there shouldn't be + * any waiters on tty->read_wait or tty->write_wait. We test the + * wait queues and kick everyone out _before_ actually starting to + * close. This ensures that we won't block while releasing the tty + * structure. + * + * The test for the o_tty closing is necessary, since the master and + * slave sides may close in any order. If the slave side closes out + * first, its count will be one, since the master side holds an open. + * Thus this test wouldn't be triggered at the time the slave closes, + * so we do it now. + * + * Note that it's possible for the tty to be opened again while we're + * flushing out waiters. By recalculating the closing flags before + * each iteration we avoid any problems. + */ + while (1) { + tty_closing = tty->count <= 1; + o_tty_closing = o_tty && + (o_tty->count <= (pty_master ? 1 : 0)); + do_sleep = 0; + + if (tty_closing) { + if (waitqueue_active(&tty->read_wait)) { + wake_up(&tty->read_wait); + do_sleep++; + } + if (waitqueue_active(&tty->write_wait)) { + wake_up(&tty->write_wait); + do_sleep++; + } + } + if (o_tty_closing) { + if (waitqueue_active(&o_tty->read_wait)) { + wake_up(&o_tty->read_wait); + do_sleep++; + } + if (waitqueue_active(&o_tty->write_wait)) { + wake_up(&o_tty->write_wait); + do_sleep++; + } + } + if (!do_sleep) + break; + + printk("release_dev: %s: read/write wait queue active!\n", + tty_name(tty)); + schedule(); + } + + /* + * The closing flags are now consistent with the open counts on + * both sides, and we've completed the last operation that could + * block, so it's safe to proceed with closing. + */ + if (tty->driver.close) tty->driver.close(tty, filp); - if (tty->driver.type == TTY_DRIVER_TYPE_PTY && - tty->driver.subtype == PTY_TYPE_MASTER) { - if (--tty->link->count < 0) { + + if (pty_master) { + if (--o_tty->count < 0) { printk("release_dev: bad pty slave count (%d) for %s\n", - tty->count, tty_name(tty)); - tty->link->count = 0; + o_tty->count, tty_name(o_tty)); + o_tty->count = 0; } } if (--tty->count < 0) { @@ -1109,41 +1235,48 @@ static void release_dev(struct file * filp) tty->count, tty_name(tty)); tty->count = 0; } - if (tty->count) - return; /* - * We're committed; at this point, we must not block! + * Perform some housekeeping before deciding whether to return. + * + * Set the TTY_CLOSING flag if this was the last open. In the + * case of a pty we may have to wait around for the other side + * to close, and TTY_CLOSING makes sure we can't be reopened. */ - if (o_tty) { - if (o_tty->count) - return; - tty->driver.other->table[idx] = NULL; - tty->driver.other->termios[idx] = NULL; - kfree_s(o_tp, sizeof(struct termios)); + if(tty_closing) + set_bit(TTY_CLOSING, &tty->flags); + if(o_tty_closing) + set_bit(TTY_CLOSING, &o_tty->flags); + + /* + * If _either_ side is closing, make sure there aren't any + * processes that still think tty or o_tty is their controlling + * tty. Also, clear redirect if it points to either tty. + */ + if (tty_closing || o_tty_closing) { + struct task_struct *p; + + for_each_task(p) { + if (p->tty == tty || (o_tty && p->tty == o_tty)) + p->tty = NULL; + } + + if (redirect == tty || (o_tty && redirect == o_tty)) + redirect = NULL; } + + /* check whether both sides are closing ... */ + if (!tty_closing || (o_tty && !o_tty_closing)) + return; + filp->private_data = 0; #ifdef TTY_DEBUG_HANGUP printk("freeing tty structure..."); #endif - tty->flags |= (1 << TTY_CLOSING); - - /* - * Make sure there aren't any processes that still think this - * tty is their controlling tty. - */ - for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) { - if (*p == 0) - continue; - if ((*p)->tty == tty) - (*p)->tty = NULL; - if (o_tty && (*p)->tty == o_tty) - (*p)->tty = NULL; - } /* - * Shutdown the current line discipline, and reset it to - * N_TTY. + * Shutdown the current line discipline, and reset it to N_TTY. + * N.B. why reset ldisc when we're releasing the memory?? */ if (tty->ldisc.close) (tty->ldisc.close)(tty); @@ -1155,41 +1288,34 @@ static void release_dev(struct file * filp) o_tty->ldisc = ldiscs[N_TTY]; } - tty->driver.table[idx] = NULL; - if (tty->driver.flags & TTY_DRIVER_RESET_TERMIOS) { - tty->driver.termios[idx] = NULL; - kfree_s(tp, sizeof(struct termios)); - } - if (tty == redirect || o_tty == redirect) - redirect = NULL; /* * Make sure that the tty's task queue isn't activated. If it - * is, take it out of the linked list. + * is, take it out of the linked list. The tqueue isn't used by + * pty's, so skip the test for them. */ - cli(); - if (tty->flip.tqueue.sync) { - struct tq_struct *tq, *prev; - - for (tq=tq_timer, prev=0; tq; prev=tq, tq=tq->next) { - if (tq == &tty->flip.tqueue) { - if (prev) - prev->next = tq->next; - else - tq_timer = tq->next; - break; + if (tty->driver.type != TTY_DRIVER_TYPE_PTY) { + cli(); + if (tty->flip.tqueue.sync) { + struct tq_struct *tq, *prev; + + for (tq=tq_timer, prev=0; tq; prev=tq, tq=tq->next) { + if (tq == &tty->flip.tqueue) { + if (prev) + prev->next = tq->next; + else + tq_timer = tq->next; + break; + } } } + sti(); } - sti(); - tty->magic = 0; - (*tty->driver.refcount)--; - free_page((unsigned long) tty); - filp->private_data = 0; - if (o_tty) { - o_tty->magic = 0; - (*o_tty->driver.refcount)--; - free_page((unsigned long) o_tty); - } + + /* + * The release_mem function takes care of the details of clearing + * the slots and preserving the termios structure. + */ + release_mem(tty, idx); } /* @@ -1274,11 +1400,6 @@ retry_open: return 0; } -/* - * Note that releasing a pty master also releases the child, so - * we have to make the redirection checks after that and on both - * sides of a pty. - */ static void tty_release(struct inode * inode, struct file * filp) { release_dev(filp); diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c index 1991a0205188..bb5aed25d89b 100644 --- a/drivers/char/tty_ioctl.c +++ b/drivers/char/tty_ioctl.c @@ -376,7 +376,6 @@ int n_tty_ioctl(struct tty_struct * tty, struct file * file, { struct tty_struct * real_tty; int retval; - int opt = 0; if (tty->driver.type == TTY_DRIVER_TYPE_PTY && tty->driver.subtype == PTY_TYPE_MASTER) @@ -414,19 +413,19 @@ int n_tty_ioctl(struct tty_struct * tty, struct file * file, sizeof (struct termios)); return 0; case TCSETSF: - opt |= TERMIOS_FLUSH; + return set_termios(real_tty, arg, TERMIOS_FLUSH); case TCSETSW: - opt |= TERMIOS_WAIT; + return set_termios(real_tty, arg, TERMIOS_WAIT); case TCSETS: - return set_termios(real_tty, arg, opt); + return set_termios(real_tty, arg, 0); case TCGETA: return get_termio(real_tty,(struct termio *) arg); case TCSETAF: - opt |= TERMIOS_FLUSH; + return set_termios(real_tty, arg, TERMIOS_FLUSH | TERMIOS_TERMIO); case TCSETAW: - opt |= TERMIOS_WAIT; + return set_termios(real_tty, arg, TERMIOS_WAIT | TERMIOS_TERMIO); case TCSETA: - return set_termios(real_tty, arg, opt|TERMIOS_TERMIO); + return set_termios(real_tty, arg, TERMIOS_TERMIO); case TCXONC: retval = tty_check_change(tty); if (retval) diff --git a/drivers/isdn/isdn_tty.c b/drivers/isdn/isdn_tty.c index a5f31eaf3e29..a629ce27922d 100644 --- a/drivers/isdn/isdn_tty.c +++ b/drivers/isdn/isdn_tty.c @@ -2445,13 +2445,16 @@ isdn_tty_get_msnstr(char *n, char **p) * Get phone-number from modem-commandbuffer */ static void -isdn_tty_getdial(char *p, char *q) +isdn_tty_getdial(char *p, char *q, int max) { int first = 1; - while (strchr("0123456789,#.*WPTS-", *p) && *p) { - if ((*p >= '0' && *p <= '9') || ((*p == 'S') && first)) + max--; + while (strchr("0123456789,#.*WPTS-", *p) && *p && (max > 0)) { + if ((*p >= '0' && *p <= '9') || ((*p == 'S') && first)) { *q++ = *p; + max--; + } p++; first = 0; } @@ -3092,7 +3095,7 @@ isdn_tty_parse_at(modem_info * info) break; case 'D': /* D - Dial */ - isdn_tty_getdial(++p, ds); + isdn_tty_getdial(++p, ds, sizeof(ds)); p += strlen(p); if (!strlen(m->msn)) isdn_tty_modem_result(10, info); diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c index 33b2b9159f61..f95e1f1e1d1c 100644 --- a/drivers/net/3c509.c +++ b/drivers/net/3c509.c @@ -279,8 +279,10 @@ int el3_probe(struct device *dev) memcpy(dev->dev_addr, phys_addr, sizeof(phys_addr)); dev->base_addr = ioaddr; dev->irq = irq; - dev->if_port = if_port; - + if (dev->mem_start) + dev->if_port = dev->mem_start & 3; + else + dev->if_port = if_port; request_region(dev->base_addr, EL3_IO_EXTENT, "3c509"); { @@ -692,8 +694,9 @@ el3_rx(struct device *dev) printk("%s: Couldn't allocate a sk_buff of size %d.\n", dev->name, pkt_len); } - lp->stats.rx_dropped++; outw(RxDiscard, ioaddr + EL3_CMD); + lp->stats.rx_dropped++; + SLOW_DOWN_IO; while (inw(ioaddr + EL3_STATUS) & 0x1000) printk(" Waiting for 3c509 to discard packet, status %x.\n", inw(ioaddr + EL3_STATUS) ); @@ -724,7 +727,7 @@ set_multicast_list(struct device *dev) outw(SetRxFilter | RxStation | RxMulticast | RxBroadcast, ioaddr + EL3_CMD); } else - outw(SetRxFilter | RxStation | RxBroadcast, ioaddr + EL3_CMD); + outw(SetRxFilter | RxStation | RxBroadcast, ioaddr + EL3_CMD); } static int diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index ace8c584141b..1427e2b97cb7 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -40,14 +40,8 @@ static char *version = Setting to > 1512 effectively disables this feature. */ static const rx_copybreak = 200; -#include -#ifdef MODULE #include #include -#else -#define MOD_INC_USE_COUNT -#define MOD_DEC_USE_COUNT -#endif #include #include diff --git a/drivers/net/Config.in b/drivers/net/Config.in index 97981b12d1e4..87445f6bbe2c 100644 --- a/drivers/net/Config.in +++ b/drivers/net/Config.in @@ -50,7 +50,7 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then tristate '3c507 support' CONFIG_EL16 fi tristate '3c509/3c579 support' CONFIG_EL3 - tristate '3c590 series (592/595/597) "Vortex" support' CONFIG_VORTEX + tristate '3c590/3c900 series (592/595/597/900/905) "Vortex/Boomerang" support' CONFIG_VORTEX fi bool 'AMD LANCE and PCnet (AT1500 and NE2100) support' CONFIG_LANCE if [ "$CONFIG_LANCE" = "y" ]; then @@ -98,6 +98,7 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then tristate 'Ansel Communications EISA 3200 support (EXPERIMENTAL)' CONFIG_AC3200 fi tristate 'Apricot Xen-II on board ethernet' CONFIG_APRICOT + tristate 'Intel EtherExpress/Pro 100B support' CONFIG_EEXPRESS_PRO100B tristate 'DE425, DE434, DE435, DE450, DE500 support' CONFIG_DE4X5 tristate 'DECchip Tulip (dc21x4x) PCI support' CONFIG_DEC_ELCP tristate 'Digi Intl. RightSwitch SE-X support' CONFIG_DGRS diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 9939b4a43ec8..d1d4ca903f8c 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -320,6 +320,15 @@ else endif endif +ifeq ($(CONFIG_EEXPRESS_PRO100B),y) +L_OBJS += eepro100.o +else + ifeq ($(CONFIG_EEXPRESS_PRO100B),m) + M_OBJS += eepro100.o + endif +endif + + ifeq ($(CONFIG_WAVELAN),y) L_OBJS += wavelan.o else diff --git a/drivers/net/Space.c b/drivers/net/Space.c index 7697ed63842d..8ee8257e6f32 100644 --- a/drivers/net/Space.c +++ b/drivers/net/Space.c @@ -50,6 +50,7 @@ extern int hp_plus_probe(struct device *dev); extern int znet_probe(struct device *); extern int express_probe(struct device *); extern int eepro_probe(struct device *); +extern int eepro100_probe(struct device *); extern int el3_probe(struct device *); extern int at1500_probe(struct device *); extern int at1700_probe(struct device *); @@ -163,6 +164,9 @@ ethif_probe(struct device *dev) #ifdef CONFIG_EEXPRESS_PRO /* Intel EtherExpress Pro/10 */ && eepro_probe(dev) #endif +#ifdef CONFIG_EEXPRESS_PRO100B /* Intel EtherExpress Pro100B */ + && eepro100_probe(dev) +#endif #ifdef CONFIG_DEPCA /* DEC DEPCA */ && depca_probe(dev) #endif diff --git a/drivers/net/dgrs.c b/drivers/net/dgrs.c index 9f0d399c6e37..19896ff95fc7 100644 --- a/drivers/net/dgrs.c +++ b/drivers/net/dgrs.c @@ -97,7 +97,6 @@ static char *version = "$Id: dgrs.c,v 1.12 1996/12/21 13:43:58 rick Exp $"; #include #include -#include /* for CONFIG_PCI */ /* * API changed at linux version 2.1.0 diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c new file mode 100644 index 000000000000..ffa0e50fd7ef --- /dev/null +++ b/drivers/net/eepro100.c @@ -0,0 +1,1731 @@ +/* drivers/net/eepro100.c: An Intel i82557 ethernet driver for linux. */ +/* + NOTICE: this version tested with kernels 1.3.72 and later only! + Written 1996 by Donald Becker. + + This software may be used and distributed according to the terms + of the GNU Public License, incorporated herein by reference. + + This driver is for the Intel EtherExpress Pro 100B boards. + It should work with other i82557 boards (if any others exist). + To use a built-in driver, install as drivers/net/eepro100.c. + To use as a module, use the compile-command at the end of the file. + + The author may be reached as becker@CESDIS.usra.edu, or C/O + Center of Excellence in Space Data and Information Sciences + Code 930.5, NASA Goddard Space Flight Center, Greenbelt MD 20771 + For updates see + +*/ + +static const char *version = +"eepro100.c:v0.32 4/8/97 Donald Becker linux-eepro100@cesdis.gsfc.nasa.gov\n"; + +/* A few user-configurable values that apply to all boards. + First set are undocumented and spelled per Intel recommendations. */ + +static int congenb = 0; /* Enable congestion control in the DP83840. */ +static int txfifo = 8; /* Tx FIFO threshold in 4 byte units, 0-15 */ +static int rxfifo = 8; /* Rx FIFO threshold, default 32 bytes. */ +static int txdmacount = 0; /* Tx DMA burst length, 0-127, default 0. */ +static int rxdmacount = 0; /* Rx DMA length, 0 means no preemption. */ + +/* If defined use the copy-only-tiny-buffer scheme for higher performance. + The value sets the copy breakpoint. Lower uses more memory, but is + faster. */ +#define SKBUFF_RX_COPYBREAK 256 + +#include +#include +#ifdef MODULE +#include +#else +#define MOD_INC_USE_COUNT +#define MOD_DEC_USE_COUNT +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* Processor type for cache alignment. */ +#include +#include +#include + +#include +#include +#include + +/* A nominally proper method to handle version dependencies is to use + LINUX_VERSION_CODE in version.h, but that triggers recompiles w/'make'. */ +#define VERSION(v,p,s) (((v)<<16)+(p<<8)+s) +#ifdef MODULE +#if (LINUX_VERSION_CODE < VERSION(1,3,0)) +#define KERNEL_1_2 +#else /* 1.3.0 */ +#if (LINUX_VERSION_CODE >= VERSION(1,3,44)) +#define NEW_MULTICAST +#define LINUX_1_4 +#else +#warning "This driver is tested for 1.3.44 and later development kernels only." +#endif /* 1.3.44 */ +#endif +#else + +#if (LINUX_VERSION_CODE >= 0x10344) +#define NEW_MULTICAST +#include +#endif + +#ifdef HAVE_HEADER_CACHE +#define LINUX_1_4 +#define NEW_MULTICAST +#else +#ifdef ETH_P_DDCMP /* Warning: Bogus! This means IS_LINUX_1_3. */ +#define KERNEL_1_3 +#else +#define KERNEL_1_2 +#endif +#endif + +#endif +/* This should be in a header file. */ +#if (LINUX_VERSION_CODE < VERSION(1,3,44)) +struct device *init_etherdev(struct device *dev, int sizeof_priv, + unsigned long *mem_startp); +#endif +#if LINUX_VERSION_CODE < 0x10300 +#define RUN_AT(x) (x) /* What to put in timer->expires. */ +#define DEV_ALLOC_SKB(len) alloc_skb(len, GFP_ATOMIC) +#define virt_to_bus(addr) ((unsigned long)addr) +#define bus_to_virt(addr) ((void*)addr) +#else /* 1.3.0 and later */ +#define RUN_AT(x) (jiffies + (x)) +#define DEV_ALLOC_SKB(len) dev_alloc_skb(len + 2) +#endif + +/* The total I/O port extent of the board. Nominally 0x18, but rounded up + for PCI allocation. */ +#define SPEEDO3_TOTAL_SIZE 0x20 + +#ifdef HAVE_DEVLIST +struct netdev_entry eepro100_drv = +{"EEPro-100", eepro100_init, SPEEDO3_TOTAL_SIZE, NULL}; +#endif + +#ifdef SPEEDO3_DEBUG +int speedo_debug = SPEEDO3_DEBUG; +#else +int speedo_debug = 3; +#endif + +/* + Theory of Operation + +I. Board Compatibility + +This device driver is designed for the Intel i82557 "Speedo3" chip, Intel's +single-chip fast ethernet controller for PCI, as used on the Intel +EtherExpress Pro 100 adapter. + +II. Board-specific settings + +PCI bus devices are configured by the system at boot time, so no jumpers +need to be set on the board. The system BIOS should be set to assign the +PCI INTA signal to an otherwise unused system IRQ line. While it's +possible to share PCI interrupt lines, it negatively impacts performance and +only recent kernels support it. + +III. Driver operation + +IIIA. General +The Speedo3 is very similar to other Intel network chips, that is to say +"apparently designed on a different planet". This chips retains the complex +Rx and Tx descriptors and multiple buffers pointers as previous chips, but +also has simplified Tx and Rx buffer modes. This driver uses the "flexible" +Tx mode, but in a simplified lower-overhead manner: it associates only a +single buffer descriptor with each frame descriptor. + +Despite the extra space overhead in each recieve skbuff, the driver must use +the simplified Rx buffer mode to assure that only a single data buffer is +associated with each RxFD. The driver implements this by reserving space +for the Rx descriptor at the head of each Rx skbuff + +The Speedo-3 has receive and command unit base addresses that are added to +almost all descriptor pointers. The driver sets these to zero, so that all +pointer fields are absolute addresses. + +The System Control Block (SCB) of some previous Intel chips exists on the +chip in both PCI I/O and memory space. This driver uses the I/O space +registers, but might switch to memory mapped mode to better support non-x86 +processors. + +IIIB. Transmit structure + +The driver must use the complex Tx command+descriptor mode in order to +have a indirect pointer to the skbuff data section. Each Tx command block +(TxCB) is associated with a single, immediately appended Tx buffer descriptor +(TxBD). A fixed ring of these TxCB+TxBD pairs are kept as part of the +speedo_private data structure for each adapter instance. + +This ring structure is used for all normal transmit packets, but the +transmit packet descriptors aren't long enough for most non-Tx commands such +as CmdConfigure. This is complicated by the possibility that the chip has +already loaded the link address in the previous descriptor. So for these +commands we convert the next free descriptor on the ring to a NoOp, and point +that descriptor's link to the complex command. + +An additional complexity of these non-transmit commands are that they may be +added asynchronous to the normal transmit queue, so we disable interrupts +whenever the Tx descriptor ring is manipulated. + +A notable aspect of the these special configure commands is that they do +work with the normal Tx ring entry scavenge method. The Tx ring scavenge +is done at interrupt time using the 'dirty_tx' index, and checking for the +command-complete bit. While the setup frames may have the NoOp command on the +Tx ring marked as complete, but not have completed the setup command, this +is not a problem. The tx_ring entry can be still safely reused, as the +tx_skbuff[] entry is always empty for config_cmd and mc_setup frames. + +Commands may have bits set e.g. CmdSuspend in the command word to either +suspend or stop the transmit/command unit. This driver always flags the last +command with CmdSuspend, erases the CmdSuspend in the previous command, and +then issues a CU_RESUME. +Note: Watch out for the potential race condition here: imagine + erasing the previous suspend + the chip processes the previous command + the chip processes the final command, and suspends + doing the CU_RESUME + the chip processes the next-yet-valid post-final-command. +So blindly sending a CU_RESUME is only safe if we do it immediately after +after erasing the previous CmdSuspend, without the possibility of an +intervening delay. Thus the resume command is always within the +interrupts-disabled region. This is a timing dependence, but handling this +condition in a timing-independent way would considerably complicate the code. + +Note: In previous generation Intel chips, restarting the command unit was a +notoriously slow process. This is presumably no longer true. + +IIIC. Receive structure + +Because of the bus-master support on the Speedo3 this driver uses the new +SKBUFF_RX_COPYBREAK scheme, rather than a fixed intermediate receive buffer. +This scheme allocates full-sized skbuffs as receive buffers. The value +SKBUFF_RX_COPYBREAK is used as the copying breakpoint: it is chosen to +trade-off the memory wasted by passing the full-sized skbuff to the queue +layer for all frames vs. the copying cost of copying a frame to a +correctly-sized skbuff. + +For small frames the copying cost is negligible (esp. considering that we +are pre-loading the cache with immediately useful header information), so we +allocate a new, minimally-sized skbuff. For large frames the copying cost +is non-trivial, and the larger copy might flush the cache of useful data, so +we pass up the skbuff the packet was received into. + +IIID. Synchronization +The driver runs as two independent, single-threaded flows of control. One +is the send-packet routine, which enforces single-threaded use by the +dev->tbusy flag. The other thread is the interrupt handler, which is single +threaded by the hardware and other software. + +The send packet thread has partial control over the Tx ring and 'dev->tbusy' +flag. It sets the tbusy flag whenever it's queuing a Tx packet. If the next +queue slot is empty, it clears the tbusy flag when finished otherwise it sets +the 'sp->tx_full' flag. + +The interrupt handler has exclusive control over the Rx ring and records stats +from the Tx ring. (The Tx-done interrupt can't be selectively turned off, so +we can't avoid the interrupt overhead by having the Tx routine reap the Tx +stats.) After reaping the stats, it marks the queue entry as empty by setting +the 'base' to zero. Iff the 'sp->tx_full' flag is set, it clears both the +tx_full and tbusy flags. + +IV. Notes + +Thanks to Steve Williams of Intel for arranging the non-disclosure agreement +that stated that I could disclose the information. But I still resent +having to sign an Intel NDA when I'm helping Intel sell their own product! + +*/ + +/* A few values that may be tweaked. */ +/* The ring sizes should be a power of two for efficiency. */ +#define TX_RING_SIZE 16 /* Effectively 2 entries fewer. */ +#define RX_RING_SIZE 16 +/* Size of an pre-allocated Rx buffer: + slack.*/ +#define PKT_BUF_SZ 1536 + +/* Time in jiffies before concluding the transmitter is hung. */ +#define TX_TIMEOUT ((400*HZ)/1000) + +/* Maximum events (Rx packets, etc.) to handle at each interrupt. */ +#define INTR_WORK 16 + +/* How to wait for the command unit to accept a command. + Typically this takes 0 ticks. */ +static inline void wait_for_cmd_done(int cmd_ioaddr) +{ + short wait = 100; + do ; + while(inb(cmd_ioaddr) && --wait >= 0); +} + +/* Operational parameter that usually are not changed. */ + +#ifndef PCI_VENDOR_ID_INTEL /* Now defined in linux/pci.h */ +#define PCI_VENDOR_ID_INTEL 0x8086 /* Hmmmm, how did they pick that? */ +#endif +#ifndef PCI_DEVICE_ID_INTEL_82557 +#define PCI_DEVICE_ID_INTEL_82557 0x1229 +#endif + +/* The rest of these values should never change. */ + +/* Offsets to the various registers. + All accesses need not be longword aligned. */ +enum speedo_offsets { + SCBStatus = 0, SCBCmd = 2, /* Rx/Command Unit command and status. */ + SCBPointer = 4, /* General purpose pointer. */ + SCBPort = 8, /* Misc. commands and operands. */ + SCBflash = 12, SCBeeprom = 14, /* EEPROM and flash memory control. */ + SCBCtrlMDI = 16, /* MDI interface control. */ + SCBEarlyRx = 20, /* Early receive byte count. */ +}; +/* Commands that can be put in a command list entry. */ +enum commands { + CmdNOp = 0, CmdIASetup = 1, CmdConfigure = 2, CmdMulticastList = 3, + CmdTx = 4, CmdTDR = 5, CmdDump = 6, CmdDiagnose = 7, + CmdSuspend = 0x4000, /* Suspend after completion. */ + CmdIntr = 0x2000, /* Interrupt after completion. */ + CmdTxFlex = 0x0008, /* Use "Flexible mode" for CmdTx command. */ +}; + +/* The SCB accepts the following controls for the Tx and Rx units: */ +#define CU_START 0x0010 +#define CU_RESUME 0x0020 +#define CU_STATSADDR 0x0040 +#define CU_SHOWSTATS 0x0050 /* Dump statistics counters. */ +#define CU_CMD_BASE 0x0060 /* Base address to add to add CU commands. */ +#define CU_DUMPSTATS 0x0070 /* Dump then reset stats counters. */ + +#define RX_START 0x0001 +#define RX_RESUME 0x0002 +#define RX_ABORT 0x0004 +#define RX_ADDR_LOAD 0x0006 +#define RX_RESUMENR 0x0007 +#define INT_MASK 0x0100 +#define DRVR_INT 0x0200 /* Driver generated interrupt. */ + +/* The Speedo3 Rx and Tx frame/buffer descriptors. */ +struct descriptor { /* A generic descriptor. */ + s16 status; /* Offset 0. */ + s16 command; /* Offset 2. */ + u32 link; /* struct descriptor * */ + unsigned char params[0]; +}; + +/* The Speedo3 Rx and Tx buffer descriptors. */ +struct RxFD { /* Receive frame descriptor. */ + s32 status; + u32 link; /* struct RxFD * */ + u32 rx_buf_addr; /* void * */ + u16 count; + u16 size; +}; + +/* Elements of the RxFD.status word. */ +#define RX_COMPLETE 0x8000 + +struct TxFD { /* Transmit frame descriptor set. */ + s32 status; + u32 link; /* void * */ + u32 tx_desc_addr; /* Always points to the tx_buf_addr element. */ + s32 count; /* # of TBD (=1), Tx start thresh., etc. */ + /* This constitutes a single "TBD" entry -- we only use one. */ + u32 tx_buf_addr; /* void *, frame to be transmitted. */ + s32 tx_buf_size; /* Length of Tx frame. */ +}; + +/* Elements of the dump_statistics block. This block must be lword aligned. */ +struct speedo_stats { + u32 tx_good_frames; + u32 tx_coll16_errs; + u32 tx_late_colls; + u32 tx_underruns; + u32 tx_lost_carrier; + u32 tx_deferred; + u32 tx_one_colls; + u32 tx_multi_colls; + u32 tx_total_colls; + u32 rx_good_frames; + u32 rx_crc_errs; + u32 rx_align_errs; + u32 rx_resource_errs; + u32 rx_overrun_errs; + u32 rx_colls_errs; + u32 rx_runt_errs; + u32 done_marker; +}; + +struct speedo_private { + char devname[8]; /* Used only for kernel debugging. */ + const char *product_name; + struct device *next_module; + struct TxFD tx_ring[TX_RING_SIZE]; /* Commands (usually CmdTxPacket). */ + /* The saved address of a sent-in-place packet/buffer, for skfree(). */ + struct sk_buff* tx_skbuff[TX_RING_SIZE]; + struct descriptor *last_cmd; /* Last command sent. */ + /* Rx descriptor ring & addresses of receive-in-place skbuffs. */ + struct RxFD *rx_ringp[RX_RING_SIZE]; + struct sk_buff* rx_skbuff[RX_RING_SIZE]; +#if (LINUX_VERSION_CODE < 0x10300) /* Kernel v1.2.*. */ + struct RxFD saved_skhead[RX_RING_SIZE]; /* Saved skbuff header chunk. */ +#endif + struct RxFD *last_rxf; /* Last command sent. */ + struct enet_statistics stats; + struct speedo_stats lstats; + struct timer_list timer; /* Media selection timer. */ + long last_rx_time; /* Last Rx, in jiffies, to handle Rx hang. */ + unsigned int cur_rx, cur_tx; /* The next free ring entry */ + unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */ + struct descriptor config_cmd; /* A configure command, with header... */ + u8 config_cmd_data[22]; /* .. and setup parameters. */ + int mc_setup_frm_len; /* The length of an allocated.. */ + struct descriptor *mc_setup_frm; /* ..multicast setup frame. */ + char rx_mode; /* Current PROMISC/ALLMULTI setting. */ + unsigned int tx_full:1; /* The Tx queue is full. */ + unsigned int full_duplex:1; /* Full-duplex operation requested. */ + unsigned int default_port:1; /* Last dev->if_port value. */ + unsigned int rx_bug:1; /* Work around receiver hang errata. */ + unsigned int rx_bug10:1; /* Receiver might hang at 10mbps. */ + unsigned int rx_bug100:1; /* Receiver might hang at 100mbps. */ + unsigned short phy[2]; /* PHY media interfaces available. */ +}; + +/* The parameters for a CmdConfigure operation. + There are so many options that it would be difficult to document each bit. + We mostly use the default or recommended settings. */ +const char basic_config_cmd[22] = { + 22, 0x08, 0, 0, 0, 0x80, 0x32, 0x03, 1, /* 1=Use MII 0=Use AUI */ + 0, 0x2E, 0, 0x60, 0, + 0xf2, 0x48, 0, 0x40, 0xf2, 0x80, /* 0x40=Force full-duplex */ + 0x3f, 0x05, }; + +/* PHY media interface chips. */ +static const char *phys[] = { + "None", "i82553-A/B", "i82553-C", "i82503", + "DP83840", "80c240", "80c24", "unknown-7", + "unknown-8", "unknown-9", "DP83840A", "unknown-11", + "unknown-12", "unknown-13", "unknown-14", "unknown-15", }; +enum phy_chips { NonSuchPhy=0, I82553AB, I82553C, I82503, DP83840, S80C240, + S80C24, PhyUndefined, DP83840A=10, }; +static const char is_mii[] = { 0, 1, 1, 0, 1, 1, 0, 1 }; + +static void speedo_found1(struct device *dev, int ioaddr, int irq, int options); + +static int read_eeprom(int ioaddr, int location); +static int mdio_read(int ioaddr, int phy_id, int location); +static int mdio_write(int ioaddr, int phy_id, int location, int value); +static int speedo_open(struct device *dev); +static void speedo_timer(unsigned long data); +static void speedo_init_rx_ring(struct device *dev); +static int speedo_start_xmit(struct sk_buff *skb, struct device *dev); +static int speedo_rx(struct device *dev); +#ifdef SA_SHIRQ +static void speedo_interrupt(int irq, void *dev_instance, struct pt_regs *regs); +#else +static void speedo_interrupt(int irq, struct pt_regs *regs); +#endif +static int speedo_close(struct device *dev); +static struct enet_statistics *speedo_get_stats(struct device *dev); +static void set_rx_mode(struct device *dev); + + + +#ifdef MODULE +/* The parameters that may be passed in... */ +/* 'options' is used to pass a transceiver override or full-duplex flag + e.g. "options=16" for FD, "options=32" for 100mbps-only. */ +static int options[] = {-1, -1, -1, -1, -1, -1, -1, -1}; +static int debug = -1; /* The debug level */ + +/* A list of all installed Speedo devices, for removing the driver module. */ +static struct device *root_speedo_dev = NULL; +#endif + +int eepro100_init(struct device *dev) +{ + int cards_found = 0; + + if (pcibios_present()) { + int pci_index; + for (pci_index = 0; pci_index < 8; pci_index++) { + unsigned char pci_bus, pci_device_fn, pci_irq_line, pci_latency; +#if (LINUX_VERSION_CODE >= VERSION(1,3,44)) + int pci_ioaddr; +#else + long pci_ioaddr; +#endif + unsigned short pci_command; + + if (pcibios_find_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_82557, + pci_index, &pci_bus, + &pci_device_fn)) + break; + pcibios_read_config_byte(pci_bus, pci_device_fn, + PCI_INTERRUPT_LINE, &pci_irq_line); + /* Note: BASE_ADDRESS_0 is for memory-mapping the registers. */ + pcibios_read_config_dword(pci_bus, pci_device_fn, + PCI_BASE_ADDRESS_1, &pci_ioaddr); + /* Remove I/O space marker in bit 0. */ + pci_ioaddr &= ~3; + if (speedo_debug > 2) + printk("Found Intel i82557 PCI Speedo at I/O %#x, IRQ %d.\n", + (int)pci_ioaddr, pci_irq_line); + + /* Get and check the bus-master and latency values. */ + pcibios_read_config_word(pci_bus, pci_device_fn, + PCI_COMMAND, &pci_command); + if ( ! (pci_command & PCI_COMMAND_MASTER)) { + printk(" PCI Master Bit has not been set! Setting...\n"); + pci_command |= PCI_COMMAND_MASTER; + pcibios_write_config_word(pci_bus, pci_device_fn, + PCI_COMMAND, pci_command); + } + pcibios_read_config_byte(pci_bus, pci_device_fn, + PCI_LATENCY_TIMER, &pci_latency); + if (pci_latency < 10) { + printk(" PCI latency timer (CFLT) is unreasonably low at %d." + " Setting to 255 clocks.\n", pci_latency); + pcibios_write_config_byte(pci_bus, pci_device_fn, + PCI_LATENCY_TIMER, 255); + } else if (speedo_debug > 1) + printk(" PCI latency timer (CFLT) is %#x.\n", pci_latency); + +#ifdef MODULE + speedo_found1(dev, pci_ioaddr, pci_irq_line, options[cards_found]); +#else + speedo_found1(dev, pci_ioaddr, pci_irq_line, + dev ? dev->mem_start : 0); +#endif + cards_found++; + } + } + + return cards_found; +} + +static void speedo_found1(struct device *dev, int ioaddr, int irq, int options) +{ + static int did_version = 0; /* Already printed version info. */ + struct speedo_private *sp; + int i; + u16 eeprom[0x40]; + + if (speedo_debug > 0 && did_version++ == 0) + printk(version); + +#if (LINUX_VERSION_CODE >= VERSION(1,3,44)) + dev = init_etherdev(dev, sizeof(struct speedo_private)); +#else + dev = init_etherdev(dev, sizeof(struct speedo_private), 0); +#endif + + /* Read the station address EEPROM before doing the reset. + Perhaps this should even be done before accepting the device, + then we wouldn't have a device name with which to report the error. */ + { + u16 sum = 0; + int j; + for (j = 0, i = 0; i < 0x40; i++) { + unsigned short value = read_eeprom(ioaddr, i); + eeprom[i] = value; + sum += value; + if (i < 3) { + dev->dev_addr[j++] = value; + dev->dev_addr[j++] = value >> 8; + } + } + if (sum != 0xBABA) + printk(KERN_WARNING "%s: Invalid EEPROM checksum %#4.4x, " + "check settings before activating this device!\n", + dev->name, sum); + /* Don't unregister_netdev(dev); as the EEPro may actually be + usable, especially if the MAC address is set later. */ + } + + /* Reset the chip: stop Tx and Rx processes and clear counters. + This takes less than 10usec and will easily finish before the next + action. */ + outl(0, ioaddr + SCBPort); + + printk(KERN_INFO "%s: Intel EtherExpress Pro 10/100 at %#3x, ", + dev->name, ioaddr); + for (i = 0; i < 5; i++) + printk("%2.2X:", dev->dev_addr[i]); + printk("%2.2X, IRQ %d.\n", dev->dev_addr[i], irq); + +#ifndef kernel_bloat + /* OK, this is pure kernel bloat. I don't like it when other drivers + waste non-pageable kernel space to emit similar messages, but I need + them for bug reports. */ + { + const char *connectors[] = {" RJ45", " BNC", " AUI", " MII"}; + /* The self-test results must be paragraph aligned. */ + int str[6], *volatile self_test_results; + int boguscnt = 16000; /* Timeout for set-test. */ + if (eeprom[3] & 0x03) + printk(KERN_INFO " Receiver lock-up bug exists -- enabling" + " work-around.\n"); + printk(KERN_INFO " Board assembly %4.4x%2.2x-%3.3d, Physical" + " connectors present:", + eeprom[8], eeprom[9]>>8, eeprom[9] & 0xff); + for (i = 0; i < 4; i++) + if (eeprom[5] & (1<>8)&15], eeprom[6] & 0x1f); + if (eeprom[7] & 0x0700) + printk(KERN_INFO " Secondary interface chip %s.\n", + phys[(eeprom[7]>>8)&7]); +#if defined(notdef) + /* ToDo: Read and set PHY registers through MDIO port. */ + for (i = 0; i < 2; i++) + printk(" MDIO register %d is %4.4x.\n", + i, mdio_read(ioaddr, eeprom[6] & 0x1f, i)); + for (i = 5; i < 7; i++) + printk(" MDIO register %d is %4.4x.\n", + i, mdio_read(ioaddr, eeprom[6] & 0x1f, i)); + printk(" MDIO register %d is %4.4x.\n", + 25, mdio_read(ioaddr, eeprom[6] & 0x1f, 25)); +#endif + if (((eeprom[6]>>8) & 0x3f) == DP83840 + || ((eeprom[6]>>8) & 0x3f) == DP83840A) { + int mdi_reg23 = mdio_read(ioaddr, eeprom[6] & 0x1f, 23) | 0x0422; + if (congenb) + mdi_reg23 |= 0x0100; + printk(" DP83840 specific setup, setting register 23 to %4.4x.\n", + mdi_reg23); + mdio_write(ioaddr, eeprom[6] & 0x1f, 23, mdi_reg23); + } + if ((options >= 0) && (options & 0x60)) { + printk(KERN_INFO " Forcing %dMbs %s-duplex operation.\n", + (options & 0x20 ? 100 : 10), + (options & 0x10 ? "full" : "half")); + mdio_write(ioaddr, eeprom[6] & 0x1f, 0, + ((options & 0x20) ? 0x2000 : 0) | /* 100mbps? */ + ((options & 0x10) ? 0x0100 : 0)); /* Full duplex? */ + } + + /* Perform a system self-test. */ + self_test_results = (int*) ((((int) str) + 15) & ~0xf); + self_test_results[0] = 0; + self_test_results[1] = -1; + outl(virt_to_bus(self_test_results) | 1, ioaddr + SCBPort); + do { +#ifdef _LINUX_DELAY_H + udelay(10); +#else + SLOW_DOWN_IO; +#endif + } while (self_test_results[1] == -1 && --boguscnt >= 0); + + if (boguscnt < 0) { /* Test optimized out. */ + printk(KERN_ERR "Self test failed, status %8.8x:\n" + KERN_ERR " Failure to initialize the i82557.\n" + KERN_ERR " Verify that the card is a bus-master" + " capable slot.\n", + self_test_results[1]); + } else + printk(KERN_INFO " General self-test: %s.\n" + KERN_INFO " Serial sub-system self-test: %s.\n" + KERN_INFO " Internal registers self-test: %s.\n" + KERN_INFO " ROM checksum self-test: %s (%#8.8x).\n", + self_test_results[1] & 0x1000 ? "failed" : "passed", + self_test_results[1] & 0x0020 ? "failed" : "passed", + self_test_results[1] & 0x0008 ? "failed" : "passed", + self_test_results[1] & 0x0004 ? "failed" : "passed", + self_test_results[0]); + } +#endif /* kernel_bloat */ + + /* We do a request_region() only to register /proc/ioports info. */ + request_region(ioaddr, SPEEDO3_TOTAL_SIZE, "Intel Speedo3 Ethernet"); + + dev->base_addr = ioaddr; + dev->irq = irq; + + if (dev->priv == NULL) + dev->priv = kmalloc(sizeof(*sp), GFP_KERNEL); + sp = dev->priv; + memset(sp, 0, sizeof(*sp)); +#ifdef MODULE + sp->next_module = root_speedo_dev; + root_speedo_dev = dev; +#endif + + sp->full_duplex = options >= 0 && (options & 0x10) ? 1 : 0; + sp->default_port = options >= 0 ? (options & 0x0f) : 0; + + sp->phy[0] = eeprom[6]; + sp->phy[1] = eeprom[7]; + sp->rx_bug = (eeprom[3] & 0x03) == 3 ? 0 : 1; + + printk(KERN_INFO " Operating in %s duplex mode.\n", + sp->full_duplex ? "full" : "half"); + if (sp->rx_bug) + printk(KERN_INFO " Reciever lock-up workaround activated.\n"); + + /* The Speedo-specific entries in the device structure. */ + dev->open = &speedo_open; + dev->hard_start_xmit = &speedo_start_xmit; + dev->stop = &speedo_close; + dev->get_stats = &speedo_get_stats; +#ifdef NEW_MULTICAST + dev->set_multicast_list = &set_rx_mode; +#endif + + return; +} + +/* Serial EEPROM section. + A "bit" grungy, but we work our way through bit-by-bit :->. */ +/* EEPROM_Ctrl bits. */ +#define EE_SHIFT_CLK 0x01 /* EEPROM shift clock. */ +#define EE_CS 0x02 /* EEPROM chip select. */ +#define EE_DATA_WRITE 0x04 /* EEPROM chip data in. */ +#define EE_WRITE_0 0x01 +#define EE_WRITE_1 0x05 +#define EE_DATA_READ 0x08 /* EEPROM chip data out. */ +#define EE_ENB (0x4800 | EE_CS) + +/* Delay between EEPROM clock transitions. + This is a "nasty" timing loop, but PC compatible machines are defined + to delay an ISA compatible period for the SLOW_DOWN_IO macro. */ +#define eeprom_delay(nanosec) do { int _i = 3; while (--_i > 0) { __SLOW_DOWN_IO; }} while (0) + +/* The EEPROM commands include the alway-set leading bit. */ +#define EE_WRITE_CMD (5 << 6) +#define EE_READ_CMD (6 << 6) +#define EE_ERASE_CMD (7 << 6) + +static int read_eeprom(int ioaddr, int location) +{ + int i; + unsigned short retval = 0; + int ee_addr = ioaddr + SCBeeprom; + int read_cmd = location | EE_READ_CMD; + + outw(EE_ENB & ~EE_CS, ee_addr); + outw(EE_ENB, ee_addr); + + /* Shift the read command bits out. */ + for (i = 10; i >= 0; i--) { + short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0; + outw(EE_ENB | dataval, ee_addr); + eeprom_delay(100); + outw(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr); + eeprom_delay(150); + outw(EE_ENB | dataval, ee_addr); /* Finish EEPROM a clock tick. */ + eeprom_delay(250); + } + outw(EE_ENB, ee_addr); + + for (i = 15; i >= 0; i--) { + outw(EE_ENB | EE_SHIFT_CLK, ee_addr); + eeprom_delay(100); + retval = (retval << 1) | ((inw(ee_addr) & EE_DATA_READ) ? 1 : 0); + outw(EE_ENB, ee_addr); + eeprom_delay(100); + } + + /* Terminate the EEPROM access. */ + outw(EE_ENB & ~EE_CS, ee_addr); + return retval; +} + +static int mdio_read(int ioaddr, int phy_id, int location) +{ + int val, boguscnt = 64*4; /* <64 usec. to complete, typ 27 ticks */ + outl(0x08000000 | (location<<16) | (phy_id<<21), ioaddr + SCBCtrlMDI); + do { +#ifdef _LINUX_DELAY_H + udelay(16); +#else + SLOW_DOWN_IO; +#endif + val = inl(ioaddr + SCBCtrlMDI); + if (--boguscnt < 0) { + printk(KERN_ERR " mdio_read() timed out with val = %8.8x.\n", val); + } + } while (! (val & 0x10000000)); + return val & 0xffff; +} + +static int mdio_write(int ioaddr, int phy_id, int location, int value) +{ + int val, boguscnt = 64*4; /* <64 usec. to complete, typ 27 ticks */ + outl(0x04000000 | (location<<16) | (phy_id<<21) | value, + ioaddr + SCBCtrlMDI); + do { +#ifdef _LINUX_DELAY_H + udelay(16); +#else + SLOW_DOWN_IO; +#endif + val = inl(ioaddr + SCBCtrlMDI); + if (--boguscnt < 0) { + printk(KERN_ERR" mdio_write() timed out with val = %8.8x.\n", val); + } + } while (! (val & 0x10000000)); + return val & 0xffff; +} + + +static int +speedo_open(struct device *dev) +{ + struct speedo_private *sp = (struct speedo_private *)dev->priv; + int ioaddr = dev->base_addr; + +#ifdef notdef + /* We could reset the chip, but should not need to. */ + outl(0, ioaddr + SCBPort); + for (i = 40; i >= 0; i--) + SLOW_DOWN_IO; /* At least 250ns */ +#endif + +#ifdef SA_SHIRQ + if (request_irq(dev->irq, &speedo_interrupt, SA_SHIRQ, + "Intel EtherExpress Pro 10/100 Ethernet", dev)) { + return -EAGAIN; + } +#else +#ifdef USE_SHARED_IRQ + if (request_shared_irq(dev->irq, &speedo_interrupt, dev, + "Intel EtherExpress Pro 10/100 Ethernet")) + return -EAGAIN; +#else + if (dev->irq < 2 || dev->irq > 15 || irq2dev_map[dev->irq] != NULL) + return -EAGAIN; + irq2dev_map[dev->irq] = dev; + if (request_irq(dev->irq, &speedo_interrupt, 0, "Intel EtherExpress Pro 10/100 Ethernet")) { + irq2dev_map[dev->irq] = NULL; + return -EAGAIN; + } +#endif +#endif + + if (speedo_debug > 1) + printk(KERN_DEBUG "%s: speedo_open() irq %d.\n", dev->name, dev->irq); + + MOD_INC_USE_COUNT; + + /* Load the statistics block address. */ + outl(virt_to_bus(&sp->lstats), ioaddr + SCBPointer); + outw(INT_MASK | CU_STATSADDR, ioaddr + SCBCmd); + sp->lstats.done_marker = 0; + + speedo_init_rx_ring(dev); + outl(0, ioaddr + SCBPointer); + outw(INT_MASK | RX_ADDR_LOAD, ioaddr + SCBCmd); + + /* Todo: verify that we must wait for previous command completion. */ + wait_for_cmd_done(ioaddr + SCBCmd); + outl(virt_to_bus(sp->rx_ringp[0]), ioaddr + SCBPointer); + outw(INT_MASK | RX_START, ioaddr + SCBCmd); + + /* Fill the first command with our physical address. */ + { + unsigned short *eaddrs = (unsigned short *)dev->dev_addr; + unsigned short *setup_frm = (short *)&(sp->tx_ring[0].tx_desc_addr); + + /* Avoid a bug(?!) here by marking the command already completed. */ + sp->tx_ring[0].status = ((CmdSuspend | CmdIASetup) << 16) | 0xa000; + sp->tx_ring[0].link = virt_to_bus(&(sp->tx_ring[1])); + *setup_frm++ = eaddrs[0]; + *setup_frm++ = eaddrs[1]; + *setup_frm++ = eaddrs[2]; + } + sp->last_cmd = (struct descriptor *)&sp->tx_ring[0]; + sp->cur_tx = 1; + sp->dirty_tx = 0; + sp->tx_full = 0; + + outl(0, ioaddr + SCBPointer); + outw(INT_MASK | CU_CMD_BASE, ioaddr + SCBCmd); + + dev->if_port = sp->default_port; + + dev->tbusy = 0; + dev->interrupt = 0; + dev->start = 1; + + /* Start the chip's Tx process and unmask interrupts. */ + /* Todo: verify that we must wait for previous command completion. */ + wait_for_cmd_done(ioaddr + SCBCmd); + outl(virt_to_bus(&sp->tx_ring[0]), ioaddr + SCBPointer); + outw(CU_START, ioaddr + SCBCmd); + + /* Setup the chip and configure the multicast list. */ + sp->mc_setup_frm = NULL; + sp->mc_setup_frm_len = 0; + sp->rx_mode = -1; /* Invalid -> always reset the mode. */ + set_rx_mode(dev); + + if (speedo_debug > 2) { + printk(KERN_DEBUG "%s: Done speedo_open(), status %8.8x.\n", + dev->name, inw(ioaddr + SCBStatus)); + } + /* Set the timer. The timer serves a dual purpose: + 1) to monitor the media interface (e.g. link beat) and perhaps switch + to an alternate media type + 2) to monitor Rx activity, and restart the Rx process if the receiver + hangs. */ + init_timer(&sp->timer); + sp->timer.expires = RUN_AT((24*HZ)/10); /* 2.4 sec. */ + sp->timer.data = (unsigned long)dev; + sp->timer.function = &speedo_timer; /* timer handler */ + add_timer(&sp->timer); + + outw(CU_DUMPSTATS, ioaddr + SCBCmd); + return 0; +} + +/* Media monitoring and control. */ +static void speedo_timer(unsigned long data) +{ + struct device *dev = (struct device *)data; + struct speedo_private *sp = (struct speedo_private *)dev->priv; + int tickssofar = jiffies - sp->last_rx_time; + + if (speedo_debug > 3) { + int ioaddr = dev->base_addr; + printk(KERN_DEBUG "%s: Media selection tick, status %4.4x.\n", + dev->name, inw(ioaddr + SCBStatus)); + } + if (sp->rx_bug) { + if (tickssofar > 2*HZ || sp->rx_mode < 0) { + /* We haven't received a packet in a Long Time. We might have been + bitten by the receiver hang bug. This can be cleared by sending + a set multicast list command. */ + set_rx_mode(dev); + } + /* We must continue to monitor the media. */ + sp->timer.expires = RUN_AT(2*HZ); /* 2.0 sec. */ + add_timer(&sp->timer); + } +} + +/* Initialize the Rx and Tx rings, along with various 'dev' bits. */ +static void +speedo_init_rx_ring(struct device *dev) +{ + struct speedo_private *sp = (struct speedo_private *)dev->priv; + struct RxFD *rxf, *last_rxf = NULL; + int i; + + sp->cur_rx = 0; + sp->dirty_rx = RX_RING_SIZE - 1; + + for (i = 0; i < RX_RING_SIZE; i++) { + struct sk_buff *skb; +#ifndef KERNEL_1_2 + skb = dev_alloc_skb(PKT_BUF_SZ + sizeof(struct RxFD)); +#else + skb = alloc_skb(PKT_BUF_SZ, GFP_ATOMIC); +#endif + sp->rx_skbuff[i] = skb; + if (skb == NULL) + break; /* Bad news! */ + skb->dev = dev; /* Mark as being used by this device. */ + +#if LINUX_VERSION_CODE >= 0x10300 + rxf = (struct RxFD *)skb->tail; + skb_reserve(skb, sizeof(struct RxFD)); +#else + /* Save the data in the header region -- it's restored later. */ + rxf = (struct RxFD *)(skb->data - sizeof(struct RxFD)); + memcpy(&sp->saved_skhead[i], rxf, sizeof(struct RxFD)); +#endif + sp->rx_ringp[i] = rxf; + if (last_rxf) + last_rxf->link = virt_to_bus(rxf); + last_rxf = rxf; + rxf->status = 0x00000001; /* '1' is flag value only. */ + rxf->link = 0; /* None yet. */ +#if LINUX_VERSION_CODE < 0x10300 + /* This field unused by i82557, we use it as a consistency check. */ + rxf->rx_buf_addr = virt_to_bus(skb->data); +#else + rxf->rx_buf_addr = virt_to_bus(skb->tail); +#endif + rxf->count = 0; + rxf->size = PKT_BUF_SZ; + } + /* Mark the last entry as end-of-list. */ + last_rxf->status = 0xC0000002; /* '2' is flag value only. */ + sp->last_rxf = last_rxf; +} + +static void speedo_tx_timeout(struct device *dev) +{ + struct speedo_private *sp = (struct speedo_private *)dev->priv; + int ioaddr = dev->base_addr; + int i; + + printk(KERN_WARNING "%s: Transmit timed out: status %4.4x " + "command %4.4x.\n", + dev->name, inw(ioaddr + SCBStatus), inw(ioaddr + SCBCmd)); +#ifndef final_version + printk("%s: Tx timeout fill index %d scavenge index %d.\n", + dev->name, sp->cur_tx, sp->dirty_tx); + printk(" Tx queue "); + for (i = 0; i < TX_RING_SIZE; i++) + printk(" %8.8x", (int)sp->tx_ring[i].status); + printk(".\n Rx ring "); + for (i = 0; i < RX_RING_SIZE; i++) + printk(" %8.8x", (int)sp->rx_ringp[i]->status); + printk(".\n"); + +#else + dev->if_port ^= 1; + printk(" (Media type switching not yet implemented.)\n"); + /* Do not do 'dev->tbusy = 0;' there -- it is incorrect. */ +#endif + if ((inw(ioaddr + SCBStatus) & 0x00C0) != 0x0080) { + printk("%s: Trying to restart the transmitter...\n", dev->name); + outl(virt_to_bus(&sp->tx_ring[sp->dirty_tx % TX_RING_SIZE]), + ioaddr + SCBPointer); + outw(CU_START, ioaddr + SCBCmd); + } else { + outw(DRVR_INT, ioaddr + SCBCmd); + } + sp->stats.tx_errors++; + dev->trans_start = jiffies; + return; +} + +static int +speedo_start_xmit(struct sk_buff *skb, struct device *dev) +{ + struct speedo_private *sp = (struct speedo_private *)dev->priv; + int ioaddr = dev->base_addr; + int entry; + + if (skb == NULL || skb->len <= 0) { + printk(KERN_ERR "%s: Obsolete driver layer request made: skbuff==NULL.\n", + dev->name); + dev_tint(dev); + return 0; + } + + /* Block a timer-based transmit from overlapping. This could better be + done with atomic_swap(1, dev->tbusy), but set_bit() works as well. + If this ever occurs the queue layer is doing something evil! */ + if (set_bit(0, (void*)&dev->tbusy) != 0) { + int tickssofar = jiffies - dev->trans_start; + if (tickssofar < TX_TIMEOUT - 2) + return 1; + if (tickssofar < TX_TIMEOUT) { + /* Reap sent packets from the full Tx queue. */ + outw(DRVR_INT, ioaddr + SCBCmd); + return 1; + } + speedo_tx_timeout(dev); + return 0; + } + + /* Caution: the write order is important here, set the base address + with the "ownership" bits last. */ + + { /* Prevent interrupts from changing the Tx ring from underneath us. */ + unsigned long flags; + + save_flags(flags); + cli(); + /* Calculate the Tx descriptor entry. */ + entry = sp->cur_tx++ % TX_RING_SIZE; + + sp->tx_skbuff[entry] = skb; + /* Todo: be a little more clever about setting the interrupt bit. */ + sp->tx_ring[entry].status = + (CmdSuspend | CmdTx | CmdTxFlex) << 16; + sp->tx_ring[entry].link = + virt_to_bus(&sp->tx_ring[sp->cur_tx % TX_RING_SIZE]); + sp->tx_ring[entry].tx_desc_addr = + virt_to_bus(&sp->tx_ring[entry].tx_buf_addr); + /* The data region is always in one buffer descriptor, Tx FIFO + threshold of 256. */ + sp->tx_ring[entry].count = 0x01208000; + sp->tx_ring[entry].tx_buf_addr = virt_to_bus(skb->data); + sp->tx_ring[entry].tx_buf_size = skb->len; + /* Todo: perhaps leave the interrupt bit set if the Tx queue is more + than half full. Argument against: we should be receiving packets + and scavenging the queue. Argument for: if so, it shouldn't + matter. */ + sp->last_cmd->command &= ~(CmdSuspend | CmdIntr); + sp->last_cmd = (struct descriptor *)&sp->tx_ring[entry]; + /* Trigger the command unit resume. */ + outw(CU_RESUME, ioaddr + SCBCmd); + restore_flags(flags); + } + + /* Leave room for set_rx_mode() to fill two entries. */ + if (sp->cur_tx - sp->dirty_tx > TX_RING_SIZE - 3) + sp->tx_full = 1; + else + dev->tbusy = 0; + + dev->trans_start = jiffies; + + return 0; +} + +/* The interrupt handler does all of the Rx thread work and cleans up + after the Tx thread. */ +#ifdef SA_SHIRQ +static void speedo_interrupt(int irq, void *dev_instance, struct pt_regs *regs) +#else +static void speedo_interrupt(int irq, struct pt_regs *regs) +#endif +{ +#ifdef SA_SHIRQ + struct device *dev = (struct device *)dev_instance; +#else +#ifdef USE_SHARED_IRQ + struct device *dev = (struct device *)(irq == 0 ? regs : irq2dev_map[irq]); +#else + struct device *dev = (struct device *)(irq2dev_map[irq]); +#endif +#endif + struct speedo_private *sp; + int ioaddr, boguscnt = INTR_WORK; + unsigned short status; + +#ifndef final_version + if (dev == NULL) { + printk(KERN_ERR "speedo_interrupt(): irq %d for unknown device.\n", irq); + return; + } +#endif + + ioaddr = dev->base_addr; + sp = (struct speedo_private *)dev->priv; +#ifndef final_version + if (dev->interrupt) { + printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name); + return; + } + dev->interrupt = 1; +#endif + + do { + status = inw(ioaddr + SCBStatus); + /* Acknowledge all of the current interrupt sources ASAP. */ + outw(status & 0xfc00, ioaddr + SCBStatus); + + if (speedo_debug > 4) + printk(KERN_DEBUG "%s: interrupt status=%#4.4x.\n", + dev->name, status); + + if ((status & 0xfc00) == 0) + break; + + if (status & 0x4000) /* Packet received. */ + speedo_rx(dev); + + if (status & 0x1000) { +#ifdef notdef + int i; + printk(KERN_WARNING"%s: The EEPro100 receiver left the ready" + " state -- %4.4x! Index %d (%d).\n", dev->name, status, + sp->cur_rx, sp->cur_rx % RX_RING_SIZE); + printk(" Rx ring:\n "); + for (i = 0; i < RX_RING_SIZE; i++) + printk(" %d %8.8x %8.8x %8.8x %d %d.\n", + i, sp->rx_ringp[i]->status, sp->rx_ringp[i]->link, + sp->rx_ringp[i]->rx_buf_addr, sp->rx_ringp[i]->count, + sp->rx_ringp[i]->size); +#endif + + if ((status & 0x003c) == 0x0028) /* No more Rx buffers. */ + outw(RX_RESUMENR, ioaddr + SCBCmd); + else if ((status & 0x003c) == 0x0008) { /* No resources (why?!) */ + /* No idea of what went wrong. Restart the receiver. */ + outl(virt_to_bus(sp->rx_ringp[sp->cur_rx % RX_RING_SIZE]), + ioaddr + SCBPointer); + outw(RX_START, ioaddr + SCBCmd); + } + sp->stats.rx_errors++; + } + + /* User interrupt, Command/Tx unit interrupt or CU not active. */ + if (status & 0xA400) { + unsigned int dirty_tx = sp->dirty_tx; + + while (sp->cur_tx - dirty_tx > 0) { + int entry = dirty_tx % TX_RING_SIZE; + int status = sp->tx_ring[entry].status; + + if (speedo_debug > 5) + printk(KERN_DEBUG " scavenge canidate %d status %4.4x.\n", + entry, status); + if ((status & 0x8000) == 0) + break; /* It still hasn't been processed. */ + /* Free the original skb. */ + if (sp->tx_skbuff[entry]) { + sp->stats.tx_packets++; /* Count only user packets. */ + dev_kfree_skb(sp->tx_skbuff[entry], FREE_WRITE); + sp->tx_skbuff[entry] = 0; + } + dirty_tx++; + } + +#ifndef final_version + if (sp->cur_tx - dirty_tx > TX_RING_SIZE) { + printk("out-of-sync dirty pointer, %d vs. %d, full=%d.\n", + dirty_tx, sp->cur_tx, sp->tx_full); + dirty_tx += TX_RING_SIZE; + } +#endif + + if (sp->tx_full && dev->tbusy + && dirty_tx > sp->cur_tx - TX_RING_SIZE + 2) { + /* The ring is no longer full, clear tbusy. */ + sp->tx_full = 0; + dev->tbusy = 0; + mark_bh(NET_BH); + } + + sp->dirty_tx = dirty_tx; + } + + if (--boguscnt < 0) { + printk("%s: Too much work at interrupt, status=0x%4.4x.\n", + dev->name, status); + /* Clear all interrupt sources. */ + outl(0xfc00, ioaddr + SCBStatus); + break; + } + } while (1); + + if (speedo_debug > 3) + printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n", + dev->name, inw(ioaddr + SCBStatus)); + +#ifndef final_version + /* Special code for testing *only*. */ + { + static int stopit = 100; + if (dev->start == 0 && --stopit < 0) { + printk(KERN_ALERT "%s: Emergency stop, interrupt is stuck.\n", + dev->name); +#ifdef SA_SHIRQ + free_irq(irq, dev); +#else + free_irq(irq); +#endif + } + } +#endif + + dev->interrupt = 0; + return; +} + +static int +speedo_rx(struct device *dev) +{ + struct speedo_private *sp = (struct speedo_private *)dev->priv; + int entry = sp->cur_rx % RX_RING_SIZE; + int status; + + if (speedo_debug > 4) + printk(KERN_DEBUG " In speedo_rx().\n"); + /* If we own the next entry, it's a new packet. Send it up. */ + while ((status = sp->rx_ringp[entry]->status) & RX_COMPLETE) { + + if (speedo_debug > 4) + printk(KERN_DEBUG " speedo_rx() status %8.8x len %d.\n", status, + sp->rx_ringp[entry]->count & 0x3fff); + if (status & 0x0200) { + printk("%s: Ethernet frame overran the Rx buffer, status %8.8x!\n", + dev->name, status); + } else if ( ! (status & 0x2000)) { + /* There was a fatal error. This *should* be impossible. */ + sp->stats.rx_errors++; + printk("%s: Anomalous event in speedo_rx(), status %8.8x.\n", + dev->name, status); + } else { + /* Malloc up new buffer, compatible with net-2e. */ + short pkt_len = sp->rx_ringp[entry]->count & 0x3fff; + struct sk_buff *skb; + int rx_in_place = 0; + + /* Check if the packet is long enough to just accept without + copying to a properly sized skbuff. */ + if (pkt_len > SKBUFF_RX_COPYBREAK) { + struct sk_buff *newskb; + char *temp; + + /* Pass up the skb already on the Rx ring. */ + skb = sp->rx_skbuff[entry]; +#ifdef KERNEL_1_2 + temp = skb->data; + if (bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr) != temp) + printk("%s: Warning -- the skbuff addresses do not match" + " in speedo_rx: %p vs. %p / %p.\n", dev->name, + bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr), + temp, skb->data); + /* Get a fresh skbuff to replace the filled one. */ + newskb = alloc_skb(PKT_BUF_SZ, GFP_ATOMIC); +#else + temp = skb_put(skb, pkt_len); + if (bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr) != temp) + printk("%s: Warning -- the skbuff addresses do not match" + " in speedo_rx: %8.8x vs. %p / %p.\n", dev->name, + sp->rx_ringp[entry]->rx_buf_addr, skb->head, temp); + /* Get a fresh skbuff to replace the filled one. */ + newskb = dev_alloc_skb(PKT_BUF_SZ + sizeof(struct RxFD)); +#endif + if (newskb) { + struct RxFD *rxf; + rx_in_place = 1; + sp->rx_skbuff[entry] = newskb; + newskb->dev = dev; +#ifdef KERNEL_1_2 + /* Restore the data in the old header region. */ + memcpy(skb->data - sizeof(struct RxFD), + &sp->saved_skhead[entry], sizeof(struct RxFD)); + /* Save the data in this header region. */ + rxf = (struct RxFD *)(newskb->data - sizeof(struct RxFD)); + sp->rx_ringp[entry] = rxf; + memcpy(&sp->saved_skhead[entry], rxf, sizeof(struct RxFD)); + rxf->rx_buf_addr = virt_to_bus(newskb->data); +#else + rxf = sp->rx_ringp[entry] = (struct RxFD *)newskb->tail; + skb_reserve(newskb, sizeof(struct RxFD)); + /* Unused by i82557, consistency check only. */ + rxf->rx_buf_addr = virt_to_bus(newskb->tail); +#endif + rxf->status = 0x00000001; + } else /* No memory, drop the packet. */ + skb = 0; + } else +#ifdef KERNEL_1_2 + skb = alloc_skb(pkt_len, GFP_ATOMIC); +#else + skb = dev_alloc_skb(pkt_len + 2); +#endif + if (skb == NULL) { + int i; + printk("%s: Memory squeeze, deferring packet.\n", dev->name); + /* Check that at least two ring entries are free. + If not, free one and mark stats->rx_dropped++. */ + /* ToDo: This is not correct!!!! We should count the number + of linked-in Rx buffer to very that we have at least two + remaining. */ + for (i = 0; i < RX_RING_SIZE; i++) + if (! ((sp->rx_ringp[(entry+i) % RX_RING_SIZE]->status) + & RX_COMPLETE)) + break; + + if (i > RX_RING_SIZE -2) { + sp->stats.rx_dropped++; + sp->rx_ringp[entry]->status = 0; + sp->cur_rx++; + } + break; + } + skb->dev = dev; +#if (LINUX_VERSION_CODE >= VERSION(1,3,44)) + if (! rx_in_place) { + skb_reserve(skb, 2); /* 16 byte align the data fields */ + memcpy(skb_put(skb, pkt_len), + bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr), pkt_len); + } + skb->protocol = eth_type_trans(skb, dev); +#else +#ifdef KERNEL_1_3 +#warning This code has only been tested with later 1.3.* kernels. + skb->len = pkt_len; + memcpy(skb->data, bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr), + pkt_len); + /* Needed for 1.3.*. */ + skb->protocol = eth_type_trans(skb, dev); +#else /* KERNEL_1_2 */ + skb->len = pkt_len; + if (! rx_in_place) { + memcpy(skb->data, + bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr), pkt_len); + } +#endif +#endif + netif_rx(skb); + sp->stats.rx_packets++; + } + + /* ToDo: This is better than before, but should be checked. */ + { + struct RxFD *rxf = sp->rx_ringp[entry]; + rxf->status = 0xC0000003; /* '3' for verification only */ + rxf->link = 0; /* None yet. */ + rxf->count = 0; + rxf->size = PKT_BUF_SZ; + sp->last_rxf->link = virt_to_bus(rxf); + sp->last_rxf->status &= ~0xC0000000; + sp->last_rxf = rxf; + entry = (++sp->cur_rx) % RX_RING_SIZE; + } + } + + sp->last_rx_time = jiffies; + return 0; +} + +static int +speedo_close(struct device *dev) +{ + int ioaddr = dev->base_addr; + struct speedo_private *sp = (struct speedo_private *)dev->priv; + int i; + + dev->start = 0; + dev->tbusy = 1; + + if (speedo_debug > 1) + printk(KERN_DEBUG "%s: Shutting down ethercard, status was %4.4x.\n", + dev->name, inw(ioaddr + SCBStatus)); + + /* Shut off the media monitoring timer. */ + del_timer(&sp->timer); + + /* Disable interrupts, and stop the chip's Rx process. */ + outw(INT_MASK, ioaddr + SCBCmd); + outw(INT_MASK | RX_ABORT, ioaddr + SCBCmd); + +#ifdef SA_SHIRQ + free_irq(dev->irq, dev); +#else + free_irq(dev->irq); + irq2dev_map[dev->irq] = 0; +#endif + + /* Free all the skbuffs in the Rx and Tx queues. */ + for (i = 0; i < RX_RING_SIZE; i++) { + struct sk_buff *skb = sp->rx_skbuff[i]; + sp->rx_skbuff[i] = 0; + /* Clear the Rx descriptors. */ + if (skb) + dev_kfree_skb(skb, FREE_WRITE); + } + + for (i = 0; i < TX_RING_SIZE; i++) { + struct sk_buff *skb = sp->tx_skbuff[i]; + sp->tx_skbuff[i] = 0; + /* Clear the Tx descriptors. */ + if (skb) + dev_kfree_skb(skb, FREE_WRITE); + } + if (sp->mc_setup_frm) { + kfree(sp->mc_setup_frm); + sp->mc_setup_frm_len = 0; + } + + /* Print a few items for debugging. */ + if (speedo_debug > 3) { + printk("%s:Printing Rx ring (next to receive into %d).\n", + dev->name, sp->cur_rx); + + for (i = 0; i < RX_RING_SIZE; i++) + printk(" Rx ring entry %d %8.8x.\n", + i, (int)sp->rx_ringp[i]->status); + + for (i = 0; i < 5; i++) + printk(" PHY index %d register %d is %4.4x.\n", + 1, i, mdio_read(ioaddr, 1, i)); + for (i = 21; i < 26; i++) + printk(" PHY index %d register %d is %4.4x.\n", + 1, i, mdio_read(ioaddr, 1, i)); + } + MOD_DEC_USE_COUNT; + + return 0; +} + +/* The Speedo-3 has an especially awkward and unusable method of getting + statistics out of the chip. It takes an unpredictable length of time + for the dump-stats command to complete. To avoid a busy-wait loop we + update the stats with the previous dump results, and then trigger a + new dump. + + These problems are mitigated by the current /proc implementation, which + calls this routine first to judge the output length, and then to emit the + output. + + Oh, and incoming frames are dropped while executing dump-stats! + */ +static struct enet_statistics * +speedo_get_stats(struct device *dev) +{ + struct speedo_private *sp = (struct speedo_private *)dev->priv; + int ioaddr = dev->base_addr; + + if (sp->lstats.done_marker == 0xA007) { /* Previous dump finished */ + sp->stats.tx_aborted_errors += sp->lstats.tx_coll16_errs; + sp->stats.tx_window_errors += sp->lstats.tx_late_colls; + sp->stats.tx_fifo_errors += sp->lstats.tx_underruns; + sp->stats.tx_fifo_errors += sp->lstats.tx_lost_carrier; + /*sp->stats.tx_deferred += sp->lstats.tx_deferred;*/ + sp->stats.collisions += sp->lstats.tx_total_colls; + sp->stats.rx_crc_errors += sp->lstats.rx_crc_errs; + sp->stats.rx_frame_errors += sp->lstats.rx_align_errs; + sp->stats.rx_over_errors += sp->lstats.rx_resource_errs; + sp->stats.rx_fifo_errors += sp->lstats.rx_overrun_errs; + sp->stats.rx_length_errors += sp->lstats.rx_runt_errs; + sp->lstats.done_marker = 0x0000; + if (dev->start) + outw(CU_DUMPSTATS, ioaddr + SCBCmd); + } + return &sp->stats; +} + +/* Set or clear the multicast filter for this adaptor. + This is very ugly with Intel chips -- we usually have to execute an + entire configuration command, plus process a multicast command. + This is complicated. We must put a large configuration command and + an arbitrarily-sized multicast command in the transmit list. + To minimize the disruption -- the previous command might have already + loaded the link -- we convert the current command block, normally a Tx + command, into a no-op and link it to the new command. +*/ +static void +set_rx_mode(struct device *dev) +{ + struct speedo_private *sp = (struct speedo_private *)dev->priv; + int ioaddr = dev->base_addr; + char new_rx_mode; + unsigned long flags; + int entry, i; + + if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ + new_rx_mode = 3; + } else if (dev->flags & IFF_ALLMULTI) { + new_rx_mode = 1; + } else + new_rx_mode = 0; + + if (sp->cur_tx - sp->dirty_tx >= TX_RING_SIZE - 1) { + /* The Tx ring is full -- don't add anything! Presumably the new mode + is in config_cmd_data and will be added anyway. */ + sp->rx_mode = -1; + return; + } + + if (new_rx_mode != sp->rx_mode) { + /* We must change the configuration. Construct a CmdConfig frame. */ + memcpy(sp->config_cmd_data, basic_config_cmd,sizeof(basic_config_cmd)); + sp->config_cmd_data[1] = (txfifo << 4) | rxfifo; + sp->config_cmd_data[4] = rxdmacount; + sp->config_cmd_data[5] = txdmacount + 0x80; + sp->config_cmd_data[15] = (new_rx_mode & 2) ? 0x49 : 0x48; + sp->config_cmd_data[19] = sp->full_duplex ? 0xC0 : 0x80; + sp->config_cmd_data[21] = (new_rx_mode & 1) ? 0x0D : 0x05; + if (sp->phy[0] & 0x8000) { /* Use the AUI port instead. */ + sp->config_cmd_data[15] |= 0x80; + sp->config_cmd_data[8] = 0; + } + save_flags(flags); + cli(); + /* Fill the "real" tx_ring frame with a no-op and point it to us. */ + entry = sp->cur_tx++ % TX_RING_SIZE; + sp->tx_skbuff[entry] = 0; /* Nothing to free. */ + sp->tx_ring[entry].status = CmdNOp << 16; + sp->tx_ring[entry].link = virt_to_bus(&sp->config_cmd); + sp->config_cmd.status = 0; + sp->config_cmd.command = CmdSuspend | CmdConfigure; + sp->config_cmd.link = + virt_to_bus(&(sp->tx_ring[sp->cur_tx % TX_RING_SIZE])); + sp->last_cmd->command &= ~CmdSuspend; + /* Immediately trigger the command unit resume. */ + outw(CU_RESUME, ioaddr + SCBCmd); + sp->last_cmd = &sp->config_cmd; + restore_flags(flags); + if (speedo_debug > 5) { + int i; + printk(" CmdConfig frame in entry %d.\n", entry); + for(i = 0; i < 32; i++) + printk(" %2.2x", ((unsigned char *)&sp->config_cmd)[i]); + printk(".\n"); + } + } + + if (new_rx_mode == 0 && dev->mc_count < 3) { + /* The simple case of 0-2 multicast list entries occurs often, and + fits within one tx_ring[] entry. */ + u16 *setup_params; + unsigned short *eaddrs; + struct dev_mc_list *mclist; + + save_flags(flags); + cli(); + entry = sp->cur_tx++ % TX_RING_SIZE; + sp->tx_skbuff[entry] = 0; + sp->tx_ring[entry].status = (CmdSuspend | CmdMulticastList) << 16; + sp->tx_ring[entry].link = + virt_to_bus(&sp->tx_ring[sp->cur_tx % TX_RING_SIZE]); + sp->tx_ring[entry].tx_desc_addr = 0; /* Really MC list count. */ + setup_params = (short *)&sp->tx_ring[entry].tx_desc_addr; + *setup_params++ = dev->mc_count*6; + /* Fill in the multicast addresses. */ + for (i = 0, mclist = dev->mc_list; i < dev->mc_count; + i++, mclist = mclist->next) { + eaddrs = (unsigned short *)mclist->dmi_addr; + *setup_params++ = *eaddrs++; + *setup_params++ = *eaddrs++; + *setup_params++ = *eaddrs++; + } + + sp->last_cmd->command &= ~CmdSuspend; + /* Immediately trigger the command unit resume. */ + outw(CU_RESUME, ioaddr + SCBCmd); + sp->last_cmd = (struct descriptor *)&sp->tx_ring[entry]; + restore_flags(flags); + } else if (new_rx_mode == 0) { + /* This does not work correctly, but why not? */ + struct dev_mc_list *mclist; + unsigned short *eaddrs; + struct descriptor *mc_setup_frm = sp->mc_setup_frm; + u16 *setup_params = (short *)mc_setup_frm->params; + int i; + + if (sp->mc_setup_frm_len < 10 + dev->mc_count*6 + || sp->mc_setup_frm == NULL) { + /* Allocate a new frame, 10bytes + addrs, with a few + extra entries for growth. */ + if (sp->mc_setup_frm) + kfree(sp->mc_setup_frm); + sp->mc_setup_frm_len = 10 + dev->mc_count*6 + 24; + printk("%s: Allocating a setup frame of size %d.\n", + dev->name, sp->mc_setup_frm_len); + sp->mc_setup_frm = kmalloc(sp->mc_setup_frm_len, + intr_count ? GFP_ATOMIC : GFP_KERNEL); + if (sp->mc_setup_frm == NULL) { + printk("%s: Failed to allocate a setup frame.\n", dev->name); + sp->rx_mode = -1; /* We failed, try again. */ + return; + } + } + mc_setup_frm = sp->mc_setup_frm; + /* Construct the new setup frame. */ + printk("%s: Constructing a setup frame at %p, %d bytes.\n", + dev->name, sp->mc_setup_frm, sp->mc_setup_frm_len); + mc_setup_frm->status = 0; + mc_setup_frm->command = CmdSuspend | CmdIntr | CmdMulticastList; + /* Link set below. */ + setup_params = (short *)mc_setup_frm->params; + *setup_params++ = dev->mc_count*6; + /* Fill in the multicast addresses. */ + for (i = 0, mclist = dev->mc_list; i < dev->mc_count; + i++, mclist = mclist->next) { + eaddrs = (unsigned short *)mclist->dmi_addr; + *setup_params++ = *eaddrs++; + *setup_params++ = *eaddrs++; + *setup_params++ = *eaddrs++; + } + + /* Disable interrupts while playing with the Tx Cmd list. */ + save_flags(flags); + cli(); + entry = sp->cur_tx++ % TX_RING_SIZE; + + if (speedo_debug > 5) + printk(" CmdMCSetup frame length %d in entry %d.\n", + dev->mc_count, entry); + + /* Change the command to a NoOp, pointing to the CmdMulti command. */ + sp->tx_skbuff[entry] = 0; + sp->tx_ring[entry].status = CmdNOp << 16; + sp->tx_ring[entry].link = virt_to_bus(mc_setup_frm); + + /* Set the link in the setup frame. */ + mc_setup_frm->link = + virt_to_bus(&(sp->tx_ring[sp->cur_tx % TX_RING_SIZE])); + + sp->last_cmd->command &= ~CmdSuspend; + /* Immediately trigger the command unit resume. */ + outw(CU_RESUME, ioaddr + SCBCmd); + sp->last_cmd = mc_setup_frm; + restore_flags(flags); + printk("%s: Last command at %p is %4.4x.\n", + dev->name, sp->last_cmd, sp->last_cmd->command); + } + + sp->rx_mode = new_rx_mode; +} + +#ifdef MODULE +#if (LINUX_VERSION_CODE < VERSION(1,3,38)) /* 1.3.38 and later */ +char kernel_version[] = UTS_RELEASE; +#endif + +int +init_module(void) +{ + int cards_found; + + if (debug >= 0) + speedo_debug = debug; + if (speedo_debug) + printk(KERN_INFO "%s", version); + + root_speedo_dev = NULL; + cards_found = eepro100_init(NULL); + return cards_found < 0 ? cards_found : 0; +} + +void +cleanup_module(void) +{ + struct device *next_dev; + + /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ + while (root_speedo_dev) { + next_dev = ((struct speedo_private *)root_speedo_dev->priv)->next_module; + unregister_netdev(root_speedo_dev); + release_region(root_speedo_dev->base_addr, SPEEDO3_TOTAL_SIZE); + kfree(root_speedo_dev); + root_speedo_dev = next_dev; + } +} +#else /* not MODULE */ +int eepro100_probe(struct device *dev) +{ + int cards_found = 0; + + cards_found = eepro100_init(dev); + + if (speedo_debug > 0 && cards_found) + printk(version); + + return cards_found ? 0 : -ENODEV; +} +#endif /* MODULE */ + +/* + * Local variables: + * compile-command: "gcc -DCONFIG_MODVERSIONS -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c eepro100.c" + * c-indent-level: 4 + * tab-width: 4 + * End: + */ diff --git a/drivers/net/ne.c b/drivers/net/ne.c index dc657089e3cc..4384bac78a57 100644 --- a/drivers/net/ne.c +++ b/drivers/net/ne.c @@ -62,9 +62,11 @@ static const char *version = /* Do we have a non std. amount of memory? (in units of 256 byte pages) */ /* #define PACKETBUF_MEMSIZE 0x40 */ +#if defined(HAVE_DEVLIST) || !defined(MODULE) /* A zero-terminated list of I/O addresses to be probed. */ static unsigned int netcard_portlist[] = { 0x300, 0x280, 0x320, 0x340, 0x360, 0}; +#endif /* defined(HAVE_DEVLIST) || !defined(MODULE) */ #ifdef CONFIG_PCI /* Ack! People are making PCI ne2000 clones! Oh the horror, the horror... */ @@ -160,7 +162,9 @@ struct netdev_entry netcard_drv = int ne_probe(struct device *dev) { +#ifndef MODULE int i; +#endif /* MODULE */ int base_addr = dev ? dev->base_addr : 0; /* First check any supplied i/o locations. User knows best. */ diff --git a/drivers/net/smc-ultra32.c b/drivers/net/smc-ultra32.c index e31fc71c8b58..418d59e1663d 100644 --- a/drivers/net/smc-ultra32.c +++ b/drivers/net/smc-ultra32.c @@ -47,7 +47,6 @@ static const char *version = "smc-ultra32.c: 06/97 v1.00\n"; #include -#include #include #include #include diff --git a/drivers/scsi/ChangeLog.ncr53c8xx b/drivers/scsi/ChangeLog.ncr53c8xx index d13f6f5c8207..94a2319757f3 100644 --- a/drivers/scsi/ChangeLog.ncr53c8xx +++ b/drivers/scsi/ChangeLog.ncr53c8xx @@ -1,3 +1,421 @@ +Sat July 26 18:00 1997 Gerard Roudier (groudier@club-internet.fr) + * revision 2.4 + Several clean-ups: + - Asynchronous pre-scaler calculation. + Synchronous divisor calculation. + - Use FE_ as feature identifier prefix instead of _F_. + - Change 'ns_sync' identifier to "minsync". + - Some others. + Apply some SPI2-R12 recommendations. + - Use Slow, Fast-10, Fast-20, Fast-40 SCSI instead of SCSI-2, + FAST SCSI-2, ULTRA, ULTRA-2. + - Reset the SCSI on bus mode change. + +Wed July 02 22:58 1997 Gerard Roudier (groudier@club-internet.fr) + * revision 2.3c + - Add define SCSI_NCR_PCI_FIX_UP_SUPPORT for conditionnal compilation + of the corresponding pci fix-up code when a small driver is needed. + - Use "ncr53c8xx" as driver name for both request_irq() and + request_region(). Using different names confused 'lsdev'. + (Suggestion sent by Henrik Storner). + +Wed June 24 22:08 1997 Gerard Roudier (groudier@club-internet.fr) + * revision 2.3b + - Print an error message on unexpected boot command line option. + - Switch to asynchronous data transfer mode after SCSI wide + negotiation. + +Wed June 24 22:08 1997 Gerard Roudier (groudier@club-internet.fr) + * revision 2.3b + - Print an error message on unexpected boot command line option. + - Switch to asynchronous data transfer mode after SCSI wide + negotiation. + +Wed June 14 22:00 1997 Gerard Roudier (groudier@club-internet.fr) + * revision 2.3a + - Add PCI LATENCY TIMER fixup code. + Increase it if necessary according to burst size. + Boot option bit : 'pcifix:4' + - On phase mismatch, calculate residual data size for all OUTPUT + phases. That's only required for interrupted DATA OUT phase, but + this information is usefull for problem solving. + - Add KERN_INFO to some messages printed to the log. + (Patch sent by Wolfram Kleff). + +Tue June 02 22:30 1997 Gerard Roudier (groudier@club-internet.fr) + * revision 2.3 + - NvRAM support code slightly improved (I think): + Use IO or MMIO according to driver setup for reading the NvRAM. + Use structures for NvRAM data instead of raw data. + - Prevent from queuing more than 1 command to the scsi SCRIPT with + negotiation attached when tagged command queueing is enabled. + - Fix-up for old 53C8XX chips that support PCI READ LINE but not + CACHE LINE SIZE. If the cache line size is unknown, set burst + to 8 dwords and disable READ LINE, otherwise set burst max to + the cache line size value. + +Sat May 24 12:30 1997 Gerard Roudier (groudier@club-internet.fr) + * revision 2.2c (for linux-2.1.40) + - Remove reference to 'x86' symbol when MODULE is defined, since this + symbol is not exported for module loading. + The value of 'x86' is used for fixing up the PCI CACHE LINE SIZE + configuration register. + - Bytes/words read one bit at a time from the serial NVRAM were'nt + initialized with zero. + - Some comments added. Minor cosmetic changes. + +Mon May 19 20:30 1997 Gerard Roudier (groudier@club-internet.fr) + * revision 2.2b + - Patch for NVRAM support by Richard Waltham applied. + The code detects Symbios NVRAM format and Tekram NVRAM format. + This enhancement allows to get hosts and devices user set up + from the NVRAM. + - Use the NVRAM contents when present to initialize user definable + target parameters. + - Update the README file. + +Sun May 11 22:30 1997 Gerard Roudier (groudier@club-internet.fr) + * revision 2.1b + - Cosmetic changes. + - Some heavy testings under pre-linux-2.1.37-6 + +Sun May 4 22:30 1997 Gerard Roudier (groudier@club-internet.fr) + * revision 2.1a + - PFEN wrongly used for PREFETCH feature bit testing. + Changed to _F_PFEN. + - 2 SCR_COPY that need NO FLUSH bit to be removed had been missed + in tp->getscr[] script (loads SXFER and SCNTL3 on reselection). + +Sat May 3 22:30 1997 Gerard Roudier (groudier@club-internet.fr) + * revision 2.1 + - Use the NO FLUSH option for MOVE MEMORY (COPY) each time it is + possible. More than 100 COPY with NO FLUSH and 6 with FLUSH for + my configuration (max queued command / device = 8). + This option bit is removed from the script instance for chips + that donnot support prefetching. + - Rewrite the ncr_exception() routine more simple (I think) and + remove useless code. + - Change the data_in and data_out script management. + Use the bottom part of these scripts instead of the beginning. + That avoids to zero the scatter/gather array when a command is + queued (1k) and to deal with some weird IID on MOVE 0 bytes when + a target wants to transfer more bytes than expected. + - Misc. improvements in the init code. + - Remove IOMAPPED/MMIO automatic switching option. + Was useless and reported not reliable. + - Fix a double read of DSTAT and remove DFE testing in the + Phase mismatch service routine. + - Etc... + +Fri Apr 26 20:00 1997 Gerard Roudier (groudier@club-internet.fr) + * revision 2.0a + - Add support if the Diamond FirePort 40 (SYM53C875J chip) + +Mon Apr 22 22:00 1997 Gerard Roudier (groudier@club-internet.fr) + * revision 2.0 + - incorporate __initdata and __initfunc directives in order to + allow 'init' to free unused memory after driver initialisations. + Patch sent by Roberto Fichera. + - rewrite the init code of the driver. Now a feature descriptor + is used for each real chip types. The code is a lot more clean, + since the driver uses device and revision ids only in the + detection procedure. + - add 'pcifix' boot command line. This command allows to fix up PCI + config space for new chips which support features based on the + cache line size and 'write and invalidate'. + - incorporate in the driver, the code used for error recovery + testing. This code is normally not compiled; have to define + SCSI_NCR_DEBUG_ERROR_RECOVERY in order to compile it. + - take into account actual SCSI bus mode for 53C895 LVD/SE controller. + In single ended mode only fast20 is supported. + (Just to not be late since such controllers are not yet available) + + +Sat Apr 20 21:00 1997 Gerard Roudier (groudier@club-internet.fr) + * revision 1.18f + - fix an old bug included in the initial port (version 0.0). + The driver allocated 10 bytes of static data and uses 12 bytes. + No danger, since data are generally aligned on 4 bytes boundary + and so byte 10 and 11 are free (I hope ...) + +Wed Apr 16 12:00 1997 Gerard Roudier (groudier@club-internet.fr) + * revision 1.18e + - reset all when an unexpected data cycle is detected while + disconnecting. + - make changes to abort() ans reset() functions according to + Leonard's documentation. + - small fix in some message for hard errors. + +Sat Apr 5 13:00 1997 Gerard Roudier (groudier@club-internet.fr) + * revision 1.18d + - Probe NCR pci device ids in reverse order if asked by user from + the boot command line. Suggested by Richard Waltham. + - Make a separate function that prints out verbose information on + severe error (assumed from hardware). + - Add the transfer period factor and the max commands per lun value + to the proc info data. If debug flags are set or verbosity is + greater than 1, debug flags and verbosity are returned in proc + info data. + - Update the documentation. + +Thu Mar 20 23:00 1997 Gerard Roudier (groudier@club-internet.fr) + * revision 1.18c + - Add special features support for NCR53C885 and NCR53C896 chip. + Quite obvious, but untested, and based on the fact that: + The 885 supports same features as the 875. + The 896 is a 64 bits PCI version of the 895. + - Improve recovery from SCSI GROSS ERRORS. + I can get such errors by making the driver negotiate offset 8 with + a disk and setting the ncr chip to a lower offset value. + I got bunches of errors that have been gracefully recovered by + the driver. + The driver now uses its timer handler in order to wait 2 sec. for + devices to settle after SCSI reset and so does not uselessly freeze + the system with interrupt masked for seconds. + - Enable 'burst op code fetch' and 'read line' for 815 chips. + - Use a 2 commands queue depth instead of 1 for devices that does + not support tagged command queuing. + - The ULTRA timing flag setting was based on the output resulting + period factor of the ncr and not on the negotiated one. + This flag setting was wrong only for 24 ns negotiated period factor. + - Some other minor changes and cleanups. + +Thu Feb 27 23:00 1997 Gerard Roudier (groudier@club-internet.fr) + * ncr53c8xx.c ncr53c8xx.h revision 1.18b + - 'On paper' support of the NCR53C895 Ultra-2 chip. + (Clock quadrupler + 7 clock divisors) + - Load the main part of the script into the on-board RAM. + - 810A rev. 0x11 PCI problem fixed. + This chip is now supported with all PCI features enabled and + 16 dwords burst transfers. + - Align on 32 boundary some internal structures. + That fixes the 810A problem and allows cache line bursting when + moving the global header (64 bytes) from/to CCBs to/from NCB. + - Synchronous parameters calculation rewritten. The driver + now uses all available clock divisors and will be able to support + clock frequencies that are not multiple of 40 Mhz if necessary. + +Sat Feb 8 22:00 1997 Gerard Roudier (groudier@club-internet.fr) + * ncr53c8xx.c - revision 1.17a + - IRQ mode set up from boot setup command. + irqm:0 open drain (default) + irqm:1 preserve initial setting (assumed from BIOS) + irqm:2 totem pole + - DIFF mode set up from boot setup command. + Suggested by Richard Waltham. + diff:0 never set up diff mode (default) + diff:1 set up diff mode according to initial setting (BIOS?) + diff:2 always set up diff mode + diff:3 set up diff mode if GPIO3 is zero (SYMBIOS boards) + - Change CONFIG option for LED support. + CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT allows LED support and + DIFF support for SYMBIOS boards and compatibles (clones?). + - Set 16 DWORD bursts for 810A rev. >= 0x12 since my SC200 with + such a chip have no problem with it (MB with Triton 2 HX). + 810A rev. 0x11 are set to 8 DWORD bursts since they may give + problems with PCI read multiple and Triton 2 HX. + Thanks to Stefan for this information. + +Sat Jan 25 22:00 1997 Gerard Roudier (groudier@club-internet.fr) + * ncr53c8xx.c - revision 1.17 + - Controller LED support. + Only works with LED pin wired to GPIO_FETCHN, so probably with + all boards using SMDS BIOS. + This option can be enabled only if CONFIG_EXPERIMENTAL is set. + - Assume clock doubler for 875 chip when clock frequency measurement + result is 40 MHz. May help when some old stuff as SDMS BIOS 3.0 + or some old driver has broken the normal BIOS settings. + - Add wide negotiation control from boot setup command. + May be usefull with systems using a 875 based board connected to + a wide device through a 50 pins to 68 pins converter. + - Add a "boot fail safe option" to the boot setup command line. + - Rewrite the "reset_command" routine. + Low-level driver are responsible to keep the involved command + alive. The new code seems to behave correctly. + - Change some variables used by the script from u_long to u_int32. + - Remove some useless code. + +Sun Jan 12 12:00 1997 Gerard Roudier (groudier@club-internet.fr) + * ncr53c8xx.c - revision 1.16e + - Add support of PCI burst length control from boot setup command. + burst:0 disable burst + burst:255 get burst from initial settings (BIOS settings?) + burst:#x set burst transfers to 1<<#x + - Only check xfer direction for common op-codes. + For all device specific / vendor specific opcodes the driver + now uses the xfer direction decided by the target. + +Sun Jan 05 12:00 1997 Gerard Roudier (groudier@club-internet.fr) + * ncr53c8xx.c - revision 1.16d + - The driver is now able to process scsi commands without + knowledge of xfer data direction. + Stefan agreed with this change for Linux. This change is + not needed under FreeBSD since low-level drivers receive + the expected data direction for each scsi request. + - Save ctest5 features bits at start-up and restore them at + module release step. + Avoid side effects when a ncr driver which trusts bios + settings is reloaded (could be the ncr53c8xx itself). + + +Wed Jan 01 23:30 1997 Gerard Roudier (groudier@club-internet.fr) + * ncr53c8xx.c - revision 1.16c + - Bad decision about 20MHz for 13 ns period factor. + Was wrong, so I restore the previous algorithm. + - Burst length 128 not correctly set in dmode. + +Thu Dec 26 22:00 1996 Gerard Roudier (groudier@club-internet.fr) + * ncr53c8xx.c ncr53c8xx.h README.ncr53c8xx - revision 1.16b + - Remove useless code. + - Try to improve error recovery in case of abort and reset. + - Remove DEBUG_NEGO by default. + - Add boot setup command support. + Now, all experimental config options can be removed. + - Update README file. + + +Mon Dec 23 23:00 1996 Gerard Roudier (groudier@club-internet.fr) + * ncr53c8xx.c ncr53c8xx.h - revision 1.16a + New display for speed ##.# MB/s (From Stefan) + - I add "WIDE" qualifier after ULTRA and FAST + - I get "FAST WIDE SCSI-2 20 MB/s" with my Atlas. That's nice. + + Richard Waltham reports SYMBIOS set the 875 to 20 MB/s for 13 ns + period factor. I decide to trust SYMBIOS. 20 MB/s output speed + instead of 19.2 MB/s should not cause problem. The ncr is only able + to use 16.67 MB/s when 20 MB/s is not possible. + + Fix from Markus Kossman: "Ultra SCSI enabled" wrongly printed + when not enabled. + + Set DEBUG_NEGO by default in order to get reports about sync nego. + Will remove it in the next patch. + +Thu Dec 19 21:00 1996 Gerard Roudier (groudier@club-internet.fr) + * ncr53c8xx.c ncr53c8xx.h README.ncr53c8xx - revision 1.16 + Incorporate new definitions in ncr53c8xx.h (From Stefan). + Check changes against Stefan's current version of the driver. + All seems ok. + +Sat Nov 30 21:00 1996 Gerard Roudier (groudier@club-internet.fr) + * ncr53c8xx.c ncr53c8xx.h + Make changes in order to support: + - Clock doubler and so 80 Mhz scsi clock for 875 chips. + - Sync transfers below 7.5 MB/sec. + Use Clock/2 between 5 and 10 Mega-transfers/s and Clock/4 below 5. + - Ultra SCSI data transfers. + - Offset 16. + + Works with my configuration. However I cannot test Ultra transfers, + since my disks are only fast scsi-2. + +Tue Nov 28 21:00 1996 Gerard Roudier (groudier@club-internet.fr) + * ncr53c8xx.c + I received yesterday my Promise SCSI Ultra board. + NCR53C875 rev. 3 with clock doubler. + Add the code to support some bus features, the large 536 dma fifo and + burst 128. Works. + +Mon Nov 4 21:00 1996 Gerard Roudier (groudier@club-internet.fr) + * ncr53c8xx.c ncr53c8xx.h - revision 1.14c + Severall control command improvements: + + - Allow to specify "all" to commands that apply to #target. + For example: "setsync all 255" sets asynchronous data + transfers for all targets on a bus. + + - Allow to control disconnection privilege per device, as follow: + "setflag #target no_sync" disables disconnection for #target. + "setflag #target" with no flag specified reenables it. + + Obviously #target may be specified as "all" in order to control + disconnection for all targets with a single control command. + + - README file updated and some hints about SCSI problems solving added. + +Sun Oct 27 22:00 1996 Gerard Roudier (groudier@club-internet.fr) + * ncr53c8xx.c ncr53c8xx.h - revision 1.14b + Add the following config parameters: + + - CONFIG_SCSI_NCR53C8XX_MAX_TAGS + Max number of queued tagged commands. + Allow from 2 to 12, default 4. + + - CONFIG_SCSI_NCR53C8XX_SYNC + Synchronous transfers frequency in MHz. + Allow from 5 to 10, default 5, 0 means asynchronous. + (And so remove CONFIG_SCSI_NCR53C8XX_FORCE_ASYNCHRONOUS) + +Sun Oct 20 16:00 1996 Gerard Roudier (groudier@club-internet.fr) + * ncr53c8xx.c + ncr_scatter() rewritten. + remove "ncr dead" detection. + +Sun Oct 13 19:00 1996 Gerard Roudier (groudier@club-internet.fr) + * ncr53c8xx.c ncr53c8xx.h - revision 1.14a + Enabling some special features makes problems with some hardware. + So, disable them by default. + Add SCSI_NCR_SPECIAL_FEATURES define to play with. + +Sun Oct 13 14:00 1996 Gerard Roudier (groudier@club-internet.fr) + * ncr53c8xx.c ncr53c8xx.h + Incorporate Stefan's patch for clock frequency detection. + (Committed in FreeBSD/ncr.c rev. 1.81). + The driver then does about the following: + Assume 40 MHz clock for all ncr chips except: + - NCR53C860 chips: + Assume 80 Mhz clock. + - NCR53C875 chips: + If clock doubler enabled, disable it and assume 40 Mhz clock. + Else if (scntl3&7)=0 measure scsi clock frequency. + Else trust bios setting of scntl3&7 (3=40 Mhz, 5=80Mhz). + +Wed Oct 9 22:00 1996 Gerard Roudier (groudier@club-internet.fr) + * ncr53c8xx.c - release 1.14 + For now, just change the clock detection as follow: + - If clock doubler selected by BIOS, assume 40 MHz clock since + clock doubler will be disabled by chip reset. + - Else if NCR53C860 assume 80 MHz clock. + - Else trust BIOS setting if (scntl3&7 >= 3) + - Else assume 40 MHz clock. + +Sat Oct 05 17:00 1996 Gerard Roudier (groudier@club-internet.fr) + * ncr53c8xx.c + Stefan sent me a patch that improves the clock frequency detection + of the driver. Stefan uses the general timer register stime1 in + order to measure as accurately as possible the scsi clock. + Works ok with my 825, but needs still testing. So will be + released later. + +Sun Sep 29 17:00 1996 Gerard Roudier (groudier@club-internet.fr) + * ncr53c8xx.c + Preserve dcntl/dmode/ctest3/ctest4 features bits at start-up. + Add the define option SCSI_NCR_TRUST_BIOS_SETTING. + - If this option is defined, the driver will preserve the + corresponding bits of io registers. + - Else, the driver will set features bits according to chip + and revision ids. + +Sun Sep 22 17:00 1996 Gerard Roudier (groudier@club-internet.fr) + * ncr53c8xx.c + Remove useless fields and code and so spare cpu: + - profile data are accumulated in jiffies ticks and converted + to milli-seconds when read through proc fs. + - when IOMAPPED is not defined, try only MMIO. + (avoid testing a value in order to choose between IO and MMIO) + +Sun Sep 01 20:00 1996 Gerard Roudier (groudier@club-internet.fr) + * ncr53c8xx.h, ncr53c8xx.c - Version 1.13 + Adaptation of the tagged command queuing depth control of the + FreeBSD driver to Linux. Now, tagged command queueing can be + disabled at run time by a "settags N 0" control command. + Add the following heuristic in order to manage intelligently (perhaps) + QUEUE_FULL status: + - Each time a QUEUE FULL status is returned by a device, disable tagged + command queuing for that device. + - Every 100 successfully complete commands, increment the maximum + queuable commands (up to the allowed limit). + Fri Aug 30 10:00 1996 Gerard Roudier (groudier@club-internet.fr) * ncr53c8xx.c - Version 1.12c Incorporate the changes of FreeBSD/ncr.c revision 1.76. diff --git a/drivers/scsi/Config.in b/drivers/scsi/Config.in index 1c6328fc99d3..7f65b6314e51 100644 --- a/drivers/scsi/Config.in +++ b/drivers/scsi/Config.in @@ -21,10 +21,13 @@ dep_tristate 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 $CONFIG_SCSI dep_tristate 'Adaptec AIC7xxx support' CONFIG_SCSI_AIC7XXX $CONFIG_SCSI if [ "$CONFIG_SCSI_AIC7XXX" != "n" ]; then bool ' Enable tagged command queueing' CONFIG_AIC7XXX_TAGGED_QUEUEING Y - int ' Maximum number of commands per LUN' CONFIG_AIC7XXX_CMDS_PER_LUN 8 + dep_tristate ' Override driver defaults for commands per LUN' CONFIG_OVERRIDE_CMDS N + if [ "$CONFIG_OVERRIDE_CMDS" != "n" ]; then + int ' Maximum number of commands per LUN' CONFIG_AIC7XXX_CMDS_PER_LUN 8 + fi bool ' Enable SCB paging' CONFIG_AIC7XXX_PAGE_ENABLE N bool ' Collect statistics to report in /proc' CONFIG_AIC7XXX_PROC_STATS N - int ' delay in seconds after SCSI bus reset' CONFIG_AIC7XXX_RESET_DELAY 15 + int ' Delay in seconds after SCSI bus reset' CONFIG_AIC7XXX_RESET_DELAY 15 fi dep_tristate 'AdvanSys SCSI support' CONFIG_SCSI_ADVANSYS $CONFIG_SCSI dep_tristate 'Always IN2000 SCSI support' CONFIG_SCSI_IN2000 $CONFIG_SCSI @@ -62,15 +65,17 @@ fi if [ "$CONFIG_PCI" = "y" -a "$CONFIG_SCSI_NCR53C7xx" != "y" ]; then dep_tristate 'NCR53C8XX SCSI support' CONFIG_SCSI_NCR53C8XX $CONFIG_SCSI if [ "$CONFIG_SCSI_NCR53C8XX" != "n" ]; then + bool ' detect and read serial NVRAMs' CONFIG_SCSI_NCR53C8XX_NVRAM_DETECT bool ' enable tagged command queueing' CONFIG_SCSI_NCR53C8XX_TAGGED_QUEUE - bool ' force normal IO' CONFIG_SCSI_NCR53C8XX_IOMAPPED - bool ' not allow targets to disconnect' CONFIG_SCSI_NCR53C8XX_NO_DISCONNECT - bool ' force asynchronous transfer mode' CONFIG_SCSI_NCR53C8XX_FORCE_ASYNCHRONOUS - bool ' force synchronous negotiation' CONFIG_SCSI_NCR53C8XX_FORCE_SYNC_NEGO - fi - if [ "$CONFIG_SCSI_NCR53C8XX" != "n" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then - bool ' disable master parity checking' CONFIG_SCSI_NCR53C8XX_DISABLE_MPARITY_CHECK - bool ' disable scsi parity checking' CONFIG_SCSI_NCR53C8XX_DISABLE_PARITY_CHECK + bool ' use normal IO' CONFIG_SCSI_NCR53C8XX_IOMAPPED + int ' maximum number of queued commands' CONFIG_SCSI_NCR53C8XX_MAX_TAGS 4 + int ' synchronous transfers frequency in MHz' CONFIG_SCSI_NCR53C8XX_SYNC 5 + if [ "$CONFIG_SCSI_NCR53C8XX_TAGGED_QUEUE" != "y" ]; then + bool ' not allow targets to disconnect' CONFIG_SCSI_NCR53C8XX_NO_DISCONNECT + fi + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool ' assume boards are SYMBIOS compatible' CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT + fi fi fi dep_tristate 'IOMEGA Parallel Port ZIP drive SCSI support' CONFIG_SCSI_PPA $CONFIG_SCSI @@ -80,6 +85,9 @@ if [ "$CONFIG_PCI" = "y" ]; then dep_tristate 'Qlogic ISP SCSI support' CONFIG_SCSI_QLOGIC_ISP $CONFIG_SCSI fi dep_tristate 'Seagate ST-02 and Future Domain TMC-8xx SCSI support' CONFIG_SCSI_SEAGATE $CONFIG_SCSI +if [ "$CONFIG_PCI" = "y" -a "$CONFIG_SCSI_AM53C974" != "y" ]; then + dep_tristate 'Tekram DC-390(T) SCSI support' CONFIG_SCSI_DC390T $CONFIG_SCSI +fi dep_tristate 'Trantor T128/T128F/T228 SCSI support' CONFIG_SCSI_T128 $CONFIG_SCSI dep_tristate 'UltraStor 14F/34F support' CONFIG_SCSI_U14_34F $CONFIG_SCSI if [ "$CONFIG_SCSI_U14_34F" != "n" ]; then diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index e2cfe6793fee..0b1559d3c1e2 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -178,6 +178,14 @@ else endif endif +ifeq ($(CONFIG_SCSI_DC390T),y) +L_OBJS += tmscsim.o +else + ifeq ($(CONFIG_SCSI_DC390T),m) + M_OBJS += tmscsim.o + endif +endif + ifeq ($(CONFIG_SCSI_AM53C974),y) L_OBJS += AM53C974.o else @@ -380,6 +388,9 @@ aic7xxx.o: aic7xxx.c aic7xxx_seq.h aic7xxx_reg.h seagate.o: seagate.c $(CC) $(CFLAGS) -DARBITRATE -DSLOW_HANDSHAKE -DFAST32 -c seagate.c +tmscsim.o : tmscsim.c + $(CC) $(CFLAGS) -c tmscsim.c + 53c8xx_d.h 53c8xx_u.h : 53c7,8xx.scr script_asm.pl ln -sf 53c7,8xx.scr fake.c $(CPP) -traditional -DCHIP=810 fake.c | grep -v '^#' | perl script_asm.pl diff --git a/drivers/scsi/README.ncr53c8xx b/drivers/scsi/README.ncr53c8xx index 34ba6360680c..1acf9887f377 100644 --- a/drivers/scsi/README.ncr53c8xx +++ b/drivers/scsi/README.ncr53c8xx @@ -1,10 +1,10 @@ -The linux NCR53C8XX driver README file +The Linux NCR53C8XX driver README file Written by Gerard Roudier 21 Rue Carnot 95170 DEUIL LA BARRE - FRANCE -12 June 1995 +19 June 1997 =============================================================================== 1. Introduction @@ -21,15 +21,31 @@ Written by Gerard Roudier 8.4 Set order type for tagged command 8.5 Set debug mode 8.6 Clear profile counters + 8.7 Set flag (no_sync) + 8.8 Debug error recovery 9. Configuration parameters -10. Some constants and flags of the ncr53c8xx.h header files -11. Provided files -12. Installation procedure for Linux version 1 -13. Installation procedure for Linux version 2 -14. Control commands under linux-1.2.13 -15. Known problems - 15.1 Tagged commands with Iomega Jaz device - 15.2 Tagged command queueing cannot be disabled at run time +10. Boot setup commands + 10.1 Syntax + 10.2 Available arguments + 10.3 Advised boot setup commands + 10.4 PCI configuration fix-up boot option + 10.5 Serial NVRAM support boot option +11. Some constants and flags of the ncr53c8xx.h header file +12. Installation + 12.1 Provided files + 12.2 Installation procedure +13. Control commands under linux-1.2.13 +14. Known problems + 14.1 Tagged commands with Iomega Jaz device + 14.2 Device names change when another controller is added +15. SCSI problem troubleshooting +16. Synchonous transfer negotiation tables + 16.1 Synchronous timings for 53C875 and 53C860 Ultra-SCSI controllers + 16.2 Synchronous timings for fast SCSI-2 53C8XX controllers +17. Serial NVRAM support (by Richard Waltham) + 17.1 Features + 17.2 Symbios NVRAM layout + 17.3 Tekram NVRAM layout =============================================================================== @@ -43,21 +59,37 @@ The original driver has been written for 386bsd and FreeBSD by: Wolfgang Stanglmeier Stefan Esser -You can find technical information about the NCR 8xx family in the PCI-HOWTO -written by Michael Will and in the SCSI-HOWTO written by Drew Eckhardt. +You can find technical information about the NCR 8xx family in the +PCI-HOWTO written by Michael Will and in the SCSI-HOWTO written by +Drew Eckhardt. Information about new chips is available at SYMBIOS web server: - http://www.symbios.com -This short documentation only describes the features of the NCR53C8XX driver, -configuration parameters and control commands available through the proc SCSI -file system read / write operations. + http://www.symbios.com/ -This driver has been tested OK with linux/i386 and is currently untested -under linux/Alpha. If you intend to use this driver under linux/Alpha, just -try it first with read-only or mounted read-only devices. +SCSI standard documentations are available at SYMBIOS ftp server: -I am not a native speaker of English and there are probably lots of + ftp://ftp.symbios.com/ + +Usefull SCSI tools written by Eric Youngdale are available at tsx-11: + + ftp://tsx-11.mit.edu/pub/linux/ALPHA/scsi/scsiinfo-X.Y.tar.gz + ftp://tsx-11.mit.edu/pub/linux/ALPHA/scsi/scsidev-X.Y.tar.gz + +These tools are not ALPHA but quite clean and work quite well. +It is essential you have the 'scsiinfo' package. + +This short documentation only describes the features of the NCR53C8XX +driver, configuration parameters and control commands available +through the proc SCSI file system read / write operations. + +This driver has been tested OK with linux/i386 and Linux/Alpha. + +Latest driver version and patches are available at: + + ftp://linux.wauug.org/pub/roudier + +I am not a native speaker of English and there are probably lots of mistakes in this README file. Any help will be welcome. @@ -71,8 +103,8 @@ The following features are supported for all chips: SCSI parity checking Master parity checking -"Wide negotiation" is supported for chips that allow it. -The following table shows some characteristics of NCR 8xx family chips: +"Wide negotiation" is supported for chips that allow it. The +following table shows some characteristics of NCR 8xx family chips: On board Supported by Tested with Chip SDMS BIOS Wide Ultra SCSI the driver the driver @@ -81,12 +113,12 @@ Chip SDMS BIOS Wide Ultra SCSI the driver the driver 810A N N N Y Y 815 Y N N Y Y 825 Y Y N Y Y -825A Y Y N Y Not yet -875 Y Y Y(1) Y Not yet - -(1) Ultra SCSI extensions will be supported in a future release of the - driver. +825A Y Y N Y Y +860 N N Y Y Y +875 Y Y Y Y Y +895 Y Y Y(1) Y not yet +(1) The 895 chip is supported 'on paper'. 3. Summary of other supported features. @@ -97,45 +129,58 @@ Chip SDMS BIOS Wide Ultra SCSI the driver the driver Debugging information: written to syslog (expert only) Scatter / gather Shared interrupt + Boot setup commands + Serial NVRAM: Symbios and Tekram formats 4. Memory mapped I/O versus normal I/O -Memory mapped I/O has less latency than normal I/O. -Since linux-1.3.x, memory mapped I/O is used rather than normal I/O. -Memory mapped I/O seems to work fine on most hardware configurations, but some -poorly designed motherboards may break this feature. +Memory mapped I/O has less latency than normal I/O. Since +linux-1.3.x, memory mapped I/O is used rather than normal I/O. Memory +mapped I/O seems to work fine on most hardware configurations, but +some poorly designed motherboards may break this feature. -During the initialization phase, the driver first tries to use memory mapped -I/O. If nothing seems wrong, it will use memory mapped I/O. -If a flaw is detected, it will use normal I/O. - -However, it's possible that memory mapped I/O does not work properly and the -driver has not detected the problem. - -The configuration option CONFIG_SCSI_NCR53C8XX_IOMAPPED forces the +The configuration option CONFIG_SCSI_NCR53C8XX_IOMAPPED forces the driver to use normal I/O in all cases. 5. Tagged command queueing -Some SCSI devices do not properly support tagged command queuing. -A safe configuration is to not enable tagged command queuing support at -boot-up, and to enable support of it with the control command "settags" -described further in this text. +Some SCSI devices do not properly support tagged command queuing. A +safe configuration is to not enable tagged command queuing support at +boot-up, and to enable support of it with the control command +"settags" described further in this text. + +Once you are sure that all your devices properly support tagged +command queuing, you can enable it by default with the +CONFIG_SCSI_NCR53C8XX_TAGGED_QUEUE configuration option. + +The maximum number of simultaneous tagged commands queued to a device +is currently set to 4 by default. It is defined in the file +ncr53c8xx.h by SCSI_NCR_MAX_TAGS. This value is suitable for most SCSI +disks. With large SCSI disks (> 2GB, cache > 512KB average seek time +< 10 ms), 8 tagged commands may give better performance. + +In some special conditions, some SCSI disk firmwares may return a +QUEUE FULL status for a SCSI command. This behaviour is managed by the +driver by the following heuristic: -Once you are sure that all your devices properly support tagged command queuing, -you can enable it by default with the CONFIG_SCSI_NCR53C8XX_TAGGED_QUEUE -configuration option. +- Each time a QUEUE FULL status is returned, tagged command queueing is + temporarily disabled. + +- Every 100 successfully completed SCSI commands, if allowed by the + current limit, the maximum number of queueable commands is + incremented and tagged command queueing is reenabled. 6. Parity checking -The driver supports SCSI parity checking and PCI bus master parity checking. -These features must be enabled in order to ensure safe data transfers. -However, some flawed devices or mother boards will have problems with -parity. You can disable parity by choosing first "CONFIG_EXPERIMENTAL". -Then, "make config" will allow to set the following configuration options: +The driver supports SCSI parity checking and PCI bus master parity +checking. These features must be enabled in order to ensure safe data +transfers. However, some flawed devices or mother boards will have +problems with parity. You can disable parity by choosing first +"CONFIG_EXPERIMENTAL". Then, "make config" will allow to set the +following configuration options: CONFIG_SCSI_NCR53C8XX_DISABLE_PARITY_CHECK (disable SCSI parity checking) CONFIG_SCSI_NCR53C8XX_DISABLE_MPARITY_CHECK (disable master parity checking) @@ -145,16 +190,19 @@ Then, "make config" will allow to set the following configuration options: Profiling information is available through the proc SCSI file system. The device associated with a host has the following pathname: + /proc/scsi/ncr53c8xx/N (N=0,1,2 ....) Generally, only 1 board is used on hardware configuration, and that device is: /proc/scsi/ncr53c8xx/0 -However, if the driver has been made as module, the number of the hosts is -incremented each time the driver is loaded. +However, if the driver has been made as module, the number of the +hosts is incremented each time the driver is loaded. In order to display profiling information, just enter: + cat /proc/scsi/ncr53c8xx/0 + and you will get something like the following text: ------------------------------------------------------- @@ -162,6 +210,7 @@ General information: Chip NCR53C810, device id 0x1, revision id 0x2 IO port address 0x6000, IRQ number 10 Using memory mapped IO at virtual address 0x282c000 + Synchronous transfer period 25, max commands per lun 4 Profiling information: num_trans = 18014 num_kbytes = 671314 @@ -175,7 +224,7 @@ Profiling information: ms_post = 1320 ------------------------------------------------------- -General information is easy to understand. The device ID and the +General information is easy to understand. The device ID and the revision ID identify the SCSI chip as follows: Chip Device id Revision Id @@ -187,15 +236,18 @@ Chip Device id Revision Id 860 0x6 825A 0x3 >= 0x10 875 0xf +895 0xc The profiling information is updated upon completion of SCSI commands. -A data structure is allocated and zeroed when the host adapter is -attached. So, if the driver is a module, the profile counters are cleared each -time the driver is loaded. -The "clearprof" command allows you to clear these counters at any time. +A data structure is allocated and zeroed when the host adapter is +attached. So, if the driver is a module, the profile counters are +cleared each time the driver is loaded. The "clearprof" command +allows you to clear these counters at any time. The following counters are available: -("num" prefix means "number of", "ms" means milli-seconds) + +("num" prefix means "number of", +"ms" means milli-seconds) num_trans Number of completed commands @@ -238,46 +290,43 @@ ms_post (time from SCSI status get to command completion call) Example above: 1.32 seconds spent for post processing -Due to the 1/100 second tick of the system clock, "ms_post" time may be -wrong. - -In the example above, we got 18038 interrupts "on the fly" and only 1673 script -breaks probably due to disconnections inside a segment of the scatter list. -This is an excellent result due to the fact that the driver tries to use small -data segments (512) for the scatter list. The CPU load of this rescatter process -is acceptable. Unlike other SCSI processors, NCR53C8XX controllers do not need -large data chunks in order to get better performance, and it seems that it -is just the opposite. -The scatter/gather algorithm of the middle SCSI driver is not optimal for -NCR SCSI processors and should be tunable according to host type. - -You can tune the "wished" segment size for the scatterlist by changing the -following "define" in the file ncr53c8xx.h. -Use only power of 2 greater than 512 (1024, 2048 or 4096). +Due to the 1/100 second tick of the system clock, "ms_post" time may +be wrong. -SCSI_NCR_SEGMENT_SIZE (default: 512) +In the example above, we got 18038 interrupts "on the fly" and only +1673 script breaks generally due to disconnections inside a segment +of the scatter list. 8. Control commands -Control commands can be sent to the driver with write operations to the -proc SCSI file system. The generic command syntax is the following: +Control commands can be sent to the driver with write operations to +the proc SCSI file system. The generic command syntax is the +following: echo " " >/proc/scsi/ncr53c8xx/0 (assumes controller number is 0) +Using "all" for "" parameter with the commands below will +apply to all targets of the SCSI chain (except the controller). + Available commands: -8.1 Set minimum synchronous period +8.1 Set minimum synchronous period factor - setsync + setsync target: target number - period: minimum synchronous period in nano-seconds. - Maximum speed = 1000/(4*period) MB/second + period: minimum synchronous period. + Maximum speed = 1000/(4*period factor) except for special + cases below. Specify a period of 255, to force asynchronous transfer mode. + 10 means 25 nano-seconds synchronous period + 11 means 30 nano-seconds synchronous period + 12 means 50 nano-seconds synchronous period + 8.2 Set wide size setwide @@ -292,7 +341,6 @@ Available commands: target: target number tags: number of concurrent tagged commands must not be greater than SCSI_NCR_MAX_TAGS (default: 4) - must not be lower that 1 (see: known problems) 8.4 Set order type for tagged command @@ -321,23 +369,63 @@ Available commands: nego: print information about SCSI negotiations phase: print information on script interruptions + Use "setdebug" with no argument to reset debug flags. + 8.6 Clear profile counters clearprof - The profile counters are automatically cleared when the amount of data - transfered reaches 1000 GB in order to avoid overflow. + The profile counters are automatically cleared when the amount of + data transfered reaches 1000 GB in order to avoid overflow. The "clearprof" command allows you to clear these counters at any time. +8.7 Set flag (no_sync) + + setflag + + target: target number + + For the moment, only one flag is available: + + no_sync: not allow target to disconnect. + + Do not specify any flag in order to reset the flag. For example: + - setflag 4 + will reset no_sync flag for target 4, so will allow it disconnections. + - setflag all + will allow disconnection for all devices on the SCSI bus. + + +8.8 Debug error recovery + + debug_error_recovery + + Available error type to trigger: + sge: SCSI gross error + abort: abort command from the middle-level driver + reset: reset command from the middle-level driver + parity: scsi parity detected in DATA IN phase + none: restore driver normal behaviour + + The code corresponding to this feature is normally not compiled. + Its purpose is driver testing only. In order to compile the code + that allows to trigger error recovery you must define at compile time + SCSI_NCR_DEBUG_ERROR_RECOVERY. + If you have compiled the driver with this option, nothing will happen + as long as you donnot use the control command 'debug_error_recovery' + with sge, abort, reset or parity as argument. + If you select an error type, it will be triggered by the driver every + 30 seconds. + 9. Configuration parameters -If the firmware of all your devices is perfect enough, all the features -supported by the driver can be enabled at start-up. -However, if only one has a flaw for some SCSI feature, you can disable the -support by the driver of this feature at linux start-up and enable this -feature after boot-up only for devices that support it safely. +If the firmware of all your devices is perfect enough, all the +features supported by the driver can be enabled at start-up. However, +if only one has a flaw for some SCSI feature, you can disable the +support by the driver of this feature at linux start-up and enable +this feature after boot-up only for devices that support it safely. CONFIG_SCSI_NCR53C8XX_IOMAPPED (default answer: n) Answer "y" if you suspect your mother board to not allow memory mapped I/O. @@ -347,9 +435,16 @@ CONFIG_SCSI_NCR53C8XX_TAGGED_QUEUE (default answer: n) Answer "y" if you are sure that all your SCSI devices that are able to accept tagged commands will proceed safely. -CONFIG_SCSI_NCR53C8XX_FORCE_ASYNCHRONOUS (default answer: n) - This option forces asynchronous transfer mode for all SCSI devices. - +CONFIG_SCSI_NCR53C8XX_MAX_TAGS (default answer: 4) + This option allows you to specify the maximum number of tagged commands + that can be queued to a device. + +CONFIG_SCSI_NCR53C8XX_SYNC (default answer: 5) + This option allows you to specify the frequency in MHz the driver + will use at boot time for synchronous data transfer negotiations. + This frequency can be changed later with the "setsync" control command. + 0 means "asynchronous data transfers". + CONFIG_SCSI_NCR53C8XX_FORCE_SYNC_NEGO (default answer: n) Force synchronous negotiation for all SCSI-2 devices. Some SCSI-2 devices do not report this feature in byte 7 of inquiry @@ -360,12 +455,331 @@ CONFIG_SCSI_NCR53C8XX_NO_DISCONNECT (default and only reasonnable answer: n) you can answer "y". Then, all SCSI devices will never disconnect the bus even while performing long SCSI operations. +CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT + Genuine SYMBIOS boards use GPIO0 in output for controller LED and GPIO3 + bit as a flag indicating singled-ended/differential interface. + If all the boards of your system are genuine SYMBIOS boards or use + BIOS and drivers from SYMBIOS, you would want to enable this option. + This option must NOT be enabled if your system has at least one 53C8XX + based scsi board with a vendor-specific BIOS. + For example, Tekram DC-390/U, DC-390/W and DC-390/F scsi controllers + use a vendor-specific BIOS and are known to not use SYMBIOS compatible + GPIO wiring. So, this option must not be enabled if your system has + such a board installed. + +CONFIG_SCSI_NCR53C8XX_NVRAM_DETECT + Enable support for reading the serial NVRAM data on Symbios and + some Symbios compatible cards, and Tekram DC390W/U/F cards. Useful for + systems with more than one Symbios compatible controller where at least + one has a serial NVRAM, or for a system with a mixture of Symbios and + Tekram cards. Enables setting the boot order of host adaptors + to something other than the default order or "reverse probe" order. + Also enables Symbios and Tekram cards to be distinguished so + CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT may be set in a system with a + mixture of Symbios and Tekram cards so the Symbios cards can make use of + the full range of Symbios features, differential, led pin, without + causing problems for the Tekram card(s). + +10. Boot setup commands + +10.1 Syntax + +Setup commands can be passed to the driver at boot time. +A boot setup command for the ncr53c8xx driver begins with the driver name +"ncr53c8xx=". The kernel syntax parser then expects an optionnal list of +integers separated with comma followed by an optionnal list of comma- +separated strings. Example of boot setup command under lilo prompt: + +lilo: linux root=/dev/hda2 ncr53c8xx=tags:4,sync:10,debug:0x200 + +- enable tagged commands, up to 4 tagged commands queued. +- set synchronous negotiation speed to 10 Mega-transfers / second. +- set DEBUG_NEGO flag. + +For the moment, the integer list of arguments is disgarded by the driver. +It will be used in the future in order to allow a per controller setup. + +Each string argument must be specified as "keyword:value". Only lower-case +characters and digits are allowed. + +10.2 Available arguments + +Master parity checking + mpar:y enabled + mpar:n disabled + +Scsi parity checking + spar:y enabled + spar:n disabled + +Scsi disconnections + disc:y enabled + disc:n disabled + +Special features + Only apply to 810A, 825A, 860 and 875 controllers. + Have no effect with normal 810 and 825. + specf:y enabled + specf:n disabled + +Ultra SCSI support + Only apply to 860 and 875 controllers. + Have no effect with other ones. + ultra:y enabled + ultra:n disabled + +Number of tagged commands + tags:0 (or tags:1 ) tagged command queuing disabled + tags:#tags (#tags > 1) tagged command queuing enabled + #tags will be truncated to the max queued commands configuration parameter. + If the driver is configured with a maximum of 4 queued commands, tags:4 is + the right argument to specify. + +Default synchronous period factor + sync:255 disabled (asynchronous transfer mode) + sync:#factor + #factor = 10 Ultra-2 SCSI 40 Mega-transfers / second + #factor = 11 Ultra-2 SCSI 33 Mega-transfers / second + #factor < 25 Ultra SCSI 20 Mega-transfers / second + #factor < 50 Fast SCSI-2 + + In all cases, the driver will use the minimum transfer period supported by + controllers according to NCR53C8XX chip type. + +Negotiate synchronous with all devices + (force sync nego) + fsn:y enabled + fsn:n disabled + +Verbosity level + verb:0 minimal + verb:1 normal + verb:2 too much + +Debug mode + debug:0 clear debug flags + debug:#x set debug flags + #x is an integer value combining the following power-of-2 values: + DEBUG_ALLOC 0x1 + DEBUG_PHASE 0x2 + DEBUG_POLL 0x4 + DEBUG_QUEUE 0x8 + DEBUG_RESULT 0x10 + DEBUG_SCATTER 0x20 + DEBUG_SCRIPT 0x40 + DEBUG_TINY 0x80 + DEBUG_TIMING 0x100 + DEBUG_NEGO 0x200 + DEBUG_TAGS 0x400 + DEBUG_FREEZE 0x800 + DEBUG_RESTART 0x1000 + + You can play safely with DEBUG_NEGO. However, some of these flags may + generate bunches of syslog messages. + +Burst max + burst:0 burst disabled + burst:255 get burst length from initial IO register settings. + burst:#x burst enabled (1<<#x burst transfers max) + #x is an integer value which is log base 2 of the burst transfers max. + The NCR53C875 and NCR53C825A support up to 128 burst transfers (#x = 7). + Other chips only support up to 16 (#x = 4). + This is a maximum value. The driver set the burst length according to chip + and revision ids. By default the driver uses the maximum value supported + by the chip. + +LED support + led:1 enable LED support + led:0 disable LED support + Donnot enable LED support if your scsi board does not use SDMS BIOS. + (See 'Configuration parameters') + +Max wide + wide:1 wide scsi enabled + wide:0 wide scsi disabled + Some scsi boards use a 875 (ultra wide) and only supply narrow connectors. + If you have connected a wide device with a 50 pins to 68 pins cable + converter, any accepted wide negotiation will break further data transfers. + In such a case, using "wide:0" in the bootup command will be helpfull. + +Differential mode + diff:0 never set up diff mode + diff:1 set up diff mode if BIOS set it + diff:2 always set up diff mode + diff:3 set diff mode if GPIO3 is not set + +IRQ mode + irqm:0 always open drain + irqm:1 same as initial settings (assumed BIOS settings) + irqm:2 always totem pole + +Reverse probe + revprob:n probe chip ids from the PCI configuration in this order: + 810, 815, 820, 860, 875, 885, 895, 896 + revprob:y probe chip ids in the reverse order. + +Fix up PCI configuration space + pcifix: