Commit 61cb5dec authored by Linus Torvalds's avatar Linus Torvalds

Linux 2.1.98

I just released a fairly small patch to 97 to bring it up to 98.

I've gotten a lot of patches in the mail for the last week, and I've been
ignoring most of them for obvious reasons. They aren't in any in-queue,
you can more-or-less consider them lost - but don't resend them all
immediately, because if I get another huge batch of patches then I'll just
have to ignore them again.

We're going slow and easy, and the plan is to not only keep me sane in the
midst of all the diapers, but I'll also at the same time take the
opportunity to actually enforce the feature-freeze. You've known about it
for a long time, _tough_.

Anyway, 2.1.98 _should_ fix:

 - the IDE/SCSI lockups. The irq enable/disable code was broken, and could
   do some really bad things. This tended to lock up the machine if you
   accessed your IDE disks heavily, or in particular if you had a mixture
   of IDE and SCSI and used them at the same time. Tell me if you still
   have problems - I'm sure there are still bugs left, and I want to hear
   about them.
 - memory management especially on small-memory machines. I think I made a
   good change to the allocation logic, and I'm hoping it will fix the bad
   bahevaiour on those wimpy machines that all you losers out there are
   using that have less than half a Gig of RAM. It certainly still works
   fine on my machine, and I'm certainly still too lazy to test it out on
   anything smaller.

There's a few other updates too: the asm constraints are fixed, so it
should compile again with other compiler versions than the particular one
I happen to be using. And some of the SCSI drivers have been updated a
bit.

There's been a lot of discussion and patches on capabilities, and I
haven't applied them yet, I'll let them simmer a bit. Similarly, I've seen
so many pathes to kmod that my head is spinning, and as I don't use
modules myself I'd really like to get feedback from users about the
different patches, so that maybe I'll get something that everybody can
agree on as acceptable. Right now I don't know which patch I should even
begin looking at.

                Linus
parent 5d2e518d
VERSION = 2
PATCHLEVEL = 1
SUBLEVEL = 97
SUBLEVEL = 98
ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/)
......
......@@ -37,11 +37,9 @@ OLD_GAS := $(shell if cat ./GAS_VER | grep 'version 2.7' > /dev/null; then echo
$(shell rm -f ./GAS_VER)
ifneq ($(OLD_GAS),yes)
CFLAGS := $(CFLAGS) -Wa,-m21164a -DBWX_USABLE
# if PYXIS, then enable use of BWIO space
ifeq ($(CONFIG_ALPHA_PYXIS),y)
CFLAGS := $(CFLAGS) -DBWIO_ENABLED
CFLAGS := $(CFLAGS) -Wa,-m21164a -DBWX_USABLE -DBWIO_ENABLED
endif
endif
......
......@@ -337,7 +337,7 @@ int get_irq_list(char *buf)
if (IO_APIC_IRQ(i))
p += sprintf(p, " IO-APIC ");
else
p += sprintf(p, " XT PIC ");
p += sprintf(p, " XT-PIC ");
p += sprintf(p, " %s", action->name);
for (action=action->next; action; action = action->next) {
......@@ -669,7 +669,6 @@ void disable_irq(unsigned int irq)
*/
static void disable_8259A_irq(unsigned int irq)
{
disabled_irq[irq]++;
cached_irq_mask |= 1 << irq;
set_8259A_irq_mask(irq);
}
......@@ -677,7 +676,7 @@ static void disable_8259A_irq(unsigned int irq)
#ifdef __SMP__
static void disable_ioapic_irq(unsigned int irq)
{
disabled_irq[irq]++;
disabled_irq[irq] = 1;
/*
* We do not disable IO-APIC irqs in hardware ...
*/
......@@ -688,12 +687,6 @@ void enable_8259A_irq (unsigned int irq)
{
unsigned long flags;
spin_lock_irqsave(&irq_controller_lock, flags);
if (disabled_irq[irq])
disabled_irq[irq]--;
else {
spin_unlock_irqrestore(&irq_controller_lock, flags);
return;
}
cached_irq_mask &= ~(1 << irq);
set_8259A_irq_mask(irq);
spin_unlock_irqrestore(&irq_controller_lock, flags);
......@@ -706,13 +699,8 @@ void enable_ioapic_irq (unsigned int irq)
int cpu = smp_processor_id();
spin_lock_irqsave(&irq_controller_lock, flags);
if (disabled_irq[irq])
disabled_irq[irq]--;
else {
spin_unlock_irqrestore(&irq_controller_lock, flags);
return;
}
#if 0
disabled_irq[irq] = 0;
/*
* In the SMP+IOAPIC case it might happen that there are an unspecified
* number of pending IRQ events unhandled. These cases are very rare,
......@@ -720,7 +708,7 @@ void enable_ioapic_irq (unsigned int irq)
* better to do it this way as thus we dont have to be aware of
* 'pending' interrupts in the IRQ path, except at this point.
*/
if (!disabled_irq[irq] && irq_events[irq]) {
if (irq_events[irq]) {
if (!ipi_pending[irq]) {
ipi_pending[irq] = 1;
--irq_events[irq];
......@@ -728,36 +716,6 @@ void enable_ioapic_irq (unsigned int irq)
}
}
spin_unlock_irqrestore(&irq_controller_lock, flags);
#else
if (!disabled_irq[irq] && irq_events[irq]) {
struct pt_regs regs; /* FIXME: these are fake currently */
disabled_irq[irq]++;
hardirq_enter(cpu);
spin_unlock(&irq_controller_lock);
release_irqlock(cpu);
while (test_bit(0,&global_irq_lock)) mb();
again:
handle_IRQ_event(irq, &regs);
spin_lock(&irq_controller_lock);
disabled_irq[irq]--;
should_handle_irq=0;
if (--irq_events[irq] && !disabled_irq[irq]) {
should_handle_irq=1;
disabled_irq[irq]++;
}
spin_unlock(&irq_controller_lock);
if (should_handle_irq)
goto again;
irq_exit(cpu, irq);
__restore_flags(flags);
} else
spin_unlock_irqrestore(&irq_controller_lock, flags);
#endif
}
#endif
......
......@@ -21,7 +21,6 @@
* applications that require more DP ram, we can expand the boundaries
* but then we have to be careful of any downloaded microcode.
*/
#include <linux/config.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
......
......@@ -21,7 +21,6 @@
* small packets.
*
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
......
#include <linux/config.h>
#include "../kernel/ppc_defs.h"
#include "../kernel/ppc_asm.tmpl"
#include <asm/processor.h>
......
......@@ -13,6 +13,7 @@
*/
#define __KERNEL_SYSCALLS__
#include <linux/config.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
......
......@@ -12,6 +12,7 @@
*
*/
#include <linux/config.h>
#include <linux/sys.h>
#include <asm/unistd.h>
#include <asm/errno.h>
......
......@@ -12,6 +12,7 @@
* 2 of the License, or (at your option) any later version.
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/delay.h>
......
......@@ -12,6 +12,7 @@
* 2 of the License, or (at your option) any later version.
*/
#include <linux/config.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/proc_fs.h>
......
......@@ -25,7 +25,6 @@
#include <linux/user.h>
#include <linux/a.out.h>
#include <linux/interrupt.h>
#include <linux/config.h>
#include <asm/pgtable.h>
#include <asm/uaccess.h>
......
......@@ -19,6 +19,7 @@
* creating a software PLL, I have set HZ to 128. -- Dan
*/
#include <linux/config.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
......
......@@ -4,7 +4,6 @@
* Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
*/
#include <linux/config.h> /* for CONFIG_PROFILE */
#include <asm/head.h>
#include <linux/kernel.h>
......
......@@ -9,7 +9,6 @@
* Copyright (C) 1996 Dave Redman (djhr@tadpole.co.uk)
*/
#include <linux/config.h>
#include <linux/ptrace.h>
#include <linux/errno.h>
#include <linux/linkage.h>
......
......@@ -1118,10 +1118,9 @@ struct request **ide_get_queue (kdev_t dev)
* conditions in the event that an unexpected interrupt occurs while
* we are in the driver.
*
* Note that when an interrupt is used to reenter the driver, the first level
* handler will already have masked the irq that triggered, but any other ones
* for the hwgroup will still be unmasked. The driver tries to be careful
* about such things.
* Note that the io-request lock will guarantee that the driver never gets
* re-entered even on another interrupt level, so we no longer need to
* mask the irq's.
*/
static void do_hwgroup_request (ide_hwgroup_t *hwgroup)
{
......@@ -1132,13 +1131,7 @@ static void do_hwgroup_request (ide_hwgroup_t *hwgroup)
del_timer(&hwgroup->timer);
ide_get_lock(&ide_lock, ide_intr, hwgroup);
hwgroup->active = 1;
do {
disable_irq(hwif->irq);
} while ((hwif = hwif->next) != hgif);
ide_do_request (hwgroup);
do {
enable_irq(hwif->irq);
} while ((hwif = hwif->next) != hgif);
}
}
......@@ -1274,10 +1267,6 @@ static void do_ide_intr (int irq, void *dev_id, struct pt_regs *regs)
if (!ide_ack_intr (hwif->io_ports[IDE_STATUS_OFFSET], hwif->io_ports[IDE_IRQ_OFFSET]))
return;
do {
if (!IDE_IRQ_EQUAL(irq, hwgroup->hwif->irq))
disable_irq(hwif->irq);
} while ((hwif = hwif->next) != hwgroup->hwif);
if (IDE_IRQ_EQUAL(irq, hwif->irq)
&& (handler = hwgroup->handler) != NULL) {
ide_drive_t *drive = hwgroup->drive;
......@@ -1309,10 +1298,6 @@ static void do_ide_intr (int irq, void *dev_id, struct pt_regs *regs)
}
__cli();
hwif = hwgroup->hwif;
do {
if (!IDE_IRQ_EQUAL(hwif->irq, irq))
enable_irq(hwif->irq);
} while ((hwif = hwif->next) != hwgroup->hwif);
}
/*
......
......@@ -658,7 +658,7 @@ MODULE_PARM(reset, "i");
#else
static int parport[LP_NO] __initdata = { [0 ... LP_NO-1] = LP_PARPORT_UNSPEC };
static int parport_nr[LP_NO] __initdata = { [0 ... LP_NO-1] = LP_PARPORT_UNSPEC };
static int reset __initdata = 0;
static int parport_ptr = 0;
......@@ -668,21 +668,21 @@ __initfunc(void lp_setup(char *str, int *ints))
if (!str) {
if (ints[0] == 0 || ints[1] == 0) {
/* disable driver on "lp=" or "lp=0" */
parport[0] = LP_PARPORT_OFF;
parport_nr[0] = LP_PARPORT_OFF;
} else {
printk(KERN_WARNING "warning: 'lp=0x%x' is deprecated, ignored\n", ints[1]);
}
} else if (!strncmp(str, "parport", 7)) {
int n = simple_strtoul(str+7, NULL, 10);
if (parport_ptr < LP_NO)
parport[parport_ptr++] = n;
parport_nr[parport_ptr++] = n;
else
printk(KERN_INFO "lp: too many ports, %s ignored.\n",
str);
} else if (!strcmp(str, "auto")) {
parport[0] = LP_PARPORT_AUTO;
parport_nr[0] = LP_PARPORT_AUTO;
} else if (!strcmp(str, "none")) {
parport[parport_ptr++] = LP_PARPORT_NONE;
parport_nr[parport_ptr++] = LP_PARPORT_NONE;
} else if (!strcmp(str, "reset")) {
reset = 1;
}
......
......@@ -7,6 +7,7 @@
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
*/
#include <linux/config.h>
#include <linux/errno.h>
#include <linux/signal.h>
#include <linux/sched.h>
......
......@@ -100,10 +100,6 @@ static int irq_write_proc(struct file *file, const char *buffer,
out_ok:
pp->irq = newirq;
if (oldirq != PARPORT_IRQ_NONE && newirq == PARPORT_IRQ_NONE &&
cad && cad->irq_func)
cad->irq_func(pp->irq, cad->private, NULL);
out:
return retval;
}
......
......@@ -34,7 +34,7 @@
#undef PARPORT_PARANOID
#define PARPORT_DEFAULT_TIMESLICE (HZ/10)
#define PARPORT_DEFAULT_TIMESLICE (HZ/5)
static struct parport *portlist = NULL, *portlist_tail = NULL;
static int portcount = 0;
......
......@@ -66,6 +66,7 @@ static char *version =
static char *lancestr = "LANCE";
static char *lancedma = "LANCE DMA";
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
......
......@@ -323,7 +323,7 @@ __initfunc(void pci_init(void))
pci_quirks_init();
#endif
#ifdef CONFIG_PROC
#ifdef CONFIG_PROC_FS
pci_proc_init();
#endif
}
......
......@@ -6,6 +6,7 @@
* Copyright (c) 1997, 1998 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
*/
#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/pci.h>
......
......@@ -6,6 +6,7 @@
* Copyright (C) 1998 Pavel Machek (pavel@ucw.cz)
*/
#include <linux/config.h>
#include <linux/kd.h>
#include <linux/tty.h>
#include <linux/malloc.h>
......
......@@ -46,6 +46,7 @@
*
*/
#include <linux/config.h>
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/interrupt.h>
......
......@@ -3,6 +3,7 @@
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/malloc.h>
#include <linux/init.h>
......
......@@ -1124,7 +1124,7 @@ static void BusLogic_InitializeProbeInfoList(BusLogic_HostAdapter_T
If a PCI BIOS is present, interrogate it for MultiMaster and FlashPoint
Host Adapters; otherwise, default to the standard ISA MultiMaster probe.
*/
if (!BusLogic_ProbeOptions.NoProbePCI && pcibios_present())
if (!BusLogic_ProbeOptions.NoProbePCI && pci_present())
{
if (BusLogic_ProbeOptions.MultiMasterFirst)
{
......
/*
* eata.c - Low-level driver for EATA/DMA SCSI host adapters.
*
*
* 18 Apr 1998 Rev. 4.20 for linux 2.0.33 and 2.1.97
* Reworked interrupt handler.
*
* 11 Apr 1998 rev. 4.05 for linux 2.0.33 and 2.1.95
* Major reliability improvement: when a batch with overlapping
* requests is detected, requests are queued one at a time
* eliminating any possible board or drive reordering.
*
* 10 Apr 1998 rev. 4.04 for linux 2.0.33 and 2.1.95
* Improved SMP support (if linux version >= 2.1.95).
*
......@@ -8,7 +16,7 @@
* Added support for new PCI code and IO-APIC remapping of irqs.
* Performance improvement: when sequential i/o is detected,
* always use direct sort instead of reverse sort.
*
*
* 4 Apr 1998 rev. 4.02 for linux 2.0.33 and 2.1.92
* io_port is now unsigned long.
*
......@@ -16,7 +24,6 @@
* Use new scsi error handling code (if linux version >= 2.1.88).
* Use new interrupt code.
*
*
* 12 Sep 1997 rev. 3.11 for linux 2.0.30 and 2.1.55
* Use of udelay inside the wait loops to avoid timeout
* problems with fast cpus.
......@@ -30,7 +37,7 @@
* Use of serial_number_at_timeout in abort and reset processing.
* Use of the __initfunc and __initdata macro in setup code.
* Minor cleanups in the list_statistics code.
* Increased controller busy timeout in order to better support
* Increased controller busy timeout in order to better support
* slow SCSI devices.
*
* 24 Feb 1997 rev. 3.00 for linux 2.0.29 and 2.1.26
......@@ -39,7 +46,7 @@
* Fixed data transfer direction for some SCSI opcodes.
* Immediate acknowledge to request sense commands.
* Linked commands to each disk device are now reordered by elevator
* sorting. Rare cases in which reordering of write requests could
* sorting. Rare cases in which reordering of write requests could
* cause wrong results are managed.
* Fixed spurious timeouts caused by long simple queue tag sequences.
* New command line option (tm:[0-3]) to choose the type of tags:
......@@ -105,7 +112,7 @@
*
* 28 Jan 1995 rev. 1.14 for linux 1.1.86
* Added module support.
* Log and do a retry when a disk drive returns a target status
* Log and do a retry when a disk drive returns a target status
* different from zero on a recovered error.
*
* 24 Jan 1995 rev. 1.13 for linux 1.1.85
......@@ -119,7 +126,7 @@
*
* 17 Dec 1994 rev. 1.11 for linux 1.1.74
* Use the scsicam_bios_param routine. This allows an easy
* migration path from disk partition tables created using
* migration path from disk partition tables created using
* different SCSI drivers and non optimal disk geometry.
*
* 15 Dec 1994 rev. 1.10 for linux 1.1.74
......@@ -173,10 +180,10 @@
* The DPT PM2001 provides only the EATA/PIO interface and hence is not
* supported by this driver.
*
* This code has been tested with up to 3 Distributed Processing Technology
* This code has been tested with up to 3 Distributed Processing Technology
* PM2122A/9X (DPT SCSI BIOS v002.D1, firmware v05E.0) EISA controllers,
* in any combination of private and shared IRQ.
* PCI support has been tested using up to 2 DPT PM3224W (DPT SCSI BIOS
* PCI support has been tested using up to 2 DPT PM3224W (DPT SCSI BIOS
* v003.D0, firmware v07G.0).
*
* DPT SmartRAID boards support "Hardware Array" - a group of disk drives
......@@ -186,14 +193,14 @@
*
* WARNING: to create a RAID-0 "Hardware Array" you must select "Other Unix"
* as the current OS in the DPTMGR "Initial System Installation" menu.
* Otherwise RAID-0 is generated as an "Array Group" (i.e. software RAID-0),
* Otherwise RAID-0 is generated as an "Array Group" (i.e. software RAID-0),
* which is not supported by the actual SCSI subsystem.
* To get the "Array Group" functionality, the Linux MD driver must be used
* instead of the DPT "Array Group" feature.
*
* Multiple ISA, EISA and PCI boards can be configured in the same system.
* It is suggested to put all the EISA boards on the same IRQ level, all
* the PCI boards on another IRQ level, while ISA boards cannot share
* the PCI boards on another IRQ level, while ISA boards cannot share
* interrupts.
*
* If you configure multiple boards on the same IRQ, the interrupt must
......@@ -206,7 +213,7 @@
* bus, or even if you system has no EISA bus at all.
* Do not force any ISA address on EATA PCI boards.
*
* If PCI bios support is configured into the kernel, BIOS32 is used to
* If PCI bios support is configured into the kernel, BIOS32 is used to
* include in the list of i/o ports to be probed all the PCI SCSI controllers.
*
* Due to a DPT BIOS "feature", it might not be possible to force an EISA
......@@ -215,11 +222,11 @@
*
* The sequence of detection probes is:
*
* - ISA 0x1F0;
* - ISA 0x1F0;
* - PCI SCSI controllers (only if BIOS32 is available);
* - EISA/PCI 0x1C88 through 0xFC88 (corresponding to EISA slots 1 to 15);
* - ISA 0x170, 0x230, 0x330.
*
*
* The above list of detection probes can be totally replaced by the
* boot command line option: "eata=port0,port1,port2,...", where the
* port0, port1... arguments are ISA/EISA/PCI addresses to be probed.
......@@ -261,15 +268,15 @@
* in the elevator sorting queue. When the active command completes, the
* commands in this queue are sorted by sector address. The sort is chosen
* between increasing or decreasing by minimizing the seek distance between
* the sector of the commands just completed and the sector of the first
* command in the list to be sorted.
* the sector of the commands just completed and the sector of the first
* command in the list to be sorted.
* Trivial math assures that the unsorted average seek distance when doing
* random seeks over S sectors is S/3.
* When (Q-1) requests are uniformly distributed over S sectors, the average
* distance between two adjacent requests is S/((Q-1) + 1), so the sorted
* average seek distance for (Q-1) random requests over S sectors is S/Q.
* The elevator sorting hence divides the seek distance by a factor Q/3.
* The above pure geometric remarks are valid in all cases and the
* The above pure geometric remarks are valid in all cases and the
* driver effectively reduces the seek distance by the predicted factor
* when there are Q concurrent read i/o operations on the device, but this
* does not necessarily results in a noticeable performance improvement:
......@@ -277,7 +284,7 @@
*
* Note: command reordering inside a batch of queued commands could cause
* wrong results only if there is at least one write request and the
* intersection (sector-wise) of all requests is not empty.
* intersection (sector-wise) of all requests is not empty.
* When the driver detects a batch including overlapping requests
* (a really rare event) strict serial (pid) order is enforced.
* ----------------------------------------------------------------------------
......@@ -316,7 +323,11 @@ MODULE_AUTHOR("Dario Ballabio");
#include <asm/io.h>
#include <asm/system.h>
#include <asm/byteorder.h>
#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,95)
#include <asm/spinlock.h>
#endif
#include <linux/proc_fs.h>
#include <linux/blk.h>
#include "scsi.h"
......@@ -359,7 +370,7 @@ struct proc_dir_entry proc_scsi_eata2x = {
#undef DEBUG_RESET
#define MAX_ISA 4
#define MAX_VESA 0
#define MAX_VESA 0
#define MAX_EISA 15
#define MAX_PCI 16
#define MAX_BOARDS (MAX_ISA + MAX_VESA + MAX_EISA + MAX_PCI)
......@@ -499,7 +510,7 @@ struct mssp {
unchar target_status; /* SCSI status received after data transfer */
unchar unused[2];
ulong inv_res_len; /* Number of bytes not transferred */
Scsi_Cmnd *SCpnt; /* Address set in cp */
struct mscp *cpp; /* Address set in cp */
char mess[12];
};
......@@ -515,7 +526,7 @@ struct mscp {
reqsen:1, /* Transfer Request Sense Data to addr using DMA */
sg:1, /* Use Scatter/Gather */
:1,
interp:1, /* The controller interprets cp, not the target */
interp:1, /* The controller interprets cp, not the target */
dout:1, /* Direction of Transfer is Out (Host to Target) */
din:1; /* Direction of Transfer is In (Target to Host) */
unchar sense_len; /* Request Sense Length */
......@@ -535,10 +546,11 @@ struct mscp {
unchar mess[3]; /* Massage to/from Target */
unchar cdb[12]; /* Command Descriptor Block */
ulong data_len; /* If sg=0 Data Length, if sg=1 sglist length */
Scsi_Cmnd *SCpnt; /* Address to be returned in sp */
struct mscp *cpp; /* Address to be returned in sp */
ulong data_address; /* If sg=0 Data Address, if sg=1 sglist address */
ulong sp_addr; /* Address where sp is DMA'ed when cp completes */
ulong sense_addr; /* Address where Sense Data is DMA'ed on error */
Scsi_Cmnd *SCpnt;
unsigned int index; /* cp index */
struct sg_list *sglist;
};
......@@ -558,7 +570,7 @@ struct hostdata {
unsigned long last_retried_pid; /* Pid of last retried command */
unsigned char subversion; /* Bus type, either ISA or EISA/PCI */
unsigned char protocol_rev; /* EATA 2.0 rev., 'A' or 'B' or 'C' */
struct mssp sp[MAX_MAILBOXES]; /* Returned status for this board */
struct mssp sp[2]; /* Returned status for this board */
};
static struct Scsi_Host *sh[MAX_BOARDS + 1];
......@@ -568,7 +580,7 @@ static char sha[MAX_BOARDS];
/* Initialize num_boards so that ihdlr can work while detect is in progress */
static unsigned int num_boards = MAX_BOARDS;
static unsigned long io_port[] __initdata = {
static unsigned long io_port[] __initdata = {
/* Space for MAX_INT_PARAM ports usable while loading as a module */
SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP,
......@@ -583,11 +595,11 @@ static unsigned long io_port[] __initdata = {
/* MAX_EISA ports */
0x1c88, 0x2c88, 0x3c88, 0x4c88, 0x5c88, 0x6c88, 0x7c88, 0x8c88,
0x9c88, 0xac88, 0xbc88, 0xcc88, 0xdc88, 0xec88, 0xfc88,
0x9c88, 0xac88, 0xbc88, 0xcc88, 0xdc88, 0xec88, 0xfc88,
/* Other (MAX_ISA - 1) ports */
0x170, 0x230, 0x330,
/* End of list */
0x0
};
......@@ -627,7 +639,7 @@ static int max_queue_depth = MAX_CMD_PER_LUN;
static void select_queue_depths(struct Scsi_Host *host, Scsi_Device *devlist) {
Scsi_Device *dev;
int j, ntag = 0, nuntag = 0, tqd, utqd;
int j, ntag = 0, nuntag = 0, tqd, utqd;
unsigned long flags;
save_flags(flags);
......@@ -792,14 +804,14 @@ __initfunc (static inline int port_detect \
if (do_dma(port_base, 0, READ_CONFIG_PIO)) return FALSE;
/* Read the info structure */
if (read_pio(port_base, (ushort *)&info, (ushort *)&info.ipad[0]))
if (read_pio(port_base, (ushort *)&info, (ushort *)&info.ipad[0]))
return FALSE;
/* Check the controller "EATA" signature */
if (info.sign != EATA_SIGNATURE) return FALSE;
if (DEV2H(info.data_len) < EATA_2_0A_SIZE) {
printk("%s: config structure size (%ld bytes) too short, detaching.\n",
printk("%s: config structure size (%ld bytes) too short, detaching.\n",
name, DEV2H(info.data_len));
return FALSE;
}
......@@ -956,7 +968,7 @@ __initfunc (static inline int port_detect \
/* DPT PM2012 does not allow to detect can_queue correctly */
if (sh[j]->can_queue > MAX_MAILBOXES || sh[j]->can_queue < 2) {
printk("%s: detect, wrong n. of Mbox %d, fixed.\n",
printk("%s: detect, wrong n. of mbox %d, fixed.\n",
BN(j), sh[j]->can_queue);
sh[j]->can_queue = MAX_MAILBOXES;
}
......@@ -984,14 +996,14 @@ __initfunc (static inline int port_detect \
for (i = 0; i < sh[j]->can_queue; i++)
if (! ((&HD(j)->cp[i])->sglist = kmalloc(
sh[j]->sg_tablesize * sizeof(struct sg_list),
sh[j]->sg_tablesize * sizeof(struct sg_list),
(sh[j]->unchecked_isa_dma ? GFP_DMA : 0) | GFP_ATOMIC))) {
printk("%s: kmalloc SGlist failed, mbox %d, detaching.\n", BN(j), i);
eata2x_release(sh[j]);
return FALSE;
}
if (max_queue_depth > MAX_TAGGED_CMD_PER_LUN)
if (max_queue_depth > MAX_TAGGED_CMD_PER_LUN)
max_queue_depth = MAX_TAGGED_CMD_PER_LUN;
if (max_queue_depth < MAX_CMD_PER_LUN) max_queue_depth = MAX_CMD_PER_LUN;
......@@ -1032,7 +1044,7 @@ __initfunc (static inline int port_detect \
if (protocol_rev == 'C')
printk("%s: max_lun %u, m1 %u, idquest %u, pci %u, eisa %u, "\
"raidnum %u.\n", name, info.max_lun, info.m1, info.idquest,
"raidnum %u.\n", name, info.max_lun, info.m1, info.idquest,
info.pci, info.eisa, info.raidnum);
#endif
......@@ -1047,8 +1059,8 @@ __initfunc (void eata2x_setup(char *str, int *ints)) {
if (argc > MAX_INT_PARAM) argc = MAX_INT_PARAM;
for (i = 0; i < argc; i++) io_port[i] = ints[i + 1];
for (i = 0; i < argc; i++) io_port[i] = ints[i + 1];
io_port[i] = 0;
setup_done = TRUE;
}
......@@ -1099,7 +1111,7 @@ __initfunc (static void add_pci_ports(void)) {
continue;
/* Reverse the returned address order */
io_port[MAX_INT_PARAM + MAX_PCI - k] =
io_port[MAX_INT_PARAM + MAX_PCI - k] =
(addr & PCI_BASE_ADDRESS_IO_MASK) + PCI_BASE_ADDRESS_0;
}
......@@ -1127,7 +1139,7 @@ __initfunc (static void add_pci_ports(void)) {
continue;
/* Reverse the returned address order */
io_port[MAX_INT_PARAM + MAX_PCI - k] =
io_port[MAX_INT_PARAM + MAX_PCI - k] =
(addr & PCI_BASE_ADDRESS_IO_MASK) + PCI_BASE_ADDRESS_0;
}
......@@ -1166,7 +1178,7 @@ __initfunc (int eata2x_detect(Scsi_Host_Template *tpnt)) {
if (j < MAX_BOARDS && port_detect(io_port[k], j, tpnt)) j++;
}
if (j > 0)
if (j > 0)
printk("EATA/DMA 2.0x: Copyright (C) 1994-1998 Dario Ballabio.\n");
num_boards = j;
......@@ -1197,7 +1209,7 @@ int eata2x_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
static const unsigned char data_out_cmds[] = {
0x0a, 0x2a, 0x15, 0x55, 0x04, 0x07, 0x18, 0x1d, 0x24, 0x2e,
0x30, 0x31, 0x32, 0x38, 0x39, 0x3a, 0x3b, 0x3d, 0x3f, 0x40,
0x30, 0x31, 0x32, 0x38, 0x39, 0x3a, 0x3b, 0x3d, 0x3f, 0x40,
0x41, 0x4c, 0xaa, 0xae, 0xb0, 0xb1, 0xb2, 0xb6, 0xea, 0x1b
};
......@@ -1215,16 +1227,16 @@ int eata2x_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
if (!done) panic("%s: qcomm, pid %ld, null done.\n", BN(j), SCpnt->pid);
if (SCpnt->cmnd[0] == REQUEST_SENSE && SCpnt->sense_buffer[0]) {
SCpnt->result = DID_OK << 16;
SCpnt->result = DID_OK << 16;
SCpnt->host_scribble = NULL;
printk("%s: qcomm, target %d.%d:%d, pid %ld, request sense ignored.\n",
BN(j), SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid);
restore_flags(flags);
done(SCpnt);
done(SCpnt);
return 0;
}
/* i is the mailbox number, look for the first free mailbox
/* i is the mailbox number, look for the first free mailbox
starting from last_cp_used */
i = HD(j)->last_cp_used + 1;
......@@ -1241,17 +1253,17 @@ int eata2x_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
if (k == sh[j]->can_queue) {
printk("%s: qcomm, no free mailbox, resetting.\n", BN(j));
if (HD(j)->in_reset)
if (HD(j)->in_reset)
printk("%s: qcomm, already in reset.\n", BN(j));
else if (eata2x_reset(SCpnt, SCSI_RESET_SUGGEST_BUS_RESET)
== SCSI_RESET_SUCCESS)
== SCSI_RESET_SUCCESS)
panic("%s: qcomm, SCSI_RESET_SUCCESS.\n", BN(j));
SCpnt->result = DID_BUS_BUSY << 16;
SCpnt->result = DID_BUS_BUSY << 16;
SCpnt->host_scribble = NULL;
printk("%s: qcomm, pid %ld, DID_BUS_BUSY, done.\n", BN(j), SCpnt->pid);
restore_flags(flags);
done(SCpnt);
done(SCpnt);
return 1;
}
......@@ -1261,13 +1273,12 @@ int eata2x_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
memset(cpp, 0, sizeof(struct mscp) - sizeof(struct sg_list *));
/* Set pointer to status packet structure */
spp = &HD(j)->sp[i];
memset(spp, 0, sizeof(struct mssp));
spp = &HD(j)->sp[0];
/* The EATA protocol uses Big Endian format */
cpp->sp_addr = V2DEV(spp);
cpp->cpp = cpp;
SCpnt->scsi_done = done;
cpp->index = i;
SCpnt->host_scribble = (unsigned char *) &cpp->index;
......@@ -1297,11 +1308,11 @@ int eata2x_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
cpp->one = TRUE;
cpp->channel = SCpnt->channel;
cpp->target = SCpnt->target;
cpp->lun = SCpnt->lun;
cpp->lun = SCpnt->lun;
cpp->SCpnt = SCpnt;
cpp->sense_addr = V2DEV(SCpnt->sense_buffer);
cpp->sense_addr = V2DEV(SCpnt->sense_buffer);
cpp->sense_len = sizeof SCpnt->sense_buffer;
if (SCpnt->device->tagged_queue) {
if (HD(j)->target_redo[SCpnt->target][SCpnt->channel] ||
......@@ -1341,13 +1352,13 @@ int eata2x_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
/* Send control packet to the board */
if (do_dma(sh[j]->io_port, (unsigned int) cpp, SEND_CP_DMA)) {
SCpnt->result = DID_ERROR << 16;
SCpnt->result = DID_ERROR << 16;
SCpnt->host_scribble = NULL;
printk("%s: qcomm, target %d.%d:%d, pid %ld, adapter busy, DID_ERROR,"\
" done.\n", BN(j), SCpnt->channel, SCpnt->target, SCpnt->lun,
SCpnt->pid);
restore_flags(flags);
done(SCpnt);
done(SCpnt);
return 1;
}
......@@ -1373,7 +1384,7 @@ int eata2x_abort(Scsi_Cmnd *SCarg) {
}
i = *(unsigned int *)SCarg->host_scribble;
printk("%s: abort, mbox %d, target %d.%d:%d, pid %ld.\n",
printk("%s: abort, mbox %d, target %d.%d:%d, pid %ld.\n",
BN(j), i, SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid);
if (i >= sh[j]->can_queue)
......@@ -1441,7 +1452,7 @@ int eata2x_reset(Scsi_Cmnd *SCarg, unsigned int reset_flags) {
save_flags(flags);
cli();
j = ((struct hostdata *) SCarg->host->hostdata)->board_number;
printk("%s: reset, enter, target %d.%d:%d, pid %ld, reset_flags %u.\n",
printk("%s: reset, enter, target %d.%d:%d, pid %ld, reset_flags %u.\n",
BN(j), SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid,
reset_flags);
......@@ -1502,10 +1513,10 @@ int eata2x_reset(Scsi_Cmnd *SCarg, unsigned int reset_flags) {
if (SCpnt->host_scribble == NULL)
panic("%s: reset, mbox %d, garbled SCpnt.\n", BN(j), i);
if (*(unsigned int *)SCpnt->host_scribble != i)
if (*(unsigned int *)SCpnt->host_scribble != i)
panic("%s: reset, mbox %d, index mismatch.\n", BN(j), i);
if (SCpnt->scsi_done == NULL)
if (SCpnt->scsi_done == NULL)
panic("%s: reset, mbox %d, SCpnt->scsi_done == NULL.\n", BN(j), i);
if (SCpnt == SCarg) arg_done = TRUE;
......@@ -1588,7 +1599,7 @@ static void sort(unsigned long sk[], unsigned int da[], unsigned int n,
for (i = 0; i < n - 1; i++) {
k = i;
for (j = k + 1; j < n; j++)
for (j = k + 1; j < n; j++)
if (rev) {
if (sk[j] > sk[k]) k = j;
}
......@@ -1605,7 +1616,7 @@ static void sort(unsigned long sk[], unsigned int da[], unsigned int n,
return;
}
static inline void reorder(unsigned int j, unsigned long cursec,
static inline int reorder(unsigned int j, unsigned long cursec,
unsigned int ihdlr, unsigned int il[], unsigned int n_ready) {
Scsi_Cmnd *SCpnt;
struct mscp *cpp;
......@@ -1625,10 +1636,10 @@ static inline void reorder(unsigned int j, unsigned long cursec,
printk("fc %d bc %d ic %d oc %d rc %d rs %d sc %d re %d"\
" av %ldK as %ldK.\n", flushcount, batchcount, inputcount,
ovlcount, readycount, readysorted, sortcount, revcount,
seeknosort / (readycount + 1),
seeknosort / (readycount + 1),
seeksorted / (readycount + 1));
if (n_ready <= 1) return;
if (n_ready <= 1) return FALSE;
for (n = 0; n < n_ready; n++) {
k = il[n]; cpp = &HD(j)->cp[k]; SCpnt = cpp->SCpnt;
......@@ -1645,7 +1656,7 @@ static inline void reorder(unsigned int j, unsigned long cursec,
if (sl[n] < sl[n - 1]) s = FALSE;
if (sl[n] > sl[n - 1]) r = FALSE;
if (link_statistics) {
if (sl[n] > sl[n - 1])
seek += sl[n] - sl[n - 1];
......@@ -1670,7 +1681,7 @@ static inline void reorder(unsigned int j, unsigned long cursec,
ll[n] = SCpnt->request.nr_sectors; pl[n] = SCpnt->pid;
if (!n) continue;
if ((sl[n] == sl[n - 1]) || (!rev && ((sl[n - 1] + ll[n - 1]) > sl[n]))
|| (rev && ((sl[n] + ll[n]) > sl[n - 1]))) overlap = TRUE;
}
......@@ -1679,9 +1690,9 @@ static inline void reorder(unsigned int j, unsigned long cursec,
if (link_statistics) {
if (cursec > sl[0]) iseek = cursec - sl[0]; else iseek = sl[0] - cursec;
batchcount++; readycount += n_ready, seeknosort += seek / 1024;
batchcount++; readycount += n_ready, seeknosort += seek / 1024;
if (input_only) inputcount++;
if (overlap) { ovlcount++; seeksorted += seek / 1024; }
if (overlap) { ovlcount++; seeksorted += iseek / 1024; }
else seeksorted += (iseek + maxsec - minsec) / 1024;
if (rev && !r) { revcount++; readysorted += n_ready; }
if (!rev && !s) { sortcount++; readysorted += n_ready; }
......@@ -1696,10 +1707,11 @@ static inline void reorder(unsigned int j, unsigned long cursec,
(ihdlr ? "ihdlr" : "qcomm"), SCpnt->channel, SCpnt->target,
SCpnt->lun, SCpnt->pid, k, flushcount, n_ready,
SCpnt->request.sector, SCpnt->request.nr_sectors, cursec,
YESNO(s), YESNO(r), YESNO(rev), YESNO(input_only),
YESNO(s), YESNO(r), YESNO(rev), YESNO(input_only),
YESNO(overlap), cpp->din);
}
#endif
return overlap;
}
static void flush_dev(Scsi_Device *dev, unsigned long cursec, unsigned int j,
......@@ -1721,13 +1733,13 @@ static void flush_dev(Scsi_Device *dev, unsigned long cursec, unsigned int j,
il[n_ready++] = k;
}
reorder(j, cursec, ihdlr, il, n_ready);
if (reorder(j, cursec, ihdlr, il, n_ready)) n_ready = 1;
for (n = 0; n < n_ready; n++) {
k = il[n]; cpp = &HD(j)->cp[k]; SCpnt = cpp->SCpnt;
if (do_dma(sh[j]->io_port, (unsigned int) cpp, SEND_CP_DMA)) {
printk("%s: %s, target %d.%d:%d, pid %ld, Mbox %d, adapter"\
printk("%s: %s, target %d.%d:%d, pid %ld, mbox %d, adapter"\
" busy, will abort.\n", BN(j), (ihdlr ? "ihdlr" : "qcomm"),
SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid, k);
HD(j)->cp_stat[k] = ABORTING;
......@@ -1739,196 +1751,201 @@ static void flush_dev(Scsi_Device *dev, unsigned long cursec, unsigned int j,
}
static inline void ihdlr(int irq, void *shap, struct pt_regs *regs) {
static inline void ihdlr(int irq, unsigned int j) {
Scsi_Cmnd *SCpnt;
unsigned int i, j, k, c, status, tstatus, reg;
unsigned int n, n_ready, il[MAX_MAILBOXES];
struct mssp *spp;
unsigned int i, k, c, status, tstatus, reg;
struct mssp *dspp, *spp;
struct mscp *cpp;
/* Check if the interrupt must be processed by this handler */
if ((j = (unsigned int)((char *)shap - sha)) >= num_boards) return;
if (sh[j]->irq != irq)
panic("%s: ihdlr, irq %d, sh[j]->irq %d.\n", BN(j), irq, sh[j]->irq);
if (do_trace) printk("%s: ihdlr, enter, irq %d, count %d.\n", BN(j), irq,
HD(j)->iocount);
/* Check if this board need to be serviced */
if (!(inb(sh[j]->io_port + REG_AUX_STATUS) & IRQ_ASSERTED)) return;
n_ready = 0;
/* Find the mailboxes to be serviced on this board */
for (i = 0; i < sh[j]->can_queue; i++) {
spp = &HD(j)->sp[i];
HD(j)->iocount++;
/* Check if this mailbox has completed the operation */
if (spp->eoc == FALSE) continue;
if (do_trace) printk("%s: ihdlr, enter, irq %d, count %d.\n", BN(j), irq,
HD(j)->iocount);
spp->eoc = FALSE;
il[n_ready++] = i;
/* Check if this board is still busy */
if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
reg = inb(sh[j]->io_port + REG_STATUS);
printk("%s: ihdlr, busy timeout error, irq %d, reg 0x%x, count %d.\n",
BN(j), irq, reg, HD(j)->iocount);
return;
}
dspp = &HD(j)->sp[0];
spp = &HD(j)->sp[1];
/* Make a local copy just before clearing the interrupt indication */
memcpy(spp, dspp, sizeof(struct mssp));
/* Clear the completion flag and cp pointer on the dynamic copy of sp */
memset(dspp, 0, sizeof(struct mssp));
/* Read the status register to clear the interrupt indication */
reg = inb(sh[j]->io_port + REG_STATUS);
/* Mailbox service loop */
for (n = 0; n < n_ready; n++) {
i = il[n];
spp = &HD(j)->sp[i];
/* Reject any sp with supspect data */
if (spp->eoc == FALSE)
printk("%s: ihdlr, spp->eoc == FALSE, irq %d, reg 0x%x, count %d.\n",
BN(j), irq, reg, HD(j)->iocount);
if (spp->cpp == NULL)
printk("%s: ihdlr, spp->cpp == NULL, irq %d, reg 0x%x, count %d.\n",
BN(j), irq, reg, HD(j)->iocount);
if (spp->eoc == FALSE || spp->cpp == NULL) return;
if (HD(j)->cp_stat[i] == IGNORE) {
HD(j)->cp_stat[i] = FREE;
return;
}
else if (HD(j)->cp_stat[i] == LOCKED) {
HD(j)->cp_stat[i] = FREE;
printk("%s: ihdlr, mbox %d unlocked, count %d.\n", BN(j), i,
HD(j)->iocount);
return;
}
else if (HD(j)->cp_stat[i] == FREE) {
printk("%s: ihdlr, mbox %d is free, count %d.\n", BN(j), i,
HD(j)->iocount);
return;
}
else if (HD(j)->cp_stat[i] == IN_RESET)
printk("%s: ihdlr, mbox %d is in reset.\n", BN(j), i);
else if (HD(j)->cp_stat[i] != IN_USE)
panic("%s: ihdlr, mbox %d, invalid cp_stat: %d.\n",
BN(j), i, HD(j)->cp_stat[i]);
cpp = spp->cpp;
/* Find the mailbox to be serviced on this board */
i = cpp - HD(j)->cp;
if (cpp < HD(j)->cp || cpp >= HD(j)->cp + sh[j]->can_queue
|| i >= sh[j]->can_queue)
panic("%s: ihdlr, invalid mscp bus address %p, cp0 %p.\n", BN(j),
cpp, HD(j)->cp);
if (HD(j)->cp_stat[i] == IGNORE) {
HD(j)->cp_stat[i] = FREE;
cpp = &HD(j)->cp[i];
SCpnt = spp->SCpnt;
return;
}
else if (HD(j)->cp_stat[i] == LOCKED) {
HD(j)->cp_stat[i] = FREE;
printk("%s: ihdlr, mbox %d unlocked, count %d.\n", BN(j), i,
HD(j)->iocount);
return;
}
else if (HD(j)->cp_stat[i] == FREE) {
printk("%s: ihdlr, mbox %d is free, count %d.\n", BN(j), i,
HD(j)->iocount);
return;
}
else if (HD(j)->cp_stat[i] == IN_RESET)
printk("%s: ihdlr, mbox %d is in reset.\n", BN(j), i);
else if (HD(j)->cp_stat[i] != IN_USE)
panic("%s: ihdlr, mbox %d, invalid cp_stat: %d.\n",
BN(j), i, HD(j)->cp_stat[i]);
if(SCpnt == NULL) panic("%s: ihdlr, mbox %d, SCpnt == NULL.\n", BN(j), i);
HD(j)->cp_stat[i] = FREE;
SCpnt = cpp->SCpnt;
if (SCpnt != cpp->SCpnt)
panic("%s: ihdlr, mbox %d, sp SCpnt %p, cp SCpnt %p.\n", BN(j), i,
SCpnt, cpp->SCpnt);
if (SCpnt == NULL) panic("%s: ihdlr, mbox %d, SCpnt == NULL.\n", BN(j), i);
if (SCpnt->host_scribble == NULL)
panic("%s: ihdlr, mbox %d, pid %ld, SCpnt %p garbled.\n", BN(j), i,
SCpnt->pid, SCpnt);
if (SCpnt->host_scribble == NULL)
panic("%s: ihdlr, mbox %d, pid %ld, SCpnt %p garbled.\n", BN(j), i,
SCpnt->pid, SCpnt);
if (*(unsigned int *)SCpnt->host_scribble != i)
panic("%s: ihdlr, mbox %d, pid %ld, index mismatch %d, irq %d.\n",
BN(j), i, SCpnt->pid, *(unsigned int *)SCpnt->host_scribble, irq);
if (*(unsigned int *)SCpnt->host_scribble != i)
panic("%s: ihdlr, mbox %d, pid %ld, index mismatch %d.\n",
BN(j), i, SCpnt->pid, *(unsigned int *)SCpnt->host_scribble);
if (linked_comm && SCpnt->device->queue_depth > 2
&& TLDEV(SCpnt->device->type))
if (linked_comm && SCpnt->device->queue_depth > 2
&& TLDEV(SCpnt->device->type))
flush_dev(SCpnt->device, SCpnt->request.sector, j, TRUE);
tstatus = status_byte(spp->target_status);
switch (spp->adapter_status) {
case ASOK: /* status OK */
/* Forces a reset if a disk drive keeps returning BUSY */
if (tstatus == BUSY && SCpnt->device->type != TYPE_TAPE)
status = DID_ERROR << 16;
/* If there was a bus reset, redo operation on each target */
else if (tstatus != GOOD && SCpnt->device->type == TYPE_DISK
&& HD(j)->target_redo[SCpnt->target][SCpnt->channel])
status = DID_BUS_BUSY << 16;
/* Works around a flaw in scsi.c */
else if (tstatus == CHECK_CONDITION
&& SCpnt->device->type == TYPE_DISK
&& (SCpnt->sense_buffer[2] & 0xf) == RECOVERED_ERROR)
status = DID_BUS_BUSY << 16;
else
status = DID_OK << 16;
if (tstatus == GOOD)
HD(j)->target_redo[SCpnt->target][SCpnt->channel] = FALSE;
if (spp->target_status && SCpnt->device->type == TYPE_DISK)
printk("%s: ihdlr, target %d.%d:%d, pid %ld, "\
"target_status 0x%x, sense key 0x%x.\n", BN(j),
SCpnt->channel, SCpnt->target, SCpnt->lun,
SCpnt->pid, spp->target_status,
SCpnt->sense_buffer[2]);
HD(j)->target_to[SCpnt->target][SCpnt->channel] = 0;
if (HD(j)->last_retried_pid == SCpnt->pid) HD(j)->retries = 0;
break;
case ASST: /* Selection Time Out */
case 0x02: /* Command Time Out */
if (HD(j)->target_to[SCpnt->target][SCpnt->channel] > 1)
status = DID_ERROR << 16;
else {
status = DID_TIME_OUT << 16;
HD(j)->target_to[SCpnt->target][SCpnt->channel]++;
}
break;
/* Perform a limited number of internal retries */
case 0x03: /* SCSI Bus Reset Received */
case 0x04: /* Initial Controller Power-up */
for (c = 0; c <= sh[j]->max_channel; c++)
for (k = 0; k < sh[j]->max_id; k++)
HD(j)->target_redo[k][c] = TRUE;
if (SCpnt->device->type != TYPE_TAPE
&& HD(j)->retries < MAX_INTERNAL_RETRIES) {
status = DID_BUS_BUSY << 16;
HD(j)->retries++;
HD(j)->last_retried_pid = SCpnt->pid;
}
else
status = DID_ERROR << 16;
break;
case 0x05: /* Unexpected Bus Phase */
case 0x06: /* Unexpected Bus Free */
case 0x07: /* Bus Parity Error */
case 0x08: /* SCSI Hung */
case 0x09: /* Unexpected Message Reject */
case 0x0a: /* SCSI Bus Reset Stuck */
case 0x0b: /* Auto Request-Sense Failed */
case 0x0c: /* Controller Ram Parity Error */
default:
tstatus = status_byte(spp->target_status);
switch (spp->adapter_status) {
case ASOK: /* status OK */
/* Forces a reset if a disk drive keeps returning BUSY */
if (tstatus == BUSY && SCpnt->device->type != TYPE_TAPE)
status = DID_ERROR << 16;
break;
}
SCpnt->result = status | spp->target_status;
HD(j)->iocount++;
/* If there was a bus reset, redo operation on each target */
else if (tstatus != GOOD && SCpnt->device->type == TYPE_DISK
&& HD(j)->target_redo[SCpnt->target][SCpnt->channel])
status = DID_BUS_BUSY << 16;
/* Works around a flaw in scsi.c */
else if (tstatus == CHECK_CONDITION
&& SCpnt->device->type == TYPE_DISK
&& (SCpnt->sense_buffer[2] & 0xf) == RECOVERED_ERROR)
status = DID_BUS_BUSY << 16;
else
status = DID_OK << 16;
if (tstatus == GOOD)
HD(j)->target_redo[SCpnt->target][SCpnt->channel] = FALSE;
if (spp->target_status && SCpnt->device->type == TYPE_DISK)
printk("%s: ihdlr, target %d.%d:%d, pid %ld, "\
"target_status 0x%x, sense key 0x%x.\n", BN(j),
SCpnt->channel, SCpnt->target, SCpnt->lun,
SCpnt->pid, spp->target_status,
SCpnt->sense_buffer[2]);
HD(j)->target_to[SCpnt->target][SCpnt->channel] = 0;
if (HD(j)->last_retried_pid == SCpnt->pid) HD(j)->retries = 0;
break;
case ASST: /* Selection Time Out */
case 0x02: /* Command Time Out */
if (HD(j)->target_to[SCpnt->target][SCpnt->channel] > 1)
status = DID_ERROR << 16;
else {
status = DID_TIME_OUT << 16;
HD(j)->target_to[SCpnt->target][SCpnt->channel]++;
}
break;
/* Perform a limited number of internal retries */
case 0x03: /* SCSI Bus Reset Received */
case 0x04: /* Initial Controller Power-up */
for (c = 0; c <= sh[j]->max_channel; c++)
for (k = 0; k < sh[j]->max_id; k++)
HD(j)->target_redo[k][c] = TRUE;
if (SCpnt->device->type != TYPE_TAPE
&& HD(j)->retries < MAX_INTERNAL_RETRIES) {
status = DID_BUS_BUSY << 16;
HD(j)->retries++;
HD(j)->last_retried_pid = SCpnt->pid;
}
else
status = DID_ERROR << 16;
break;
case 0x05: /* Unexpected Bus Phase */
case 0x06: /* Unexpected Bus Free */
case 0x07: /* Bus Parity Error */
case 0x08: /* SCSI Hung */
case 0x09: /* Unexpected Message Reject */
case 0x0a: /* SCSI Bus Reset Stuck */
case 0x0b: /* Auto Request-Sense Failed */
case 0x0c: /* Controller Ram Parity Error */
default:
status = DID_ERROR << 16;
break;
}
SCpnt->result = status | spp->target_status;
#if defined (DEBUG_INTERRUPT)
if (SCpnt->result || do_trace)
if (SCpnt->result || do_trace)
#else
if ((spp->adapter_status != ASOK && HD(j)->iocount > 1000) ||
(spp->adapter_status != ASOK &&
spp->adapter_status != ASST && HD(j)->iocount <= 1000) ||
do_trace || msg_byte(spp->target_status))
if ((spp->adapter_status != ASOK && HD(j)->iocount > 1000) ||
(spp->adapter_status != ASOK &&
spp->adapter_status != ASST && HD(j)->iocount <= 1000) ||
do_trace || msg_byte(spp->target_status))
#endif
printk("%s: ihdlr, mbox %2d, err 0x%x:%x,"\
" target %d.%d:%d, pid %ld, reg 0x%x, count %d.\n",
BN(j), i, spp->adapter_status, spp->target_status,
SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid,
reg, HD(j)->iocount);
printk("%s: ihdlr, mbox %2d, err 0x%x:%x,"\
" target %d.%d:%d, pid %ld, reg 0x%x, count %d.\n",
BN(j), i, spp->adapter_status, spp->target_status,
SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid,
reg, HD(j)->iocount);
/* Set the command state to inactive */
SCpnt->host_scribble = NULL;
SCpnt->scsi_done(SCpnt);
/* Set the command state to inactive */
SCpnt->host_scribble = NULL;
} /* Mailbox loop */
if (n_ready > 1)
printk("%s: ihdlr, multiple commands (%d) completed.\n", BN(j), n_ready);
SCpnt->scsi_done(SCpnt);
if (do_trace) printk("%s: ihdlr, exit, irq %d, count %d.\n", BN(j), irq,
HD(j)->iocount);
......@@ -1938,18 +1955,22 @@ static inline void ihdlr(int irq, void *shap, struct pt_regs *regs) {
static void do_interrupt_handler(int irq, void *shap, struct pt_regs *regs) {
#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,95)
unsigned int j;
/* Check if the interrupt must be processed by this handler */
if ((j = (unsigned int)((char *)shap - sha)) >= num_boards) return;
#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,95)
{
unsigned long flags;
spin_lock_irqsave(&io_request_lock, flags);
ihdlr(irq, shap, regs);
ihdlr(irq, j);
spin_unlock_irqrestore(&io_request_lock, flags);
}
#else
ihdlr(irq, shap, regs);
ihdlr(irq, j);
#endif
}
int eata2x_release(struct Scsi_Host *shpnt) {
......@@ -1960,11 +1981,11 @@ int eata2x_release(struct Scsi_Host *shpnt) {
cli();
for (j = 0; sh[j] != NULL && sh[j] != shpnt; j++);
if (sh[j] == NULL) panic("%s: release, invalid Scsi_Host pointer.\n",
driver_name);
for (i = 0; i < sh[j]->can_queue; i++)
for (i = 0; i < sh[j]->can_queue; i++)
if ((&HD(j)->cp[i])->sglist) kfree((&HD(j)->cp[i])->sglist);
free_irq(sh[j]->irq, &sha[j]);
......
......@@ -13,7 +13,7 @@ int eata2x_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
int eata2x_abort(Scsi_Cmnd *);
int eata2x_reset(Scsi_Cmnd *, unsigned int);
#define EATA_VERSION "4.04.00"
#define EATA_VERSION "4.20.00"
#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
......
......@@ -23,6 +23,7 @@
$Header: /vger/u4/cvs/linux/drivers/scsi/hosts.h,v 1.6 1997/01/19 23:07:13 davem Exp $
*/
#include <linux/config.h>
#include <linux/proc_fs.h>
/* It is senseless to set SG_ALL any higher than this - the performance
......
/*
* u14-34f.c - Low-level driver for UltraStor 14F/34F SCSI host adapters.
*
* 18 Apr 1998 Rev. 4.20 for linux 2.0.33 and 2.1.97
* Reworked interrupt handler.
*
* 11 Apr 1998 rev. 4.05 for linux 2.0.33 and 2.1.95
* Major reliability improvement: when a batch with overlapping
* requests is detected, requests are queued one at a time
* eliminating any possible board or drive reordering.
*
* 10 Apr 1998 rev. 4.04 for linux 2.0.33 and 2.1.95
* Improved SMP support (if linux version >= 2.1.95).
*
* 9 Apr 1998 rev. 4.03 for linux 2.0.33 and 2.1.94
* Performance improvement: when sequential i/o is detected,
* always use direct sort instead of reverse sort.
*
*
* 4 Apr 1998 rev. 4.02 for linux 2.0.33 and 2.1.92
* io_port is now unsigned long.
*
......@@ -35,7 +43,7 @@
* Fixed data transfer direction for some SCSI opcodes.
* Immediate acknowledge to request sense commands.
* Linked commands to each disk device are now reordered by elevator
* sorting. Rare cases in which reordering of write requests could
* sorting. Rare cases in which reordering of write requests could
* cause wrong results are managed.
*
* 18 Jan 1997 rev. 2.60 for linux 2.1.21 and 2.0.28
......@@ -119,12 +127,12 @@
* 28 Oct 1994 rev. 1.09 for linux 1.1.58 Final BETA release.
* 16 Jul 1994 rev. 1.00 for linux 1.1.29 Initial ALPHA release.
*
* This driver is a total replacement of the original UltraStor
* This driver is a total replacement of the original UltraStor
* scsi driver, but it supports ONLY the 14F and 34F boards.
* It can be configured in the same kernel in which the original
* ultrastor driver is configured to allow the original U24F
* support.
*
*
* Multiple U14F and/or U34F host adapters are supported.
*
* Copyright (C) 1994-1998 Dario Ballabio (dario@milano.europe.dg.com)
......@@ -148,11 +156,11 @@
* 24F - EISA Bus Master HA with floppy support and WD1003 emulation.
* 34F - VESA Local-Bus Bus Master HA (no WD1003 emulation).
*
* This code has been tested with up to two U14F boards, using both
* This code has been tested with up to two U14F boards, using both
* firmware 28004-005/38004-004 (BIOS rev. 2.00) and the latest firmware
* 28004-006/38004-005 (BIOS rev. 2.01).
* 28004-006/38004-005 (BIOS rev. 2.01).
*
* The latest firmware is required in order to get reliable operations when
* The latest firmware is required in order to get reliable operations when
* clustering is enabled. ENABLE_CLUSTERING provides a performance increase
* up to 50% on sequential access.
*
......@@ -168,24 +176,24 @@
* have their BIOS disabled, or enabled to an higher address.
* Boards are named Ux4F0, Ux4F1..., according to the port address order in
* the io_port[] array.
*
*
* The following facts are based on real testing results (not on
* documentation) on the above U14F board.
*
* - The U14F board should be jumpered for bus on time less or equal to 7
* microseconds, while the default is 11 microseconds. This is order to
* get acceptable performance while using floppy drive and hard disk
* together. The jumpering for 7 microseconds is: JP13 pin 15-16,
*
* - The U14F board should be jumpered for bus on time less or equal to 7
* microseconds, while the default is 11 microseconds. This is order to
* get acceptable performance while using floppy drive and hard disk
* together. The jumpering for 7 microseconds is: JP13 pin 15-16,
* JP14 pin 7-8 and pin 9-10.
* The reduction has a little impact on scsi performance.
*
*
* - If scsi bus length exceeds 3m., the scsi bus speed needs to be reduced
* from 10Mhz to 5Mhz (do this by inserting a jumper on JP13 pin 7-8).
*
* - If U14F on board firmware is older than 28004-006/38004-005,
* the U14F board is unable to provide reliable operations if the scsi
* the U14F board is unable to provide reliable operations if the scsi
* request length exceeds 16Kbyte. When this length is exceeded the
* behavior is:
* behavior is:
* - adapter_status equal 0x96 or 0xa3 or 0x93 or 0x94;
* - adapter_status equal 0 and target_status equal 2 on for all targets
* in the next operation following the reset.
......@@ -199,7 +207,7 @@
* Any reset of the scsi bus is going to kill tape operations, since
* no retry is allowed for tapes. Bus resets are more likely when the
* scsi bus is under heavy load.
* Requests using scatter/gather have a maximum length of 16 x 1024 bytes
* Requests using scatter/gather have a maximum length of 16 x 1024 bytes
* when DISABLE_CLUSTERING is in effect, but unscattered requests could be
* larger than 16Kbyte.
*
......@@ -246,15 +254,15 @@
* in the elevator sorting queue. When the active command completes, the
* commands in this queue are sorted by sector address. The sort is chosen
* between increasing or decreasing by minimizing the seek distance between
* the sector of the commands just completed and the sector of the first
* command in the list to be sorted.
* the sector of the commands just completed and the sector of the first
* command in the list to be sorted.
* Trivial math assures that the unsorted average seek distance when doing
* random seeks over S sectors is S/3.
* When (Q-1) requests are uniformly distributed over S sectors, the average
* distance between two adjacent requests is S/((Q-1) + 1), so the sorted
* average seek distance for (Q-1) random requests over S sectors is S/Q.
* The elevator sorting hence divides the seek distance by a factor Q/3.
* The above pure geometric remarks are valid in all cases and the
* The above pure geometric remarks are valid in all cases and the
* driver effectively reduces the seek distance by the predicted factor
* when there are Q concurrent read i/o operations on the device, but this
* does not necessarily results in a noticeable performance improvement:
......@@ -262,7 +270,7 @@
*
* Note: command reordering inside a batch of queued commands could cause
* wrong results only if there is at least one write request and the
* intersection (sector-wise) of all requests is not empty.
* intersection (sector-wise) of all requests is not empty.
* When the driver detects a batch including overlapping requests
* (a really rare event) strict serial (pid) order is enforced.
* ----------------------------------------------------------------------------
......@@ -300,6 +308,11 @@ MODULE_AUTHOR("Dario Ballabio");
#include <asm/io.h>
#include <asm/system.h>
#include <asm/byteorder.h>
#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,95)
#include <asm/spinlock.h>
#endif
#include <linux/proc_fs.h>
#include <linux/blk.h>
#include "scsi.h"
......@@ -350,7 +363,7 @@ struct proc_dir_entry proc_scsi_u14_34f = {
#undef DEBUG_RESET
#define MAX_ISA 3
#define MAX_VESA 1
#define MAX_VESA 1
#define MAX_EISA 0
#define MAX_PCI 0
#define MAX_BOARDS (MAX_ISA + MAX_VESA + MAX_EISA + MAX_PCI)
......@@ -462,7 +475,7 @@ static char sha[MAX_BOARDS];
/* Initialize num_boards so that ihdlr can work while detect is in progress */
static unsigned int num_boards = MAX_BOARDS;
static unsigned long io_port[] __initdata = {
static unsigned long io_port[] __initdata = {
/* Space for MAX_INT_PARAM ports usable while loading as a module */
SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP,
......@@ -494,7 +507,7 @@ static unsigned long io_port[] __initdata = {
#define V2DEV(addr) ((addr) ? H2DEV(virt_to_bus((void *)addr)) : 0)
#define DEV2V(addr) ((addr) ? DEV2H(bus_to_virt((unsigned long)addr)) : 0)
static void interrupt_handler(int, void *, struct pt_regs *);
static void do_interrupt_handler(int, void *, struct pt_regs *);
static void flush_dev(Scsi_Device *, unsigned long, unsigned int, unsigned int);
static int do_trace = FALSE;
static int setup_done = FALSE;
......@@ -520,7 +533,7 @@ static int max_queue_depth = MAX_CMD_PER_LUN;
static void select_queue_depths(struct Scsi_Host *host, Scsi_Device *devlist) {
Scsi_Device *dev;
int j, ntag = 0, nuntag = 0, tqd, utqd;
int j, ntag = 0, nuntag = 0, tqd, utqd;
unsigned long flags;
save_flags(flags);
......@@ -637,23 +650,23 @@ __initfunc (static inline int port_detect \
char *bus_type, dma_name[16];
/* Allowed BIOS base addresses (NULL indicates reserved) */
void *bios_segment_table[8] = {
NULL,
void *bios_segment_table[8] = {
NULL,
(void *) 0xc4000, (void *) 0xc8000, (void *) 0xcc000, (void *) 0xd0000,
(void *) 0xd4000, (void *) 0xd8000, (void *) 0xdc000
};
/* Allowed IRQs */
unsigned char interrupt_table[4] = { 15, 14, 11, 10 };
/* Allowed DMA channels for ISA (0 indicates reserved) */
unsigned char dma_channel_table[4] = { 5, 6, 7, 0 };
/* Head/sector mappings */
struct {
unsigned char heads;
unsigned char sectors;
} mapping_table[4] = {
} mapping_table[4] = {
{ 16, 63 }, { 64, 32 }, { 64, 63 }, { 64, 32 }
};
......@@ -694,7 +707,7 @@ __initfunc (static inline int port_detect \
subversion = (in_byte & 0x0f);
/* Board detected, allocate its IRQ */
if (request_irq(irq, interrupt_handler,
if (request_irq(irq, do_interrupt_handler,
SA_INTERRUPT | ((subversion == ESA) ? SA_SHIRQ : 0),
driver_name, (void *) &sha[j])) {
printk("%s: unable to allocate IRQ %u, detaching.\n", name, irq);
......@@ -797,14 +810,14 @@ __initfunc (static inline int port_detect \
for (i = 0; i < sh[j]->can_queue; i++)
if (! ((&HD(j)->cp[i])->sglist = kmalloc(
sh[j]->sg_tablesize * sizeof(struct sg_list),
sh[j]->sg_tablesize * sizeof(struct sg_list),
(sh[j]->unchecked_isa_dma ? GFP_DMA : 0) | GFP_ATOMIC))) {
printk("%s: kmalloc SGlist failed, mbox %d, detaching.\n", BN(j), i);
u14_34f_release(sh[j]);
return FALSE;
}
if (max_queue_depth > MAX_TAGGED_CMD_PER_LUN)
if (max_queue_depth > MAX_TAGGED_CMD_PER_LUN)
max_queue_depth = MAX_TAGGED_CMD_PER_LUN;
if (max_queue_depth < MAX_CMD_PER_LUN) max_queue_depth = MAX_CMD_PER_LUN;
......@@ -834,8 +847,8 @@ __initfunc (void u14_34f_setup(char *str, int *ints)) {
if (argc > MAX_INT_PARAM) argc = MAX_INT_PARAM;
for (i = 0; i < argc; i++) io_port[i] = ints[i + 1];
for (i = 0; i < argc; i++) io_port[i] = ints[i + 1];
io_port[i] = 0;
setup_done = TRUE;
}
......@@ -884,7 +897,7 @@ __initfunc (int u14_34f_detect(Scsi_Host_Template *tpnt)) {
if (j < MAX_BOARDS && port_detect(io_port[k], j, tpnt)) j++;
}
if (j > 0)
if (j > 0)
printk("UltraStor 14F/34F: Copyright (C) 1994-1998 Dario Ballabio.\n");
num_boards = j;
......@@ -916,7 +929,7 @@ int u14_34f_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
static const unsigned char data_out_cmds[] = {
0x0a, 0x2a, 0x15, 0x55, 0x04, 0x07, 0x18, 0x1d, 0x24, 0x2e,
0x30, 0x31, 0x32, 0x38, 0x39, 0x3a, 0x3b, 0x3d, 0x3f, 0x40,
0x30, 0x31, 0x32, 0x38, 0x39, 0x3a, 0x3b, 0x3d, 0x3f, 0x40,
0x41, 0x4c, 0xaa, 0xae, 0xb0, 0xb1, 0xb2, 0xb6, 0xea, 0x1b
};
......@@ -934,16 +947,16 @@ int u14_34f_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
if (!done) panic("%s: qcomm, pid %ld, null done.\n", BN(j), SCpnt->pid);
if (SCpnt->cmnd[0] == REQUEST_SENSE && SCpnt->sense_buffer[0]) {
SCpnt->result = DID_OK << 16;
SCpnt->result = DID_OK << 16;
SCpnt->host_scribble = NULL;
printk("%s: qcomm, target %d.%d:%d, pid %ld, request sense ignored.\n",
BN(j), SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid);
restore_flags(flags);
done(SCpnt);
done(SCpnt);
return 0;
}
/* i is the mailbox number, look for the first free mailbox
/* i is the mailbox number, look for the first free mailbox
starting from last_cp_used */
i = HD(j)->last_cp_used + 1;
......@@ -960,17 +973,17 @@ int u14_34f_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
if (k == sh[j]->can_queue) {
printk("%s: qcomm, no free mailbox, resetting.\n", BN(j));
if (HD(j)->in_reset)
if (HD(j)->in_reset)
printk("%s: qcomm, already in reset.\n", BN(j));
else if (u14_34f_reset(SCpnt, SCSI_RESET_SUGGEST_BUS_RESET)
== SCSI_RESET_SUCCESS)
else if (u14_34f_reset(SCpnt, SCSI_RESET_SUGGEST_BUS_RESET)
== SCSI_RESET_SUCCESS)
panic("%s: qcomm, SCSI_RESET_SUCCESS.\n", BN(j));
SCpnt->result = DID_BUS_BUSY << 16;
SCpnt->result = DID_BUS_BUSY << 16;
SCpnt->host_scribble = NULL;
printk("%s: qcomm, pid %ld, DID_BUS_BUSY, done.\n", BN(j), SCpnt->pid);
restore_flags(flags);
done(SCpnt);
done(SCpnt);
return 1;
}
......@@ -983,7 +996,7 @@ int u14_34f_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
SCpnt->host_scribble = (unsigned char *) &cpp->index;
if (do_trace) printk("%s: qcomm, mbox %d, target %d.%d:%d, pid %ld.\n",
BN(j), i, SCpnt->channel, SCpnt->target,
BN(j), i, SCpnt->channel, SCpnt->target,
SCpnt->lun, SCpnt->pid);
cpp->xdir = DTD_IN;
......@@ -1136,7 +1149,7 @@ int u14_34f_reset(Scsi_Cmnd *SCarg, unsigned int reset_flags) {
save_flags(flags);
cli();
j = ((struct hostdata *) SCarg->host->hostdata)->board_number;
printk("%s: reset, enter, target %d.%d:%d, pid %ld, reset_flags %u.\n",
printk("%s: reset, enter, target %d.%d:%d, pid %ld, reset_flags %u.\n",
BN(j), SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid,
reset_flags);
......@@ -1197,10 +1210,10 @@ int u14_34f_reset(Scsi_Cmnd *SCarg, unsigned int reset_flags) {
if (SCpnt->host_scribble == NULL)
panic("%s: reset, mbox %d, garbled SCpnt.\n", BN(j), i);
if (*(unsigned int *)SCpnt->host_scribble != i)
if (*(unsigned int *)SCpnt->host_scribble != i)
panic("%s: reset, mbox %d, index mismatch.\n", BN(j), i);
if (SCpnt->scsi_done == NULL)
if (SCpnt->scsi_done == NULL)
panic("%s: reset, mbox %d, SCpnt->scsi_done == NULL.\n", BN(j), i);
if (SCpnt == SCarg) arg_done = TRUE;
......@@ -1294,7 +1307,7 @@ static void sort(unsigned long sk[], unsigned int da[], unsigned int n,
for (i = 0; i < n - 1; i++) {
k = i;
for (j = k + 1; j < n; j++)
for (j = k + 1; j < n; j++)
if (rev) {
if (sk[j] > sk[k]) k = j;
}
......@@ -1311,7 +1324,7 @@ static void sort(unsigned long sk[], unsigned int da[], unsigned int n,
return;
}
static inline void reorder(unsigned int j, unsigned long cursec,
static inline int reorder(unsigned int j, unsigned long cursec,
unsigned int ihdlr, unsigned int il[], unsigned int n_ready) {
Scsi_Cmnd *SCpnt;
struct mscp *cpp;
......@@ -1331,10 +1344,10 @@ static inline void reorder(unsigned int j, unsigned long cursec,
printk("fc %d bc %d ic %d oc %d rc %d rs %d sc %d re %d"\
" av %ldK as %ldK.\n", flushcount, batchcount, inputcount,
ovlcount, readycount, readysorted, sortcount, revcount,
seeknosort / (readycount + 1),
seeknosort / (readycount + 1),
seeksorted / (readycount + 1));
if (n_ready <= 1) return;
if (n_ready <= 1) return FALSE;
for (n = 0; n < n_ready; n++) {
k = il[n]; cpp = &HD(j)->cp[k]; SCpnt = cpp->SCpnt;
......@@ -1351,7 +1364,7 @@ static inline void reorder(unsigned int j, unsigned long cursec,
if (sl[n] < sl[n - 1]) s = FALSE;
if (sl[n] > sl[n - 1]) r = FALSE;
if (link_statistics) {
if (sl[n] > sl[n - 1])
seek += sl[n] - sl[n - 1];
......@@ -1376,7 +1389,7 @@ static inline void reorder(unsigned int j, unsigned long cursec,
ll[n] = SCpnt->request.nr_sectors; pl[n] = SCpnt->pid;
if (!n) continue;
if ((sl[n] == sl[n - 1]) || (!rev && ((sl[n - 1] + ll[n - 1]) > sl[n]))
|| (rev && ((sl[n] + ll[n]) > sl[n - 1]))) overlap = TRUE;
}
......@@ -1385,9 +1398,9 @@ static inline void reorder(unsigned int j, unsigned long cursec,
if (link_statistics) {
if (cursec > sl[0]) iseek = cursec - sl[0]; else iseek = sl[0] - cursec;
batchcount++; readycount += n_ready, seeknosort += seek / 1024;
batchcount++; readycount += n_ready, seeknosort += seek / 1024;
if (input_only) inputcount++;
if (overlap) { ovlcount++; seeksorted += seek / 1024; }
if (overlap) { ovlcount++; seeksorted += iseek / 1024; }
else seeksorted += (iseek + maxsec - minsec) / 1024;
if (rev && !r) { revcount++; readysorted += n_ready; }
if (!rev && !s) { sortcount++; readysorted += n_ready; }
......@@ -1402,10 +1415,11 @@ static inline void reorder(unsigned int j, unsigned long cursec,
(ihdlr ? "ihdlr" : "qcomm"), SCpnt->channel, SCpnt->target,
SCpnt->lun, SCpnt->pid, k, flushcount, n_ready,
SCpnt->request.sector, SCpnt->request.nr_sectors, cursec,
YESNO(s), YESNO(r), YESNO(rev), YESNO(input_only),
YESNO(s), YESNO(r), YESNO(rev), YESNO(input_only),
YESNO(overlap), cpp->xdir);
}
#endif
return overlap;
}
static void flush_dev(Scsi_Device *dev, unsigned long cursec, unsigned int j,
......@@ -1427,13 +1441,13 @@ static void flush_dev(Scsi_Device *dev, unsigned long cursec, unsigned int j,
il[n_ready++] = k;
}
reorder(j, cursec, ihdlr, il, n_ready);
if (reorder(j, cursec, ihdlr, il, n_ready)) n_ready = 1;
for (n = 0; n < n_ready; n++) {
k = il[n]; cpp = &HD(j)->cp[k]; SCpnt = cpp->SCpnt;
if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
printk("%s: %s, target %d.%d:%d, pid %ld, Mbox %d, adapter"\
printk("%s: %s, target %d.%d:%d, pid %ld, mbox %d, adapter"\
" busy, will abort.\n", BN(j), (ihdlr ? "ihdlr" : "qcomm"),
SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid, k);
HD(j)->cp_stat[k] = ABORTING;
......@@ -1444,33 +1458,43 @@ static void flush_dev(Scsi_Device *dev, unsigned long cursec, unsigned int j,
outb(CMD_OGM_INTR, sh[j]->io_port + REG_LCL_INTR);
HD(j)->cp_stat[k] = IN_USE;
}
}
static inline void ihdlr(int irq, void *shap, struct pt_regs *regs) {
static inline void ihdlr(int irq, unsigned int j) {
Scsi_Cmnd *SCpnt;
unsigned int i, j, k, c, status, tstatus, reg, ret;
struct mscp *spp;
/* Check if the interrupt must be processed by this handler */
if ((j = (unsigned int)((char *)shap - sha)) >= num_boards) return;
unsigned int i, k, c, status, tstatus, reg, ret;
struct mscp *spp, *cpp;
if (sh[j]->irq != irq)
panic("%s: ihdlr, irq %d, sh[j]->irq %d.\n", BN(j), irq, sh[j]->irq);
/* Check if this board need to be serviced */
if (!((reg = inb(sh[j]->io_port + REG_SYS_INTR)) & IRQ_ASSERTED)) return;
HD(j)->iocount++;
if (do_trace) printk("%s: ihdlr, enter, irq %d, count %d.\n", BN(j), irq,
HD(j)->iocount);
/* Check if this board need to be serviced */
if (!((reg = inb(sh[j]->io_port + REG_SYS_INTR)) & IRQ_ASSERTED)) return;
/* Check if this board is still busy */
if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
outb(CMD_CLR_INTR, sh[j]->io_port + REG_SYS_INTR);
printk("%s: ihdlr, busy timeout error, irq %d, reg 0x%x, count %d.\n",
BN(j), irq, reg, HD(j)->iocount);
return;
}
spp = (struct mscp *)DEV2V(ret = inl(sh[j]->io_port + REG_ICM));
cpp = spp;
/* Clear interrupt pending flag */
outb(CMD_CLR_INTR, sh[j]->io_port + REG_SYS_INTR);
i = spp - HD(j)->cp;
/* Find the mailbox to be serviced on this board */
i = cpp - HD(j)->cp;
if (spp < HD(j)->cp || spp >= HD(j)->cp + sh[j]->can_queue
if (cpp < HD(j)->cp || cpp >= HD(j)->cp + sh[j]->can_queue
|| i >= sh[j]->can_queue)
panic("%s: ihdlr, invalid mscp bus address %p, cp0 %p.\n", BN(j),
(void *)ret, HD(j)->cp);
......@@ -1492,22 +1516,22 @@ static inline void ihdlr(int irq, void *shap, struct pt_regs *regs) {
}
else if (HD(j)->cp_stat[i] == IN_RESET)
printk("%s: ihdlr, mbox %d is in reset.\n", BN(j), i);
else if (HD(j)->cp_stat[i] != IN_USE)
panic("%s: ihdlr, mbox %d, invalid cp_stat: %d.\n",
else if (HD(j)->cp_stat[i] != IN_USE)
panic("%s: ihdlr, mbox %d, invalid cp_stat: %d.\n",
BN(j), i, HD(j)->cp_stat[i]);
HD(j)->cp_stat[i] = FREE;
SCpnt = spp->SCpnt;
SCpnt = cpp->SCpnt;
if (SCpnt == NULL) panic("%s: ihdlr, mbox %d, SCpnt == NULL.\n", BN(j), i);
if (SCpnt->host_scribble == NULL)
if (SCpnt->host_scribble == NULL)
panic("%s: ihdlr, mbox %d, pid %ld, SCpnt %p garbled.\n", BN(j), i,
SCpnt->pid, SCpnt);
if (*(unsigned int *)SCpnt->host_scribble != i)
panic("%s: ihdlr, mbox %d, pid %ld, index mismatch %d, irq %d.\n",
BN(j), i, SCpnt->pid, *(unsigned int *)SCpnt->host_scribble, irq);
if (*(unsigned int *)SCpnt->host_scribble != i)
panic("%s: ihdlr, mbox %d, pid %ld, index mismatch %d.\n",
BN(j), i, SCpnt->pid, *(unsigned int *)SCpnt->host_scribble);
if (linked_comm && SCpnt->device->queue_depth > 2
&& TLDEV(SCpnt->device->type))
......@@ -1519,7 +1543,7 @@ static inline void ihdlr(int irq, void *shap, struct pt_regs *regs) {
case ASOK: /* status OK */
/* Forces a reset if a disk drive keeps returning BUSY */
if (tstatus == BUSY && SCpnt->device->type != TYPE_TAPE)
if (tstatus == BUSY && SCpnt->device->type != TYPE_TAPE)
status = DID_ERROR << 16;
/* If there was a bus reset, redo operation on each target */
......@@ -1541,7 +1565,7 @@ static inline void ihdlr(int irq, void *shap, struct pt_regs *regs) {
if (spp->target_status && SCpnt->device->type == TYPE_DISK)
printk("%s: ihdlr, target %d.%d:%d, pid %ld, "\
"target_status 0x%x, sense key 0x%x.\n", BN(j),
"target_status 0x%x, sense key 0x%x.\n", BN(j),
SCpnt->channel, SCpnt->target, SCpnt->lun,
SCpnt->pid, spp->target_status,
SCpnt->sense_buffer[2]);
......@@ -1568,10 +1592,10 @@ static inline void ihdlr(int irq, void *shap, struct pt_regs *regs) {
case 0x96: /* Illegal SCSI command */
case 0xa3: /* SCSI bus reset error */
for (c = 0; c <= sh[j]->max_channel; c++)
for (k = 0; k < sh[j]->max_id; k++)
for (c = 0; c <= sh[j]->max_channel; c++)
for (k = 0; k < sh[j]->max_id; k++)
HD(j)->target_redo[k][c] = TRUE;
case 0x92: /* Data over/under-run */
......@@ -1581,7 +1605,7 @@ static inline void ihdlr(int irq, void *shap, struct pt_regs *regs) {
HD(j)->retries++;
HD(j)->last_retried_pid = SCpnt->pid;
}
else
else
status = DID_ERROR << 16;
break;
......@@ -1598,13 +1622,12 @@ static inline void ihdlr(int irq, void *shap, struct pt_regs *regs) {
}
SCpnt->result = status | spp->target_status;
HD(j)->iocount++;
#if defined (DEBUG_INTERRUPT)
if (SCpnt->result || do_trace)
if (SCpnt->result || do_trace)
#else
if ((spp->adapter_status != ASOK && HD(j)->iocount > 1000) ||
(spp->adapter_status != ASOK &&
(spp->adapter_status != ASOK &&
spp->adapter_status != ASST && HD(j)->iocount <= 1000) ||
do_trace || msg_byte(spp->target_status))
#endif
......@@ -1625,20 +1648,24 @@ static inline void ihdlr(int irq, void *shap, struct pt_regs *regs) {
return;
}
static void interrupt_handler(int irq, void *shap, struct pt_regs *regs) {
static void do_interrupt_handler(int irq, void *shap, struct pt_regs *regs) {
#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,95)
unsigned int j;
/* Check if the interrupt must be processed by this handler */
if ((j = (unsigned int)((char *)shap - sha)) >= num_boards) return;
#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,95)
{
unsigned long flags;
spin_lock_irqsave(&io_request_lock, flags);
ihdlr(irq, shap, regs);
ihdlr(irq, j);
spin_unlock_irqrestore(&io_request_lock, flags);
}
#else
ihdlr(irq, shap, regs);
ihdlr(irq, j);
#endif
}
int u14_34f_release(struct Scsi_Host *shpnt) {
......@@ -1649,11 +1676,11 @@ int u14_34f_release(struct Scsi_Host *shpnt) {
cli();
for (j = 0; sh[j] != NULL && sh[j] != shpnt; j++);
if (sh[j] == NULL) panic("%s: release, invalid Scsi_Host pointer.\n",
driver_name);
for (i = 0; i < sh[j]->can_queue; i++)
for (i = 0; i < sh[j]->can_queue; i++)
if ((&HD(j)->cp[i])->sglist) kfree((&HD(j)->cp[i])->sglist);
free_irq(sh[j]->irq, &sha[j]);
......
......@@ -13,7 +13,7 @@ int u14_34f_abort(Scsi_Cmnd *);
int u14_34f_reset(Scsi_Cmnd *, unsigned int);
int u14_34f_biosparam(Disk *, kdev_t, int *);
#define U14_34F_VERSION "4.04.00"
#define U14_34F_VERSION "4.20.00"
#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
......
......@@ -108,6 +108,7 @@ static elf_addr_t *
create_elf_tables(char *p, int argc, int envc,
struct elfhdr * exec,
unsigned long load_addr,
unsigned long load_bias,
unsigned long interp_load_addr, int ibcs)
{
elf_caddr_t *argv;
......@@ -173,7 +174,7 @@ create_elf_tables(char *p, int argc, int envc,
NEW_AUX_ENT(3, AT_PAGESZ, ELF_EXEC_PAGESIZE);
NEW_AUX_ENT(4, AT_BASE, interp_load_addr);
NEW_AUX_ENT(5, AT_FLAGS, 0);
NEW_AUX_ENT(6, AT_ENTRY, (elf_addr_t) exec->e_entry);
NEW_AUX_ENT(6, AT_ENTRY, load_bias + exec->e_entry);
NEW_AUX_ENT(7, AT_UID, (elf_addr_t) current->uid);
NEW_AUX_ENT(8, AT_EUID, (elf_addr_t) current->euid);
NEW_AUX_ENT(9, AT_GID, (elf_addr_t) current->gid);
......@@ -584,6 +585,7 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
current->mm->end_data = 0;
current->mm->end_code = 0;
current->mm->mmap = NULL;
current->flags &= ~PF_FORKNOEXEC;
elf_entry = (unsigned long) elf_ex.e_entry;
/* Do this immediately, since STACK_TOP as used in setup_arg_pages
......@@ -712,7 +714,7 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
bprm->argc,
bprm->envc,
(interpreter_type == INTERPRETER_ELF ? &elf_ex : NULL),
load_addr,
load_addr, load_bias,
interp_load_addr,
(interpreter_type == INTERPRETER_AOUT ? 0 : 1));
/* N.B. passed_fileno might not be initialized? */
......
/*
* $Id: nfsroot.c,v 1.43 1997/10/16 19:55:27 mj Exp $
* $Id: nfsroot.c,v 1.45 1998/03/07 10:44:46 mj Exp $
*
* Copyright (C) 1995, 1996 Gero Kuhlmann <gero@gkminix.han.de>
*
......@@ -59,6 +59,8 @@
* host IP address (but host name defaults to IP
* address anyway).
* Martin Mares : Use root_server_addr appropriately during setup.
* Martin Mares : Rewrote parameter parsing, now hopefully giving
* correct overriding.
*/
#include <linux/types.h>
......@@ -83,11 +85,9 @@
/* Default path we try to mount. "%s" gets replaced by our IP address */
#define NFS_ROOT "/tftpboot/%s"
#define NFS_ROOT_NAME_LEN 256
/* Parameters passed from the kernel command line */
static char nfs_root_name[NFS_ROOT_NAME_LEN] __initdata = "default";
static int nfs_params_parsed = 0;
static char nfs_root_name[256] __initdata = "";
/* Address of NFS server */
static __u32 servaddr __initdata = 0;
......@@ -150,19 +150,15 @@ static struct nfs_bool_opts {
/*
* Prepare the NFS data structure and parse any options. This tries to
* set as many values in the nfs_data structure as known right now.
* Extract IP address from the parameter string if needed. Note that we
* need to have root_server_addr set _before_ IPConfig gets called as it
* can override it.
*/
__initfunc(static int root_nfs_name(char *name))
__initfunc(static void root_nfs_parse_addr(char *name))
{
char buf[NFS_MAXPATHLEN];
char *cp, *cq, *options, *val;
int octets = 0;
char *cp, *cq;
if (nfs_params_parsed)
return nfs_params_parsed;
/* It is possible to override the server IP number here */
cp = cq = name;
while (octets < 4) {
while (*cp >= '0' && *cp <= '9')
......@@ -179,45 +175,20 @@ __initfunc(static int root_nfs_name(char *name))
if (*cp == ':')
*cp++ = '\0';
root_server_addr = in_aton(name);
name = cp;
strcpy(name, cp);
}
}
/* Clear the nfs_data structure and setup the server hostname */
memset(&nfs_data, 0, sizeof(nfs_data));
/* Set the name of the directory to mount */
if (root_server_path[0] && !strcmp(name, "default"))
strncpy(buf, root_server_path, NFS_MAXPATHLEN-1);
else
strncpy(buf, name, NFS_MAXPATHLEN-1);
buf[NFS_MAXPATHLEN-1] = '\0';
if ((options = strchr(buf, ',')))
*options++ = '\0';
if (!strcmp(buf, "default"))
strcpy(buf, NFS_ROOT);
cp = system_utsname.nodename;
if (strlen(buf) + strlen(cp) > NFS_MAXPATHLEN) {
printk(KERN_ERR "Root-NFS: Pathname for remote directory too long.\n");
return -1;
}
sprintf(nfs_path, buf, cp);
/* Set some default values */
nfs_port = -1;
nfs_data.version = NFS_MOUNT_VERSION;
nfs_data.flags = NFS_MOUNT_NONLM; /* No lockd in nfs root yet */
nfs_data.rsize = NFS_DEF_FILE_IO_BUFFER_SIZE;
nfs_data.wsize = NFS_DEF_FILE_IO_BUFFER_SIZE;
nfs_data.bsize = 0;
nfs_data.timeo = 7;
nfs_data.retrans = 3;
nfs_data.acregmin = 3;
nfs_data.acregmax = 60;
nfs_data.acdirmin = 30;
nfs_data.acdirmax = 60;
/*
* Parse option string.
*/
__initfunc(static void root_nfs_parse(char *name, char *buf))
{
char *options, *val, *cp;
/* Process any options */
if (options) {
if ((options = strchr(name, ','))) {
*options++ = 0;
cp = strtok(options, ",");
while (cp) {
if ((val = strchr(cp, '='))) {
......@@ -239,6 +210,50 @@ __initfunc(static int root_nfs_name(char *name))
cp = strtok(NULL, ",");
}
}
if (name[0] && strcmp(name, "default")) {
strncpy(buf, name, NFS_MAXPATHLEN-1);
buf[NFS_MAXPATHLEN-1] = 0;
}
}
/*
* Prepare the NFS data structure and parse all options.
*/
__initfunc(static int root_nfs_name(char *name))
{
char buf[NFS_MAXPATHLEN];
char *cp;
/* Set some default values */
memset(&nfs_data, 0, sizeof(nfs_data));
nfs_port = -1;
nfs_data.version = NFS_MOUNT_VERSION;
nfs_data.flags = NFS_MOUNT_NONLM; /* No lockd in nfs root yet */
nfs_data.rsize = NFS_DEF_FILE_IO_BUFFER_SIZE;
nfs_data.wsize = NFS_DEF_FILE_IO_BUFFER_SIZE;
nfs_data.bsize = 0;
nfs_data.timeo = 7;
nfs_data.retrans = 3;
nfs_data.acregmin = 3;
nfs_data.acregmax = 60;
nfs_data.acdirmin = 30;
nfs_data.acdirmax = 60;
strcpy(buf, NFS_ROOT);
/* Process options received from the remote server */
root_nfs_parse(root_server_path, buf);
/* Override them by options set on kernel command-line */
root_nfs_parse(name, buf);
cp = system_utsname.nodename;
if (strlen(buf) + strlen(cp) > NFS_MAXPATHLEN) {
printk(KERN_ERR "Root-NFS: Pathname for remote directory too long.\n");
return -1;
}
sprintf(nfs_path, buf, cp);
return 1;
}
......@@ -317,7 +332,7 @@ __initfunc(void nfs_root_setup(char *line, int *ints))
line[sizeof(nfs_root_name) - strlen(NFS_ROOT) - 1] = '\0';
sprintf(nfs_root_name, NFS_ROOT, line);
}
nfs_params_parsed = root_nfs_name(nfs_root_name);
root_nfs_parse_addr(nfs_root_name);
}
......
......@@ -2,6 +2,8 @@
* include/asm-alpha/serial.h
*/
#include <linux/config.h>
/*
* This assumes you have a 1.8432 MHz clock for your UART.
*
......
......@@ -2,6 +2,8 @@
* include/asm-i386/serial.h
*/
#include <linux/config.h>
/*
* This assumes you have a 1.8432 MHz clock for your UART.
*
......
......@@ -293,7 +293,7 @@ __asm__ __volatile__ ("movw %3,0(%2)\n\t" \
"movb $0,6(%2)\n\t" \
"movb %%ah,7(%2)\n\t" \
"rorl $16,%%eax" \
: "=m"(*(n)) : "a" (addr), "r"(n), "g"(limit), "i"(type))
: "=m"(*(n)) : "a" (addr), "r"(n), "ir"(limit), "i"(type))
#define set_tss_desc(n,addr) \
_set_tssldt_desc(((char *) (n)),((int)(addr)),235,0x89)
......
#include <linux/config.h>
#ifndef _ASM_IRQ_H
#define _ASM_IRQ_H
......
#include <linux/config.h>
#ifndef __PPC_MMU_CONTEXT_H
#define __PPC_MMU_CONTEXT_H
......
#include <linux/config.h>
#ifndef _PPC_PAGE_H
#define _PPC_PAGE_H
......
#include <linux/config.h>
#ifndef _PPC_PGTABLE_H
#define _PPC_PGTABLE_H
......
/* $Id: system.h,v 1.68 1998/03/09 14:04:51 jj Exp $ */
#include <linux/config.h>
#ifndef __SPARC_SYSTEM_H
#define __SPARC_SYSTEM_H
......
......@@ -3,6 +3,9 @@
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
*/
#include <linux/config.h>
#ifndef _SPARC_TIMER_H
#define _SPARC_TIMER_H
......
/*
* This is <linux/capability.h>
*
* Andrew G. Morgan <morgan@parc.power.net>
* Andrew G. Morgan <morgan@transmeta.com>
* Alexander Kjeldaas <astor@guardian.no>
* with help from Aleph1, Roland Buresund and Andrew Main.
*/
......
......@@ -283,7 +283,6 @@ extern __inline__ unsigned int parport_yield_blocking(struct pardevice *dev)
if ((dev->port->waithead == NULL) || (timeslip < dev->timeslice))
return 0;
parport_release(dev);
schedule();
return parport_claim_or_block(dev);
}
......
......@@ -113,7 +113,7 @@ int kmod_init(void)
* CLONE_FILES just saves some space (we don't need any
* new file descriptors). Ditto for CLONE_SIGHAND.
*/
kernel_thread(kmod_thread, NULL, CLONE_FILES |CLONE_FS | CLONE_SIGHAND);
kernel_thread(kmod_thread, NULL, CLONE_FILES | CLONE_FS | CLONE_SIGHAND);
kmod_unload_timer.next = NULL;
kmod_unload_timer.prev = NULL;
......
......@@ -273,10 +273,8 @@ unsigned long __get_free_pages(int gfp_mask, unsigned long order)
* "maxorder" is the highest order number that we're allowed
* to empty in order to find a free page..
*/
maxorder = order + NR_MEM_LISTS/3;
if (gfp_mask & __GFP_MED)
maxorder += NR_MEM_LISTS/3;
if ((gfp_mask & __GFP_HIGH) || maxorder > NR_MEM_LISTS)
maxorder = NR_MEM_LISTS-1;
if (gfp_mask & __GFP_HIGH)
maxorder = NR_MEM_LISTS;
if (in_interrupt() && (gfp_mask & __GFP_WAIT)) {
......@@ -295,6 +293,7 @@ unsigned long __get_free_pages(int gfp_mask, unsigned long order)
if (gfp_mask & __GFP_WAIT) {
int freed = try_to_free_pages(gfp_mask,SWAP_CLUSTER_MAX);
gfp_mask &= ~__GFP_WAIT; /* go through this only once */
maxorder = NR_MEM_LISTS; /* Allow anything this time */
if (freed)
goto repeat;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment