/* --- IRQ detection -------------------------------------- */
-/* This code is for detecting ECP interrupts (due to problems with the
- * monolithic interrupt probing routines).
- *
- * In short this is a voting system where the interrupt with the most
- * "votes" is the elected interrupt (it SHOULD work...)
- *
- * This is horribly x86-specific at the moment. I'm not convinced it
- * belongs at all.
- */
-
-static int intr_vote[16];
-
-static void parport_vote_intr_func(int irq, void *dev_id, struct pt_regs *regs)
-{
- intr_vote[irq]++;
- return;
-}
-
-static long open_intr_election(void)
-{
- long tmp = 0;
- int i;
-
- /* We ignore the timer - irq 0 */
- for (i = 1; i < 16; i++) {
- intr_vote[i] = 0;
- if (request_irq(i, parport_vote_intr_func,
- SA_INTERRUPT, "probe", intr_vote) == 0)
- tmp |= 1 << i;
- }
- return tmp;
-}
-
-static int close_intr_election(long tmp)
-{
- int irq = PARPORT_IRQ_NONE;
- int i, valid = 1;
-
- /* We ignore the timer - irq 0 */
- for (i = 1; i < 16; i++)
- if (tmp & (1 << i)) {
- if (intr_vote[i]) {
- if (irq != PARPORT_IRQ_NONE)
- /* More than one interrupt */
- valid = 0;
- irq = i;
- }
- free_irq(i, intr_vote);
- }
- if(valid)
- return irq;
- else
- return PARPORT_IRQ_NONE;
-}
-
/* Only if supports ECP mode */
static int programmable_irq_support(struct parport *pb)
{
static int irq_probe_ECP(struct parport *pb)
{
int irqs, i;
- unsigned char oecr = parport_pc_read_econtrol(pb);
- probe_irq_off(probe_irq_on()); /* Clear any interrupts */
- irqs = open_intr_election();
+ sti();
+ irqs = probe_irq_on();
- parport_pc_write_econtrol(pb, 0x00); /* Reset FIFO */
- parport_pc_write_econtrol(pb, 0xd0); /* TEST FIFO + nErrIntrEn */
+ parport_pc_write_econtrol(pb, 0x00); /* Reset FIFO */
+ parport_pc_write_econtrol(pb, 0xd0); /* TEST FIFO + nErrIntrEn */
/* If Full FIFO sure that WriteIntrThresold is generated */
for (i=0; i < 1024 && !(parport_pc_read_econtrol(pb) & 0x02) ; i++)
parport_pc_write_fifo(pb, 0xaa);
- pb->irq = close_intr_election(irqs);
- parport_pc_write_econtrol(pb, oecr);
+ pb->irq = probe_irq_off(irqs);
+ parport_pc_write_econtrol(pb, 0x00);
+
+ if (pb->irq <= 0)
+ pb->irq = PARPORT_IRQ_NONE;
+
return pb->irq;
}
return PARPORT_IRQ_NONE;
#endif
- probe_irq_off(probe_irq_on()); /* Clear any interrupts */
- irqs = open_intr_election();
+ sti();
+ irqs = probe_irq_on();
if (pb->modes & PARPORT_MODE_PCECR)
- parport_pc_write_econtrol(pb, parport_pc_read_econtrol(pb) | 0x10);
+ parport_pc_frob_econtrol (pb, 0x10, 0x10);
epp_clear_timeout(pb);
- parport_pc_write_control(pb, parport_pc_read_control(pb) | 0x20);
- parport_pc_write_control(pb, parport_pc_read_control(pb) | 0x10);
+ parport_pc_frob_control (pb, 0x20, 0x20);
+ parport_pc_frob_control (pb, 0x10, 0x10);
epp_clear_timeout(pb);
- /* Device isn't expecting an EPP read
+ /* Device isn't expecting an EPP read
* and generates an IRQ.
*/
parport_pc_read_epp(pb);
udelay(20);
- pb->irq = close_intr_election(irqs);
+ pb->irq = probe_irq_off (irqs);
parport_pc_write_econtrol(pb, oecr);
parport_pc_write_control(pb, octr);
+
+ if (pb->irq <= 0)
+ pb->irq = PARPORT_IRQ_NONE;
+
return pb->irq;
}
*/
static int parport_irq_probe(struct parport *pb)
{
- if (pb->modes & PARPORT_MODE_PCECR)
+ unsigned char oecr = parport_pc_read_econtrol (pb);
+
+ if (pb->modes & PARPORT_MODE_PCECR) {
pb->irq = programmable_irq_support(pb);
+ if (pb->irq != PARPORT_IRQ_NONE)
+ goto out;
+ }
if (pb->modes & PARPORT_MODE_PCECP)
pb->irq = irq_probe_ECP(pb);
-
+
if (pb->irq == PARPORT_IRQ_NONE &&
(pb->modes & PARPORT_MODE_PCECPEPP)) {
- unsigned char oecr = parport_pc_read_econtrol(pb);
- parport_pc_write_econtrol(pb, 0x80);
pb->irq = irq_probe_EPP(pb);
parport_pc_write_econtrol(pb, oecr);
}
if (pb->irq == PARPORT_IRQ_NONE)
pb->irq = irq_probe_SPP(pb);
+out:
+ parport_pc_write_econtrol (pb, oecr);
return pb->irq;
}
/*
* 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.
*
* 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");
MODULE_PARM(tag_mode, "i");
MODULE_AUTHOR("Dario Ballabio");
#endif
+
#endif
#include <linux/string.h>
#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
#undef DEBUG_LINKED_COMMANDS
#undef DEBUG_DETECT
+#undef DEBUG_PCI_DETECT
#undef DEBUG_INTERRUPT
#undef DEBUG_RESET
#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;
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;
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);
#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)
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
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;
}
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;
if (SCpnt->request.sector > maxsec) maxsec = SCpnt->request.sector;
sl[n] = SCpnt->request.sector;
+ ioseek += SCpnt->request.nr_sectors;
if (!n) continue;
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++) {
}
-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];
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];
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) {
unsigned long flags;
unsigned int i, j;
#define _EATA_H
#include <scsi/scsicam.h>
+#include <linux/version.h>
int eata2x_detect(Scsi_Host_Template *);
int eata2x_release(struct Scsi_Host *);
int eata2x_abort(Scsi_Cmnd *);
int eata2x_reset(Scsi_Cmnd *, unsigned int);
-#define EATA_VERSION "4.02.00"
+#define EATA_VERSION "4.04.00"
#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
/*
* u14-34f.c - Low-level driver for UltraStor 14F/34F 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
+ * 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.
*
* 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");
MODULE_PARM(max_queue_depth, "i");
MODULE_AUTHOR("Dario Ballabio");
#endif
+
#endif
#include <linux/string.h>
#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 u14_34f_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;
subversion = (in_byte & 0x0f);
/* Board detected, allocate its IRQ */
- if (request_irq(irq, u14_34f_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);
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;
if (SCpnt->request.sector > maxsec) maxsec = SCpnt->request.sector;
sl[n] = SCpnt->request.sector;
+ ioseek += SCpnt->request.nr_sectors;
if (!n) continue;
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++) {
}
}
-static void u14_34f_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, ret;
struct mscp *spp;
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;
SCpnt = spp->SCpnt;
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 u14_34f_release(struct Scsi_Host *shpnt) {
unsigned long flags;
unsigned int i, j;
#ifndef _U14_34F_H
#define _U14_34F_H
+#include <linux/version.h>
+
int u14_34f_detect(Scsi_Host_Template *);
int u14_34f_release(struct Scsi_Host *);
int u14_34f_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
int u14_34f_reset(Scsi_Cmnd *, unsigned int);
int u14_34f_biosparam(Disk *, kdev_t, int *);
-#define U14_34F_VERSION "4.02.00"
+#define U14_34F_VERSION "4.04.00"
#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
return x;
}
-#define mb() __asm__ __volatile__ ("" : : :"memory")
+/*
+ * Force strict CPU ordering.
+ * And yes, this is required on UP too when we're talking
+ * to devices.
+ */
+#define mb() __asm__ __volatile__ ("lock; addl $0,0(%%esp)": : :"memory")
/* interrupt control.. */
#define __sti() __asm__ __volatile__ ("sti": : :"memory")