patch-2.1.95 linux/drivers/scsi/eata.c
Next file: linux/drivers/scsi/eata.h
Previous file: linux/drivers/scsi/aha1740.c
Back to the patch index
Back to the overall index
- Lines: 268
- Date:
Fri Apr 10 10:13:58 1998
- Orig file:
v2.1.94/linux/drivers/scsi/eata.c
- Orig date:
Mon Apr 6 17:41:00 1998
diff -u --recursive --new-file v2.1.94/linux/drivers/scsi/eata.c linux/drivers/scsi/eata.c
@@ -1,6 +1,14 @@
/*
* eata.c - Low-level driver for EATA/DMA SCSI host adapters.
*
+ * 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
+ * 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.
*
@@ -280,11 +288,14 @@
* the driver sets host->wish_block = TRUE for all ISA boards.
*/
+#include <linux/version.h>
+
#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
#define MAX_INT_PARAM 10
+
#if defined(MODULE)
#include <linux/module.h>
-#include <linux/version.h>
+
#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,26)
MODULE_PARM(io_port, "1-" __MODULE_STRING(MAX_INT_PARAM) "i");
MODULE_PARM(linked_comm, "i");
@@ -294,6 +305,7 @@
MODULE_PARM(tag_mode, "i");
MODULE_AUTHOR("Dario Ballabio");
#endif
+
#endif
#include <linux/string.h>
@@ -314,9 +326,12 @@
#include "eata.h"
#include <linux/stat.h>
#include <linux/config.h>
-#include <linux/bios32.h>
#include <linux/pci.h>
+#if LINUX_VERSION_CODE < LinuxVersionCode(2,1,93)
+#include <linux/bios32.h>
+#endif
+
#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,36)
#include <linux/init.h>
#else
@@ -338,6 +353,7 @@
#undef DEBUG_LINKED_COMMANDS
#undef DEBUG_DETECT
+#undef DEBUG_PCI_DETECT
#undef DEBUG_INTERRUPT
#undef DEBUG_RESET
@@ -583,7 +599,7 @@
#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 eata2x_interrupt_handler(int, void *, struct pt_regs *);
+static void 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;
@@ -715,10 +731,48 @@
return FALSE;
}
+__initfunc (static inline int
+ get_pci_irq(unsigned long port_base, unsigned char *apic_irq)) {
+
+#if defined(CONFIG_PCI)
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,93)
+
+ unsigned int addr;
+ struct pci_dev *dev = NULL;
+
+ if (!pci_present()) return FALSE;
+
+ while((dev = pci_find_class(PCI_CLASS_STORAGE_SCSI << 8, dev))) {
+
+ if (pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &addr)) continue;
+
+#if defined(DEBUG_PCI_DETECT)
+ printk("%s: get_pci_irq, bus %d, devfn 0x%x, addr 0x%x, apic_irq %u.\n",
+ driver_name, dev->bus->number, dev->devfn, addr, dev->irq);
+#endif
+
+ if ((addr & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO)
+ continue;
+
+ if ((addr & PCI_BASE_ADDRESS_IO_MASK) + PCI_BASE_ADDRESS_0 == port_base) {
+ *apic_irq = dev->irq;
+ return TRUE;
+ }
+
+ }
+
+#endif /* end new style PCI code */
+
+#endif /* end CONFIG_PCI */
+
+ return FALSE;
+}
+
__initfunc (static inline int port_detect \
(unsigned long port_base, unsigned int j, Scsi_Host_Template *tpnt)) {
unsigned char irq, dma_channel, subversion, i;
- unsigned char protocol_rev;
+ unsigned char protocol_rev, apic_irq;
struct eata_info info;
char *bus_type, dma_name[16], tag_type;
@@ -812,8 +866,13 @@
printk("%s: warning, LEVEL triggering is suggested for IRQ %u.\n",
name, irq);
+ if (get_pci_irq(port_base, &apic_irq) && (irq != apic_irq)) {
+ printk("%s: IRQ %u mapped to IO-APIC IRQ %u.\n", name, irq, apic_irq);
+ irq = apic_irq;
+ }
+
/* Board detected, allocate its IRQ */
- if (request_irq(irq, eata2x_interrupt_handler,
+ if (request_irq(irq, 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);
@@ -1016,21 +1075,49 @@
#if defined(CONFIG_PCI)
- unsigned short i = 0;
- unsigned char bus, devfn;
unsigned int addr, k;
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,93)
+
+ struct pci_dev *dev = NULL;
+
if (!pci_present()) return;
for (k = 0; k < MAX_PCI; k++) {
+ if (!(dev = pci_find_class(PCI_CLASS_STORAGE_SCSI << 8, dev))) break;
+
+ if (pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &addr)) continue;
+
+#if defined(DEBUG_PCI_DETECT)
+ printk("%s: detect, seq. %d, bus %d, devfn 0x%x, addr 0x%x.\n",
+ driver_name, k, dev->bus->number, dev->devfn, addr);
+#endif
+
+ if ((addr & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO)
+ continue;
+
+ /* Reverse the returned address order */
+ io_port[MAX_INT_PARAM + MAX_PCI - k] =
+ (addr & PCI_BASE_ADDRESS_IO_MASK) + PCI_BASE_ADDRESS_0;
+ }
+
+#else /* else old style PCI code */
+
+ unsigned short i = 0;
+ unsigned char bus, devfn;
+
+ if (!pcibios_present()) return;
+
+ for (k = 0; k < MAX_PCI; k++) {
+
if (pcibios_find_class(PCI_CLASS_STORAGE_SCSI << 8, i++, &bus, &devfn)
!= PCIBIOS_SUCCESSFUL) break;
if (pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, &addr)
!= PCIBIOS_SUCCESSFUL) continue;
-#if defined(DEBUG_DETECT)
+#if defined(DEBUG_PCI_DETECT)
printk("%s: detect, seq. %d, bus %d, devfn 0x%x, addr 0x%x.\n",
driver_name, k, bus, devfn, addr);
#endif
@@ -1042,7 +1129,10 @@
io_port[MAX_INT_PARAM + MAX_PCI - k] =
(addr & PCI_BASE_ADDRESS_IO_MASK) + PCI_BASE_ADDRESS_0;
}
-#endif
+
+#endif /* end old style PCI code */
+
+#endif /* end CONFIG_PCI */
return;
}
@@ -1523,6 +1613,7 @@
unsigned int input_only = TRUE, overlap = FALSE;
unsigned long sl[n_ready], pl[n_ready], ll[n_ready];
unsigned long maxsec = 0, minsec = ULONG_MAX, seek = 0, iseek = 0;
+ unsigned long ioseek = 0;
static unsigned int flushcount = 0, batchcount = 0, sortcount = 0;
static unsigned int readycount = 0, ovlcount = 0, inputcount = 0;
@@ -1547,6 +1638,7 @@
if (SCpnt->request.sector > maxsec) maxsec = SCpnt->request.sector;
sl[n] = SCpnt->request.sector;
+ ioseek += SCpnt->request.nr_sectors;
if (!n) continue;
@@ -1568,6 +1660,8 @@
if (cursec > ((maxsec + minsec) / 2)) rev = TRUE;
+ if (ioseek > ((maxsec - minsec) / 2)) rev = FALSE;
+
if (!((rev && r) || (!rev && s))) sort(sl, il, n_ready, rev);
if (!input_only) for (n = 0; n < n_ready; n++) {
@@ -1644,8 +1738,7 @@
}
-static void eata2x_interrupt_handler(int irq, void *shap,
- struct pt_regs *regs) {
+static inline void ihdlr(int irq, void *shap, struct pt_regs *regs) {
Scsi_Cmnd *SCpnt;
unsigned int i, j, k, c, status, tstatus, reg;
unsigned int n, n_ready, il[MAX_MAILBOXES];
@@ -1703,7 +1796,8 @@
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.\n", BN(j), i);
+ panic("%s: ihdlr, mbox %d, invalid cp_stat: %d.\n",
+ BN(j), i, HD(j)->cp_stat[i]);
HD(j)->cp_stat[i] = FREE;
cpp = &HD(j)->cp[i];
@@ -1839,6 +1933,22 @@
HD(j)->iocount);
return;
+}
+
+static void interrupt_handler(int irq, void *shap, struct pt_regs *regs) {
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,95)
+
+ unsigned long flags;
+ spin_lock_irqsave(&io_request_lock, flags);
+ ihdlr(irq, shap, regs);
+ spin_unlock_irqrestore(&io_request_lock, flags);
+
+#else
+
+ ihdlr(irq, shap, regs);
+
+#endif
}
int eata2x_release(struct Scsi_Host *shpnt) {
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov