summaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1998-05-07 02:55:41 +0000
committerRalf Baechle <ralf@linux-mips.org>1998-05-07 02:55:41 +0000
commitdcec8a13bf565e47942a1751a9cec21bec5648fe (patch)
tree548b69625b18cc2e88c3e68d0923be546c9ebb03 /drivers/scsi
parent2e0f55e79c49509b7ff70ff1a10e1e9e90a3dfd4 (diff)
o Merge with Linux 2.1.99.
o Fix ancient bug in the ELF loader making ldd crash. o Fix ancient bug in the keyboard code for SGI, SNI and Jazz.
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/53c7,8xx.c80
-rw-r--r--drivers/scsi/53c7xx.c40
-rw-r--r--drivers/scsi/53c7xx.h8
-rw-r--r--drivers/scsi/AM53C974.c355
-rw-r--r--drivers/scsi/BusLogic.c892
-rw-r--r--drivers/scsi/BusLogic.h63
-rw-r--r--drivers/scsi/Config.in6
-rw-r--r--drivers/scsi/NCR5380.c25
-rw-r--r--drivers/scsi/NCR5380.h30
-rw-r--r--drivers/scsi/NCR53c406a.c16
-rw-r--r--drivers/scsi/README.BusLogic22
-rw-r--r--drivers/scsi/README.aic7xxx240
-rw-r--r--drivers/scsi/README.in20007
-rw-r--r--drivers/scsi/a2091.c13
-rw-r--r--drivers/scsi/a3000.c12
-rw-r--r--drivers/scsi/advansys.c28
-rw-r--r--drivers/scsi/aha1542.c15
-rw-r--r--drivers/scsi/aha1740.c5
-rw-r--r--drivers/scsi/aic7xxx.c8380
-rw-r--r--drivers/scsi/aic7xxx.h84
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx.reg237
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx.seq844
-rw-r--r--drivers/scsi/aic7xxx/scsi_message.h8
-rw-r--r--drivers/scsi/aic7xxx/sequencer.h39
-rw-r--r--drivers/scsi/aic7xxx_proc.c176
-rw-r--r--drivers/scsi/aic7xxx_reg.h157
-rw-r--r--drivers/scsi/aic7xxx_seq.h757
-rw-r--r--drivers/scsi/dtc.c2
-rw-r--r--drivers/scsi/dtc.h1
-rw-r--r--drivers/scsi/eata.c865
-rw-r--r--drivers/scsi/eata.h55
-rw-r--r--drivers/scsi/eata_dma.c15
-rw-r--r--drivers/scsi/eata_pio.c19
-rw-r--r--drivers/scsi/esp.c11
-rw-r--r--drivers/scsi/fdomain.c173
-rw-r--r--drivers/scsi/g_NCR5380.c2
-rw-r--r--drivers/scsi/g_NCR5380.h1
-rw-r--r--drivers/scsi/gdth.c56
-rw-r--r--drivers/scsi/gvp11.c12
-rw-r--r--drivers/scsi/hosts.c7
-rw-r--r--drivers/scsi/hosts.h24
-rw-r--r--drivers/scsi/ibmmca.c15
-rw-r--r--drivers/scsi/ide-scsi.c172
-rw-r--r--drivers/scsi/ide-scsi.h5
-rw-r--r--drivers/scsi/in2000.c26
-rw-r--r--drivers/scsi/in2000.h6
-rw-r--r--drivers/scsi/jazz_esp.c3
-rw-r--r--drivers/scsi/mac53c94.c14
-rw-r--r--drivers/scsi/mesh.c14
-rw-r--r--drivers/scsi/mvme16x.c1
-rw-r--r--drivers/scsi/ncr53c8xx.c225
-rw-r--r--drivers/scsi/ncr53c8xx.h11
-rw-r--r--drivers/scsi/pas16.c2
-rw-r--r--drivers/scsi/pas16.h1
-rw-r--r--drivers/scsi/pci2000.c33
-rw-r--r--drivers/scsi/pci2220i.c39
-rw-r--r--drivers/scsi/pluto.c31
-rw-r--r--drivers/scsi/pluto.h12
-rw-r--r--drivers/scsi/psi240i.c11
-rw-r--r--drivers/scsi/qlogicfas.c14
-rw-r--r--drivers/scsi/qlogicisp.c90
-rw-r--r--drivers/scsi/qlogicpti.c82
-rw-r--r--drivers/scsi/scsi.c68
-rw-r--r--drivers/scsi/scsi.h1
-rw-r--r--drivers/scsi/scsi_ioctl.c13
-rw-r--r--drivers/scsi/scsi_obsolete.c57
-rw-r--r--drivers/scsi/scsiiom.c9
-rw-r--r--drivers/scsi/sd.c31
-rw-r--r--drivers/scsi/seagate.c14
-rw-r--r--drivers/scsi/sg.c20
-rw-r--r--drivers/scsi/sgiwd93.c7
-rw-r--r--drivers/scsi/sparc_esp.c2
-rw-r--r--drivers/scsi/sr.c11
-rw-r--r--drivers/scsi/st.c8
-rw-r--r--drivers/scsi/t128.c2
-rw-r--r--drivers/scsi/t128.h1
-rw-r--r--drivers/scsi/tmscsim.c318
-rw-r--r--drivers/scsi/tmscsim.h17
-rw-r--r--drivers/scsi/u14-34f.c663
-rw-r--r--drivers/scsi/u14-34f.h53
-rw-r--r--drivers/scsi/ultrastor.c15
-rw-r--r--drivers/scsi/wd7000.c14
82 files changed, 9036 insertions, 6877 deletions
diff --git a/drivers/scsi/53c7,8xx.c b/drivers/scsi/53c7,8xx.c
index 092b8500a..2aad6a7f9 100644
--- a/drivers/scsi/53c7,8xx.c
+++ b/drivers/scsi/53c7,8xx.c
@@ -243,7 +243,6 @@ typedef unsigned int u32;
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/errno.h>
-#include <linux/bios32.h>
#include <linux/pci.h>
#include <linux/proc_fs.h>
#include <linux/string.h>
@@ -254,6 +253,7 @@ typedef unsigned int u32;
#include <linux/time.h>
#include <linux/blk.h>
#include <linux/init.h>
+#include <asm/spinlock.h>
#include "scsi.h"
#include "hosts.h"
@@ -291,6 +291,7 @@ static int NCR53c8xx_run_tests (struct Scsi_Host *host);
static int NCR53c8xx_script_len;
static int NCR53c8xx_dsa_len;
static void NCR53c7x0_intr(int irq, void *dev_id, struct pt_regs * regs);
+static void do_NCR53c7x0_intr(int irq, void *dev_id, struct pt_regs * regs);
static int ncr_halt (struct Scsi_Host *host);
static void intr_phase_mismatch (struct Scsi_Host *host, struct NCR53c7x0_cmd
*cmd);
@@ -1135,9 +1136,9 @@ NCR53c7x0_init (struct Scsi_Host *host) {
if (!search) {
#ifdef __powerpc__
- if (request_irq(host->irq, NCR53c7x0_intr, SA_SHIRQ, "53c7,8xx", NULL))
+ if (request_irq(host->irq, do_NCR53c7x0_intr, SA_SHIRQ, "53c7,8xx", NULL))
#else
- if (request_irq(host->irq, NCR53c7x0_intr, SA_INTERRUPT, "53c7,8xx", NULL))
+ if (request_irq(host->irq, do_NCR53c7x0_intr, SA_INTERRUPT, "53c7,8xx", NULL))
#endif
{
@@ -1413,53 +1414,46 @@ normal_init (Scsi_Host_Template *tpnt, int board, int chip,
__initfunc(static int
ncr_pci_init (Scsi_Host_Template *tpnt, int board, int chip,
unsigned char bus, unsigned char device_fn, long long options)) {
- unsigned short vendor_id, device_id, command;
+ unsigned short command;
#ifdef LINUX_1_2
unsigned long
#else
unsigned int
#endif
base, io_port;
- unsigned char irq, revision;
+ unsigned char revision;
int error, expected_chip;
int expected_id = -1, max_revision = -1, min_revision = -1;
- int i;
+ int i, irq;
+ struct pci_dev *pdev = pci_find_slot(bus, device_fn);
printk("scsi-ncr53c7,8xx : at PCI bus %d, device %d, function %d\n",
bus, (int) (device_fn & 0xf8) >> 3,
(int) device_fn & 7);
- if (!pcibios_present()) {
- printk("scsi-ncr53c7,8xx : not initializing due to lack of PCI BIOS,\n"
+ if (!pdev) {
+ printk("scsi-ncr53c7,8xx : not initializing -- PCI device not found,\n"
" try using memory, port, irq override instead.\n");
return -1;
}
- if ((error = pcibios_read_config_word (bus, device_fn, PCI_VENDOR_ID,
- &vendor_id)) ||
- (error = pcibios_read_config_word (bus, device_fn, PCI_DEVICE_ID,
- &device_id)) ||
- (error = pcibios_read_config_word (bus, device_fn, PCI_COMMAND,
+ if ((error = pcibios_read_config_word (bus, device_fn, PCI_COMMAND,
&command)) ||
- (error = pcibios_read_config_dword (bus, device_fn,
- PCI_BASE_ADDRESS_0, &io_port)) ||
- (error = pcibios_read_config_dword (bus, device_fn,
- PCI_BASE_ADDRESS_1, &base)) ||
(error = pcibios_read_config_byte (bus, device_fn, PCI_CLASS_REVISION,
- &revision)) ||
- (error = pcibios_read_config_byte (bus, device_fn, PCI_INTERRUPT_LINE,
- &irq))) {
- printk ("scsi-ncr53c7,8xx : error %s not initializing due to error reading configuration space\n"
- " perhaps you specified an incorrect PCI bus, device, or function.\n"
- , pcibios_strerror(error));
+ &revision))) {
+ printk ("scsi-ncr53c7,8xx : error %d not initializing due to error reading configuration space\n"
+ " perhaps you specified an incorrect PCI bus, device, or function.\n", error);
return -1;
}
+ io_port = pdev->base_address[0];
+ base = pdev->base_address[1];
+ irq = pdev->irq;
/* If any one ever clones the NCR chips, this will have to change */
- if (vendor_id != PCI_VENDOR_ID_NCR) {
+ if (pdev->vendor != PCI_VENDOR_ID_NCR) {
printk ("scsi-ncr53c7,8xx : not initializing, 0x%04x is not NCR vendor ID\n",
- (int) vendor_id);
+ (int) pdev->vendor);
return -1;
}
@@ -1467,14 +1461,16 @@ ncr_pci_init (Scsi_Host_Template *tpnt, int board, int chip,
if ( ! (command & PCI_COMMAND_MASTER)) {
printk("SCSI: PCI Master Bit has not been set. Setting...\n");
command |= PCI_COMMAND_MASTER|PCI_COMMAND_IO;
- pcibios_write_config_word(bus, device_fn, PCI_COMMAND, command);
- if (io_port >= 0x10000000) {
+ pci_write_config_word(pdev, PCI_COMMAND, command);
+
+ if (io_port >= 0x10000000 && is_prep ) {
/* Mapping on PowerPC can't handle this! */
unsigned long new_io_port;
new_io_port = (io_port & 0x00FFFFFF) | 0x01000000;
printk("SCSI: I/O moved from %08X to %08x\n", io_port, new_io_port);
io_port = new_io_port;
- pcibios_write_config_dword(bus, device_fn, PCI_BASE_ADDRESS_0, io_port);
+ pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, io_port);
+ pdev->base_address[0] = io_port;
}
}
#endif
@@ -1519,7 +1515,7 @@ ncr_pci_init (Scsi_Host_Template *tpnt, int board, int chip,
}
for (i = 0; i < NPCI_CHIP_IDS; ++i) {
- if (device_id == pci_chip_ids[i].pci_device_id) {
+ if (pdev->device == pci_chip_ids[i].pci_device_id) {
max_revision = pci_chip_ids[i].max_revision;
min_revision = pci_chip_ids[i].min_revision;
expected_chip = pci_chip_ids[i].chip;
@@ -1528,10 +1524,10 @@ ncr_pci_init (Scsi_Host_Template *tpnt, int board, int chip,
expected_id = pci_chip_ids[i].pci_device_id;
}
- if (chip && device_id != expected_id)
+ if (chip && pdev->device != expected_id)
printk ("scsi-ncr53c7,8xx : warning : device id of 0x%04x doesn't\n"
" match expected 0x%04x\n",
- (unsigned int) device_id, (unsigned int) expected_id );
+ (unsigned int) pdev->device, (unsigned int) expected_id );
if (max_revision != -1 && revision > max_revision)
printk ("scsi-ncr53c7,8xx : warning : revision of %d is greater than %d.\n",
@@ -1598,7 +1594,7 @@ NCR53c7xx_detect(Scsi_Host_Template *tpnt)) {
}
}
- if (pcibios_present()) {
+ if (pci_present()) {
for (i = 0; i < NPCI_CHIP_IDS; ++i)
for (pci_index = 0;
!pcibios_find_device (PCI_VENDOR_ID_NCR,
@@ -4396,6 +4392,22 @@ intr_scsi (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) {
}
/*
+ * Function : do_NCR53c7x0_intr()
+ *
+ * Purpose : A quick wrapper function added to grab the io_request_lock
+ * spin lock prior to entering the real interrupt handler. Needed
+ * for 2.1.95 and above.
+ */
+static void
+do_NCR53c7x0_intr(int irq, void *dev_id, struct pt_regs * regs) {
+ unsigned long flags;
+
+ spin_lock_irqsave(&io_request_lock, flags);
+ NCR53c7x0_intr(irq, dev_id, regs);
+ spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
+/*
* Function : static void NCR53c7x0_intr (int irq, void *dev_id, struct pt_regs * regs)
*
* Purpose : handle NCR53c7x0 interrupts for all NCR devices sharing
@@ -5130,8 +5142,8 @@ intr_bf (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) {
pci_status &= ~PCI_STATUS_PARITY;
}
} else {
- printk ("scsi%d : couldn't read status register : %s\n",
- host->host_no, pcibios_strerror (tmp));
+ printk ("scsi%d : couldn't read status register : error %d\n",
+ host->host_no, tmp);
retry = NEVER;
}
}
diff --git a/drivers/scsi/53c7xx.c b/drivers/scsi/53c7xx.c
index 93a30f3e9..be68e101d 100644
--- a/drivers/scsi/53c7xx.c
+++ b/drivers/scsi/53c7xx.c
@@ -244,8 +244,6 @@
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/errno.h>
-#include <linux/bios32.h>
-#include <linux/pci.h>
#include <linux/proc_fs.h>
#include <linux/string.h>
#include <linux/malloc.h>
@@ -254,6 +252,7 @@
#include <linux/ioport.h>
#include <linux/time.h>
#include <linux/blk.h>
+#include <asm/spinlock.h>
#ifdef CONFIG_AMIGA
#include <asm/pgtable.h>
@@ -315,7 +314,8 @@ static int shutdown (struct Scsi_Host *host);
static void abnormal_finished (struct NCR53c7x0_cmd *cmd, int result);
static int disable (struct Scsi_Host *host);
static int NCR53c7xx_run_tests (struct Scsi_Host *host);
-void NCR53c7x0_intr(int irq, void *dev_id, struct pt_regs * regs);
+static void NCR53c7x0_intr(int irq, void *dev_id, struct pt_regs * regs);
+static void do_NCR53c7x0_intr(int irq, void *dev_id, struct pt_regs * regs);
static int ncr_halt (struct Scsi_Host *host);
static void intr_phase_mismatch (struct Scsi_Host *host, struct NCR53c7x0_cmd
*cmd);
@@ -670,6 +670,7 @@ find_host (int host) {
return h;
}
+#if 0
/*
* Function : request_synchronous (int host, int target)
*
@@ -717,6 +718,7 @@ request_synchronous (int host, int target) {
restore_flags(flags);
return 0;
}
+#endif
/*
* Function : request_disconnect (int host, int on_or_off)
@@ -1069,10 +1071,10 @@ NCR53c7x0_init (struct Scsi_Host *host) {
*/
#ifdef CONFIG_MVME16x
- if (request_irq(IRQ_MVME16x_SCSI, NCR53c7x0_intr, 0, "SCSI-script", NULL))
+ if (request_irq(IRQ_MVME16x_SCSI, do_NCR53c7x0_intr, 0, "SCSI-script", NULL))
panic ("Couldn't get SCSI IRQ");
#ifdef MVME16x_INTFLY
- else if (request_irq(IRQ_MVME16x_FLY, NCR53c7x0_intr, 0, "SCSI-intfly", NULL))
+ else if (request_irq(IRQ_MVME16x_FLY, do_NCR53c7x0_intr, 0, "SCSI-intfly", NULL))
panic ("Couldn't get INT_FLY IRQ");
#endif
#else
@@ -1081,9 +1083,9 @@ NCR53c7x0_init (struct Scsi_Host *host) {
if (!search) {
#ifdef CONFIG_AMIGA
- if (request_irq(IRQ_AMIGA_PORTS, NCR53c7x0_intr, 0, "53c7xx", NCR53c7x0_intr)) {
+ if (request_irq(IRQ_AMIGA_PORTS, do_NCR53c7x0_intr, 0, "53c7xx", NCR53c7x0_intr)) {
#else
- if (request_irq(host->irq, NCR53c7x0_intr, SA_INTERRUPT, "53c7xx", NULL)) {
+ if (request_irq(host->irq, do_NCR53c7x0_intr, SA_INTERRUPT, "53c7xx", NULL)) {
#endif
printk("scsi%d : IRQ%d not free, detaching\n"
" You have either a configuration problem, or a\n"
@@ -1121,16 +1123,12 @@ NCR53c7x0_init (struct Scsi_Host *host) {
/*
* Function : static int ncr53c7xx_init(Scsi_Host_Template *tpnt, int board,
- * int chip, u32 base, int io_port, int irq, int dma,
- * long long options, int clock);
+ * int chip, u32 base, int io_port, int irq, int dma, long long options,
+ * int clock);
*
* Purpose : initializes a NCR53c7,8x0 based on base addresses,
* IRQ, and DMA channel.
*
- * Useful where a new NCR chip is backwards compatible with
- * a supported chip, but the DEVICE ID has changed so it
- * doesn't show up when the autoprobe does a pcibios_find_device.
- *
* Inputs : tpnt - Template for this SCSI adapter, board - board level
* product, chip - 710
*
@@ -4072,6 +4070,20 @@ void dump_log(void)
}
#endif
+/* Function : NCR53c7x0_intr
+ *
+ * Purpose : grab the global io_request_lock spin lock before entering the
+ * real interrupt routine.
+ */
+static void
+do_NCR53c7x0_intr (int irq, void *dev_id, struct pt_regs * regs) {
+ unsigned long flags;
+
+ spin_lock_irqsave(&io_request_lock, flags);
+ NCR53c7x0_intr(irq, dev_id, regs);
+ spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
/*
* Function : static void NCR53c7x0_intr (int irq, void *dev_id, struct pt_regs * regs)
*
@@ -4086,7 +4098,7 @@ void dump_log(void)
* script interrupt handler will call back to this function.
*/
-void
+static void
NCR53c7x0_intr (int irq, void *dev_id, struct pt_regs * regs) {
NCR53c7x0_local_declare();
struct Scsi_Host *host; /* Host we are looking at */
diff --git a/drivers/scsi/53c7xx.h b/drivers/scsi/53c7xx.h
index a2a53f107..cbbcbf02f 100644
--- a/drivers/scsi/53c7xx.h
+++ b/drivers/scsi/53c7xx.h
@@ -1247,14 +1247,6 @@ struct NCR53c7x0_hostdata {
digits of part number */
char valid_ids[8]; /* Valid SCSI ID's for adapter */
- /*
- * PCI bus, device, function, only for NCR53c8x0 chips.
- * pci_valid indicates that the PCI configuration information
- * is valid, and we can twiddle MAX_LAT, etc. as recommended
- * for maximum performance in the NCR documentation.
- */
- unsigned char pci_bus, pci_device_fn;
- unsigned pci_valid:1;
u32 *dsp; /* dsp to restart with after
all stacked interrupts are
diff --git a/drivers/scsi/AM53C974.c b/drivers/scsi/AM53C974.c
index f19065027..2f5fb197d 100644
--- a/drivers/scsi/AM53C974.c
+++ b/drivers/scsi/AM53C974.c
@@ -3,7 +3,6 @@
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/errno.h>
-#include <linux/bios32.h>
#include <linux/pci.h>
#include <linux/string.h>
#include <linux/blk.h>
@@ -11,6 +10,7 @@
#include <asm/io.h>
#include <asm/system.h>
+#include <asm/spinlock.h>
#include "scsi.h"
#include "hosts.h"
@@ -35,6 +35,8 @@
* Robin Cutshaw (robin@xfree86.org) and is used here in a
* slightly modified form.
*
+ * PCI detection rewritten by Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+ *
* For the remaining code:
* Copyright 1994, D. Frieauff
* EMail: fri@rsx42sun0.dofn.de
@@ -189,23 +191,6 @@
#define DEF_RAE 0 /* CNTLREG4, RAE active negation on REQ, ACK only */
#define DEF_RADE 1 /* 1CNTLREG4, active negation on REQ, ACK and data */
-/*** PCI block ***/
-/* standard registers are defined in <linux/pci.h> */
-#ifndef PCI_VENDOR_ID_AMD
-#define PCI_VENDOR_ID_AMD 0x1022
-#define PCI_DEVICE_ID_AMD_SCSI 0x2020
-#endif
-#define PCI_BASE_MASK 0xFFFFFFE0
-#define PCI_COMMAND_PERREN 0x40
-#define PCI_SCRATCH_REG_0 0x40 /* 16 bits */
-#define PCI_SCRATCH_REG_1 0x42 /* 16 bits */
-#define PCI_SCRATCH_REG_2 0x44 /* 16 bits */
-#define PCI_SCRATCH_REG_3 0x46 /* 16 bits */
-#define PCI_SCRATCH_REG_4 0x48 /* 16 bits */
-#define PCI_SCRATCH_REG_5 0x4A /* 16 bits */
-#define PCI_SCRATCH_REG_6 0x4C /* 16 bits */
-#define PCI_SCRATCH_REG_7 0x4E /* 16 bits */
-
/*** SCSI block ***/
#define CTCLREG 0x00 /* r current transf. count, low byte */
#define CTCMREG 0x04 /* r current transf. count, middle byte */
@@ -363,113 +348,21 @@ typedef struct _override_t {
int max_offset; /* max. sync. offset, 0 = asynchronous */
} override_t;
-/************ PCI stuff *************/
-#define AM53C974_PCIREG_OPEN() outb(0xF1, 0xCF8); outb(0, 0xCFA)
-#define AM53C974_PCIREG_CLOSE() outb(0, 0xCF8)
-#define AM53C974_PCIREG_READ_BYTE(instance,a) ( inb((a) + (instance)->io_port) )
-#define AM53C974_PCIREG_READ_WORD(instance,a) ( inw((a) + (instance)->io_port) )
-#define AM53C974_PCIREG_READ_DWORD(instance,a) ( inl((a) + (instance)->io_port) )
-#define AM53C974_PCIREG_WRITE_BYTE(instance,x,a) ( outb((x), (a) + (instance)->io_port) )
-#define AM53C974_PCIREG_WRITE_WORD(instance,x,a) ( outw((x), (a) + (instance)->io_port) )
-#define AM53C974_PCIREG_WRITE_DWORD(instance,x,a) ( outl((x), (a) + (instance)->io_port) )
-
-typedef struct _pci_config_t {
- /* start of official PCI config space header */
- union {
- unsigned int device_vendor;
- struct {
- unsigned short vendor;
- unsigned short device;
- } dv;
- } dv_id;
-#define _device_vendor dv_id.device_vendor
-#define _vendor dv_id.dv.vendor
-#define _device dv_id.dv.device
- union {
- unsigned int status_command;
- struct {
- unsigned short command;
- unsigned short status;
- } sc;
- } stat_cmd;
-#define _status_command stat_cmd.status_command
-#define _command stat_cmd.sc.command
-#define _status stat_cmd.sc.status
- union {
- unsigned int class_revision;
- struct {
- unsigned char rev_id;
- unsigned char prog_if;
- unsigned char sub_class;
- unsigned char base_class;
- } cr;
- } class_rev;
-#define _class_revision class_rev.class_revision
-#define _rev_id class_rev.cr.rev_id
-#define _prog_if class_rev.cr.prog_if
-#define _sub_class class_rev.cr.sub_class
-#define _base_class class_rev.cr.base_class
- union {
- unsigned int bist_header_latency_cache;
- struct {
- unsigned char cache_line_size;
- unsigned char latency_timer;
- unsigned char header_type;
- unsigned char bist;
- } bhlc;
- } bhlc;
-#define _bist_header_latency_cache bhlc.bist_header_latency_cache
-#define _cache_line_size bhlc.bhlc.cache_line_size
-#define _latency_timer bhlc.bhlc.latency_timer
-#define _header_type bhlc.bhlc.header_type
-#define _bist bhlc.bhlc.bist
- unsigned int _base0;
- unsigned int _base1;
- unsigned int _base2;
- unsigned int _base3;
- unsigned int _base4;
- unsigned int _base5;
- unsigned int rsvd1;
- unsigned int rsvd2;
- unsigned int _baserom;
- unsigned int rsvd3;
- unsigned int rsvd4;
- union {
- unsigned int max_min_ipin_iline;
- struct {
- unsigned char int_line;
- unsigned char int_pin;
- unsigned char min_gnt;
- unsigned char max_lat;
- } mmii;
- } mmii;
-#define _max_min_ipin_iline mmii.max_min_ipin_iline
-#define _int_line mmii.mmii.int_line
-#define _int_pin mmii.mmii.int_pin
-#define _min_gnt mmii.mmii.min_gnt
-#define _max_lat mmii.mmii.max_lat
- /* end of official PCI config space header */
- unsigned short _ioaddr; /* config type 1 - private I/O addr */
- unsigned int _pcibus; /* config type 2 - private bus id */
- unsigned int _cardnum; /* config type 2 - private card number */
-} pci_config_t;
-
#ifdef AM53C974_DEBUG
-static void AM53C974_print_pci(struct Scsi_Host *instance);
static void AM53C974_print_phase(struct Scsi_Host *instance);
static void AM53C974_print_queues(struct Scsi_Host *instance);
#endif /* AM53C974_DEBUG */
static void AM53C974_print(struct Scsi_Host *instance);
static void AM53C974_keywait(void);
-static __inline__ int AM53C974_bios_detect(Scsi_Host_Template *tpnt);
-static __inline__ int AM53C974_nobios_detect(Scsi_Host_Template *tpnt);
-static int AM53C974_init(Scsi_Host_Template *tpnt, pci_config_t pci_config);
+static __inline__ int AM53C974_pci_detect(Scsi_Host_Template *tpnt);
+static int AM53C974_init(Scsi_Host_Template *tpnt, struct pci_dev *pdev);
static void AM53C974_config_after_reset(struct Scsi_Host *instance);
static __inline__ void initialize_SCp(Scsi_Cmnd *cmd);
static __inline__ void run_main(void);
static void AM53C974_main (void);
static void AM53C974_intr(int irq, void *dev_id, struct pt_regs *regs);
+static void do_AM53C974_intr(int irq, void *dev_id, struct pt_regs *regs);
static void AM53C974_intr_disconnect(struct Scsi_Host *instance);
static int AM53C974_sync_neg(struct Scsi_Host *instance, int target, unsigned char *msg);
static __inline__ void AM53C974_set_async(struct Scsi_Host *instance, int target);
@@ -502,52 +395,6 @@ struct proc_dir_entry proc_scsi_am53c974 = {
#ifdef AM53C974_DEBUG
static int deb_stop = 1;
-/**************************************************************************
- * Function : void AM53C974_print_pci(struct Scsi_Host *instance)
- *
- * Purpose : dump the PCI registers for debugging purposes
- *
- * Input : instance - which AM53C974
- **************************************************************************/
-static void AM53C974_print_pci(struct Scsi_Host *instance)
-{
-int i;
-unsigned short vendor_id, device_id, command, status, scratch[8];
-unsigned long class_revision, base;
-unsigned char irq, cache_line_size, latency_timer, header_type;
-
-AM53C974_PCIREG_OPEN();
-
-for (i = 0; i < 8; i++) *(scratch + i) = AM53C974_PCIREG_READ_WORD(instance, PCI_SCRATCH_REG_0 + 2*i);
-vendor_id = AM53C974_PCIREG_READ_WORD(instance, PCI_VENDOR_ID);
-device_id = AM53C974_PCIREG_READ_WORD(instance, PCI_DEVICE_ID);
-command = AM53C974_PCIREG_READ_WORD(instance, PCI_COMMAND);
-status = AM53C974_PCIREG_READ_WORD(instance, PCI_STATUS);
-class_revision = AM53C974_PCIREG_READ_DWORD(instance, PCI_CLASS_REVISION);
-cache_line_size = AM53C974_PCIREG_READ_BYTE(instance, PCI_CACHE_LINE_SIZE);
-latency_timer = AM53C974_PCIREG_READ_BYTE(instance, PCI_LATENCY_TIMER);
-header_type = AM53C974_PCIREG_READ_BYTE(instance, PCI_HEADER_TYPE);
-base = AM53C974_PCIREG_READ_DWORD(instance, PCI_BASE_ADDRESS_0);
-irq = AM53C974_PCIREG_READ_BYTE(instance, PCI_INTERRUPT_LINE);
-
-AM53C974_PCIREG_CLOSE();
-
-
-printk("------------- start of PCI register dump -------------\n");
-printk("PCI_VENDOR_ID: 0x%x\n", vendor_id);
-printk("PCI_DEVICE_ID: 0x%x\n", device_id);
-printk("PCI_COMMAND: 0x%x\n", command);
-printk("PCI_STATUS: 0x%x\n", status);
-printk("PCI_CLASS_REVISION: 0x%lx\n", class_revision);
-printk("PCI_CACHE_LINE_SIZE: 0x%x\n", cache_line_size);
-printk("PCI_LATENCY_TIMER: 0x%x\n", latency_timer);
-printk("PCI_HEADER_TYPE: 0x%x\n", header_type);
-printk("PCI_BASE_ADDRESS_0: 0x%lx\n", base);
-printk("PCI_INTERRUPT_LINE: %d\n", irq);
-for (i = 0; i < 8; i++) printk("PCI_SCRATCH_%d: 0x%x\n", i, scratch[i]);
-printk("------------- end of PCI register dump -------------\n\n");
-}
-
static struct {
unsigned char value;
char *name;
@@ -732,7 +579,7 @@ if (ints[0] < 4)
#if defined (CONFIG_PCI)
/**************************************************************************
-* Function : int AM53C974_bios_detect(Scsi_Host_Template *tpnt)
+* Function : int AM53C974_pci_detect(Scsi_Host_Template *tpnt)
*
* Purpose : detects and initializes AM53C974 SCSI chips with PCI Bios
*
@@ -740,161 +587,34 @@ if (ints[0] < 4)
*
* Returns : number of host adapters detected
**************************************************************************/
-static __inline__ int AM53C974_bios_detect(Scsi_Host_Template *tpnt)
+static __inline__ int AM53C974_pci_detect(Scsi_Host_Template *tpnt)
{
int count = 0; /* number of boards detected */
-int pci_index;
-pci_config_t pci_config;
-
-for (pci_index = 0; pci_index <= 16; ++pci_index) {
- unsigned char pci_bus, pci_device_fn;
- if (pcibios_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_SCSI, pci_index, &pci_bus, &pci_device_fn) != 0)
- break;
-
- pcibios_read_config_word(pci_bus, pci_device_fn, PCI_VENDOR_ID, &pci_config._vendor);
- pcibios_read_config_word(pci_bus, pci_device_fn, PCI_DEVICE_ID, &pci_config._device);
- pcibios_read_config_word(pci_bus, pci_device_fn, PCI_COMMAND, &pci_config._command);
- pcibios_read_config_word(pci_bus, pci_device_fn, PCI_STATUS, &pci_config._status);
- pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_CLASS_REVISION, &pci_config._class_revision);
- pcibios_read_config_byte(pci_bus, pci_device_fn, PCI_CACHE_LINE_SIZE, &pci_config._cache_line_size);
- pcibios_read_config_byte(pci_bus, pci_device_fn, PCI_LATENCY_TIMER, &pci_config._latency_timer);
- pcibios_read_config_byte(pci_bus, pci_device_fn, PCI_HEADER_TYPE, &pci_config._header_type);
- pcibios_read_config_byte(pci_bus, pci_device_fn, PCI_BIST, &pci_config._bist);
- pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_0, &pci_config._base0);
- pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_1, &pci_config._base1);
- pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_2, &pci_config._base2);
- pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_3, &pci_config._base3);
- pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_4, &pci_config._base4);
- pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_5, &pci_config._base5);
- pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_ROM_ADDRESS, &pci_config._baserom);
- pcibios_read_config_byte(pci_bus, pci_device_fn, PCI_INTERRUPT_LINE, &pci_config._int_line);
- pcibios_read_config_byte(pci_bus, pci_device_fn, PCI_INTERRUPT_PIN, &pci_config._int_pin);
- pcibios_read_config_byte(pci_bus, pci_device_fn, PCI_MIN_GNT, &pci_config._min_gnt);
- pcibios_read_config_byte(pci_bus, pci_device_fn, PCI_MAX_LAT, &pci_config._max_lat);
- pci_config._pcibus = 0xFFFFFFFF;
- pci_config._cardnum = 0xFFFFFFFF;
-
+struct pci_dev *pdev = NULL;
+unsigned short command;
+
+while ((pdev = pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_SCSI, pdev))) {
+ pci_read_config_word(pdev, PCI_COMMAND, &command);
+
/* check whether device is I/O mapped -- should be */
- if (!(pci_config._command & PCI_COMMAND_IO)) continue;
+ if (!(command & PCI_COMMAND_IO)) continue;
/* PCI Spec 2.1 states that it is either the driver's or the PCI card's responsibility
to set the PCI Master Enable Bit if needed.
(from Mark Stockton <marks@schooner.sys.hou.compaq.com>) */
- if (!(pci_config._command & PCI_COMMAND_MASTER)) {
- pci_config._command |= PCI_COMMAND_MASTER;
+ if (!(command & PCI_COMMAND_MASTER)) {
+ command |= PCI_COMMAND_MASTER;
printk("PCI Master Bit has not been set. Setting...\n");
- pcibios_write_config_word(pci_bus, pci_device_fn, PCI_COMMAND, pci_config._command); }
+ pci_write_config_word(pdev, PCI_COMMAND, command); }
/* everything seems OK now, so initialize */
- if (AM53C974_init(tpnt, pci_config)) count++ ;
+ if (AM53C974_init(tpnt, pdev)) count++ ;
}
return (count);
}
#endif
/**************************************************************************
-* Function : int AM53C974_nobios_detect(Scsi_Host_Template *tpnt)
-*
-* Purpose : detects and initializes AM53C974 SCSI chips using PCI config 2
-*
-* Inputs : tpnt - host template
-*
-* Returns : number of host adapters detected
-*
-* NOTE : This code assumes the controller on PCI bus 0.
-*
-* Origin: Robin Cutshaw (robin@xfree86.org)
-**************************************************************************/
-static __inline__ int AM53C974_nobios_detect(Scsi_Host_Template *tpnt)
-{
-int count = 0; /* number of boards detected */
-pci_config_t pci_config;
-
-/* first try PCI config method 1 */
-for (pci_config._pcibus = 0; pci_config._pcibus < 0x10; pci_config._pcibus++) {
- for (pci_config._cardnum = 0; pci_config._cardnum < 0x20; pci_config._cardnum++) {
- unsigned long config_cmd;
- config_cmd = 0x80000000 | (pci_config._pcibus<<16) | (pci_config._cardnum<<11);
-
- outl(config_cmd, 0xCF8); /* ioreg 0 */
- pci_config._device_vendor = inl(0xCFC);
-
- if ((pci_config._vendor == PCI_VENDOR_ID_AMD) && (pci_config._device == PCI_DEVICE_ID_AMD_SCSI)) {
- outl(config_cmd | PCI_COMMAND, 0xCF8); pci_config._status_command = inl(0xCFC);
- outl(config_cmd | PCI_CLASS_REVISION, 0xCF8); pci_config._class_revision = inl(0xCFC);
- outl(config_cmd | PCI_CACHE_LINE_SIZE, 0xCF8); pci_config._bist_header_latency_cache = inl(0xCFC);
- outl(config_cmd | PCI_BASE_ADDRESS_0, 0xCF8); pci_config._base0 = inl(0xCFC);
- outl(config_cmd | PCI_BASE_ADDRESS_1, 0xCF8); pci_config._base1 = inl(0xCFC);
- outl(config_cmd | PCI_BASE_ADDRESS_2, 0xCF8); pci_config._base2 = inl(0xCFC);
- outl(config_cmd | PCI_BASE_ADDRESS_3, 0xCF8); pci_config._base3 = inl(0xCFC);
- outl(config_cmd | PCI_BASE_ADDRESS_4, 0xCF8); pci_config._base4 = inl(0xCFC);
- outl(config_cmd | PCI_BASE_ADDRESS_5, 0xCF8); pci_config._base5 = inl(0xCFC);
- outl(config_cmd | PCI_ROM_ADDRESS, 0xCF8); pci_config._baserom = inl(0xCFC);
- outl(config_cmd | PCI_INTERRUPT_LINE, 0xCF8); pci_config._max_min_ipin_iline = inl(0xCFC);
-
- /* check whether device is I/O mapped -- should be */
- if (!(pci_config._command & PCI_COMMAND_IO)) continue;
-
- /* PCI Spec 2.1 states that it is either the driver's or the PCI card's responsibility
- to set the PCI Master Enable Bit if needed.
- From Mark Stockton <marks@schooner.sys.hou.compaq.com> */
- if (!(pci_config._command & PCI_COMMAND_MASTER)) {
- pci_config._command |= PCI_COMMAND_MASTER;
- printk("Config 1; PCI Master Bit has not been set. Setting...\n");
- outl(config_cmd | PCI_COMMAND, 0xCF8); outw(pci_config._command, 0xCFC); }
-
- /* everything seems OK now, so initialize */
- if (AM53C974_init(tpnt, pci_config)) count++ ;
- }
- }
- }
-outb(0, 0xCF8); /* is this really necessary? */
-
-/* try PCI config method 2, if no device was detected by method 1 */
-if (!count) {
- AM53C974_PCIREG_OPEN();
-
- pci_config._pcibus = 0xFFFFFFFF;
- pci_config._cardnum = 0xFFFFFFFF;
-
- for (pci_config._ioaddr = 0xC000; pci_config._ioaddr < 0xD000; pci_config._ioaddr += 0x0100) {
- pci_config._device_vendor = inl(pci_config._ioaddr);
-
- if ((pci_config._vendor == PCI_VENDOR_ID_AMD) && (pci_config._device == PCI_DEVICE_ID_AMD_SCSI)) {
- pci_config._status_command = inl(pci_config._ioaddr + PCI_COMMAND);
- pci_config._class_revision = inl(pci_config._ioaddr + PCI_CLASS_REVISION);
- pci_config._bist_header_latency_cache = inl(pci_config._ioaddr + PCI_CACHE_LINE_SIZE);
- pci_config._base0 = inl(pci_config._ioaddr + PCI_BASE_ADDRESS_0);
- pci_config._base1 = inl(pci_config._ioaddr + PCI_BASE_ADDRESS_1);
- pci_config._base2 = inl(pci_config._ioaddr + PCI_BASE_ADDRESS_2);
- pci_config._base3 = inl(pci_config._ioaddr + PCI_BASE_ADDRESS_3);
- pci_config._base4 = inl(pci_config._ioaddr + PCI_BASE_ADDRESS_4);
- pci_config._base5 = inl(pci_config._ioaddr + PCI_BASE_ADDRESS_5);
- pci_config._baserom = inl(pci_config._ioaddr + PCI_ROM_ADDRESS);
- pci_config._max_min_ipin_iline = inl(pci_config._ioaddr + PCI_INTERRUPT_LINE);
-
- /* check whether device is I/O mapped -- should be */
- if (!(pci_config._command & PCI_COMMAND_IO)) continue;
-
- /* PCI Spec 2.1 states that it is either the driver's or the PCI card's responsibility
- to set the PCI Master Enable Bit if needed.
- From Mark Stockton <marks@schooner.sys.hou.compaq.com> */
- if (!(pci_config._command & PCI_COMMAND_MASTER)) {
- pci_config._command |= PCI_COMMAND_MASTER;
- printk("Config 2; PCI Master Bit has not been set. Setting...\n");
- outw(pci_config._command, pci_config._ioaddr + PCI_COMMAND); }
-
- /* everything seems OK now, so initialize */
- if (AM53C974_init(tpnt, pci_config)) count++ ;
- }
- }
- AM53C974_PCIREG_CLOSE();
- }
-
-return(count);
-}
-
-/**************************************************************************
* Function : int AM53C974_detect(Scsi_Host_Template *tpnt)
*
* Purpose : detects and initializes AM53C974 SCSI chips
@@ -905,21 +625,19 @@ return(count);
**************************************************************************/
__initfunc(int AM53C974_detect(Scsi_Host_Template *tpnt))
{
-int count; /* number of boards detected */
+int count = 0; /* number of boards detected */
tpnt->proc_dir = &proc_scsi_am53c974;
#if defined (CONFIG_PCI)
-if (pcibios_present())
- count = AM53C974_bios_detect(tpnt);
- else
+if (pci_present())
+ count = AM53C974_pci_detect(tpnt);
#endif
-count = AM53C974_nobios_detect(tpnt);
return (count);
}
/**************************************************************************
-* Function : int AM53C974_init(Scsi_Host_Template *tpnt, pci_config_t pci_config)
+* Function : int AM53C974_init(Scsi_Host_Template *tpnt, struct pci_dev *pdev)
*
* Purpose : initializes instance and corresponding AM53/79C974 chip,
*
@@ -932,7 +650,7 @@ return (count);
* set up by the BIOS (as reflected by contents of register CNTLREG1).
* This is the only BIOS assistance we need.
**************************************************************************/
-__initfunc(static int AM53C974_init(Scsi_Host_Template *tpnt, pci_config_t pci_config))
+__initfunc(static int AM53C974_init(Scsi_Host_Template *tpnt, struct pci_dev *pdev))
{
AM53C974_local_declare();
int i, j;
@@ -947,9 +665,8 @@ struct AM53C974_hostdata *hostdata;
instance = scsi_register(tpnt, sizeof(struct AM53C974_hostdata));
hostdata = (struct AM53C974_hostdata *)instance->hostdata;
instance->base = NULL;
-instance->io_port = pci_config._base0 & (pci_config._base0 & 0x1 ?
- 0xFFFFFFFC : 0xFFFFFFF0);
-instance->irq = pci_config._int_line;
+instance->io_port = pdev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK;
+instance->irq = pdev->irq;
instance->dma_channel = -1;
AM53C974_setio(instance);
@@ -1001,7 +718,7 @@ for (search = first_host;
(search->irq != instance->irq) || (search == instance) );
search = search->next);
if (!search) {
- if (request_irq(instance->irq, AM53C974_intr, SA_INTERRUPT, "AM53C974", NULL)) {
+ if (request_irq(instance->irq, do_AM53C974_intr, SA_INTERRUPT, "AM53C974", NULL)) {
printk("scsi%d: IRQ%d not free, detaching\n", instance->host_no, instance->irq);
scsi_unregister(instance);
return 0; }
@@ -1270,6 +987,24 @@ main_running = 0;
* *
* Returns : nothing *
************************************************************************/
+static void do_AM53C974_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+unsigned long flags;
+
+spin_lock_irqsave(&io_request_lock, flags);
+AM53C974_intr(irq, dev_id, regs);
+spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
+/************************************************************************
+* Function : AM53C974_intr(int irq, void *dev_id, struct pt_regs *regs) *
+* *
+* Purpose : interrupt handler *
+* *
+* Inputs : irq - interrupt line, regs - ? *
+* *
+* Returns : nothing *
+************************************************************************/
static void AM53C974_intr(int irq, void *dev_id, struct pt_regs *regs)
{
AM53C974_local_declare();
diff --git a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c
index b81756cc8..28f18d7dd 100644
--- a/drivers/scsi/BusLogic.c
+++ b/drivers/scsi/BusLogic.c
@@ -2,7 +2,7 @@
Linux Driver for BusLogic MultiMaster and FlashPoint SCSI Host Adapters
- Copyright 1995 by Leonard N. Zubkoff <lnz@dandelion.com>
+ Copyright 1995-1998 by Leonard N. Zubkoff <lnz@dandelion.com>
This program is free software; you may redistribute and/or modify it under
the terms of the GNU General Public License Version 2 as published by the
@@ -26,14 +26,15 @@
*/
-#define BusLogic_DriverVersion "2.0.11"
-#define BusLogic_DriverDate "31 January 1998"
+#define BusLogic_DriverVersion "2.1.13"
+#define BusLogic_DriverDate "17 April 1998"
#include <linux/version.h>
#include <linux/module.h>
#include <linux/config.h>
#include <linux/types.h>
+#include <linux/blk.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/ioport.h>
@@ -41,10 +42,9 @@
#include <linux/sched.h>
#include <linux/stat.h>
#include <linux/pci.h>
-#include <linux/bios32.h>
#include <asm/dma.h>
#include <asm/io.h>
-#include <asm/irq.h>
+#include <asm/spinlock.h>
#include <asm/system.h>
#include "scsi.h"
#include "hosts.h"
@@ -112,15 +112,6 @@ static BusLogic_HostAdapter_T
/*
- BusLogic_RegisteredHostAdapters is an array of linked lists of all the
- registered BusLogic Host Adapters, indexed by IRQ Channel.
-*/
-
-static BusLogic_HostAdapter_T
- *BusLogic_RegisteredHostAdapters[NR_IRQS] = { NULL };
-
-
-/*
BusLogic_ProbeInfoCount is the number of entries in BusLogic_ProbeInfoList.
*/
@@ -150,16 +141,6 @@ static char
/*
- BusLogic_FirstCompletedCCB and BusLogic_LastCompletedCCB are pointers
- to the first and last CCBs that are queued for completion processing.
-*/
-
-static BusLogic_CCB_T
- *BusLogic_FirstCompletedCCB = NULL,
- *BusLogic_LastCompletedCCB = NULL;
-
-
-/*
BusLogic_ProcDirectoryEntry is the BusLogic /proc/scsi directory entry.
*/
@@ -178,7 +159,7 @@ static void BusLogic_AnnounceDriver(BusLogic_HostAdapter_T *HostAdapter)
BusLogic_Announce("***** BusLogic SCSI Driver Version "
BusLogic_DriverVersion " of "
BusLogic_DriverDate " *****\n", HostAdapter);
- BusLogic_Announce("Copyright 1995 by Leonard N. Zubkoff "
+ BusLogic_Announce("Copyright 1995-1998 by Leonard N. Zubkoff "
"<lnz@dandelion.com>\n", HostAdapter);
}
@@ -203,7 +184,7 @@ const char *BusLogic_DriverInfo(SCSI_Host_T *Host)
static void BusLogic_RegisterHostAdapter(BusLogic_HostAdapter_T *HostAdapter)
{
- HostAdapter->NextAll = NULL;
+ HostAdapter->Next = NULL;
if (BusLogic_FirstRegisteredHostAdapter == NULL)
{
BusLogic_FirstRegisteredHostAdapter = HostAdapter;
@@ -211,20 +192,9 @@ static void BusLogic_RegisterHostAdapter(BusLogic_HostAdapter_T *HostAdapter)
}
else
{
- BusLogic_LastRegisteredHostAdapter->NextAll = HostAdapter;
+ BusLogic_LastRegisteredHostAdapter->Next = HostAdapter;
BusLogic_LastRegisteredHostAdapter = HostAdapter;
}
- HostAdapter->Next = NULL;
- if (BusLogic_RegisteredHostAdapters[HostAdapter->IRQ_Channel] != NULL)
- {
- BusLogic_HostAdapter_T *LastHostAdapter =
- BusLogic_RegisteredHostAdapters[HostAdapter->IRQ_Channel];
- BusLogic_HostAdapter_T *NextHostAdapter;
- while ((NextHostAdapter = LastHostAdapter->Next) != NULL)
- LastHostAdapter = NextHostAdapter;
- LastHostAdapter->Next = HostAdapter;
- }
- else BusLogic_RegisteredHostAdapters[HostAdapter->IRQ_Channel] = HostAdapter;
}
@@ -238,7 +208,7 @@ static void BusLogic_UnregisterHostAdapter(BusLogic_HostAdapter_T *HostAdapter)
if (HostAdapter == BusLogic_FirstRegisteredHostAdapter)
{
BusLogic_FirstRegisteredHostAdapter =
- BusLogic_FirstRegisteredHostAdapter->NextAll;
+ BusLogic_FirstRegisteredHostAdapter->Next;
if (HostAdapter == BusLogic_LastRegisteredHostAdapter)
BusLogic_LastRegisteredHostAdapter = NULL;
}
@@ -247,24 +217,11 @@ static void BusLogic_UnregisterHostAdapter(BusLogic_HostAdapter_T *HostAdapter)
BusLogic_HostAdapter_T *PreviousHostAdapter =
BusLogic_FirstRegisteredHostAdapter;
while (PreviousHostAdapter != NULL &&
- PreviousHostAdapter->NextAll != HostAdapter)
- PreviousHostAdapter = PreviousHostAdapter->NextAll;
- if (PreviousHostAdapter != NULL)
- PreviousHostAdapter->NextAll = HostAdapter->NextAll;
- }
- HostAdapter->NextAll = NULL;
- if (BusLogic_RegisteredHostAdapters[HostAdapter->IRQ_Channel] != HostAdapter)
- {
- BusLogic_HostAdapter_T *PreviousHostAdapter =
- BusLogic_RegisteredHostAdapters[HostAdapter->IRQ_Channel];
- while (PreviousHostAdapter != NULL &&
PreviousHostAdapter->Next != HostAdapter)
PreviousHostAdapter = PreviousHostAdapter->Next;
if (PreviousHostAdapter != NULL)
PreviousHostAdapter->Next = HostAdapter->Next;
}
- else BusLogic_RegisteredHostAdapters[HostAdapter->IRQ_Channel] =
- HostAdapter->Next;
HostAdapter->Next = NULL;
}
@@ -466,7 +423,7 @@ static int BusLogic_Command(BusLogic_HostAdapter_T *HostAdapter,
unsigned char *ReplyPointer = (unsigned char *) ReplyData;
BusLogic_StatusRegister_T StatusRegister;
BusLogic_InterruptRegister_T InterruptRegister;
- unsigned long ProcessorFlags = 0;
+ ProcessorFlags_T ProcessorFlags = 0;
int ReplyBytes = 0, Result;
long TimeoutCounter;
/*
@@ -794,12 +751,7 @@ static int BusLogic_InitializeMultiMasterProbeInfo(BusLogic_HostAdapter_T
boolean ForceBusDeviceScanningOrder = false;
boolean ForceBusDeviceScanningOrderChecked = false;
boolean StandardAddressSeen[6];
- unsigned char Bus, DeviceFunction;
- unsigned int BaseAddress0, BaseAddress1;
- unsigned char IRQ_Channel;
- BusLogic_IO_Address_T IO_Address;
- BusLogic_PCI_Address_T PCI_Address;
- unsigned short Index = 0;
+ PCI_Device_T *PCI_Device = NULL;
int i;
if (BusLogic_ProbeInfoCount >= BusLogic_MaxHostAdapters) return 0;
BusLogic_ProbeInfoCount++;
@@ -818,147 +770,148 @@ static int BusLogic_InitializeMultiMasterProbeInfo(BusLogic_HostAdapter_T
particular standard ISA I/O Address need not be probed.
*/
PrimaryProbeInfo->IO_Address = 0;
- while (pcibios_find_device(PCI_VENDOR_ID_BUSLOGIC,
- PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER,
- Index++, &Bus, &DeviceFunction) == 0)
- if (pcibios_read_config_dword(Bus, DeviceFunction,
- PCI_BASE_ADDRESS_0, &BaseAddress0) == 0 &&
- pcibios_read_config_dword(Bus, DeviceFunction,
- PCI_BASE_ADDRESS_1, &BaseAddress1) == 0 &&
- pcibios_read_config_byte(Bus, DeviceFunction,
- PCI_INTERRUPT_LINE, &IRQ_Channel) == 0)
- {
- BusLogic_HostAdapter_T *HostAdapter = PrototypeHostAdapter;
- BusLogic_PCIHostAdapterInformation_T PCIHostAdapterInformation;
- BusLogic_ModifyIOAddressRequest_T ModifyIOAddressRequest;
- unsigned char Device = DeviceFunction >> 3;
- IO_Address = BaseAddress0 & PCI_BASE_ADDRESS_IO_MASK;
- PCI_Address = BaseAddress1 & PCI_BASE_ADDRESS_MEM_MASK;
- if ((BaseAddress0 & PCI_BASE_ADDRESS_SPACE)
- != PCI_BASE_ADDRESS_SPACE_IO)
- {
- BusLogic_Error("BusLogic: Base Address0 0x%X not I/O for "
- "MultiMaster Host Adapter\n", NULL, BaseAddress0);
- BusLogic_Error("at PCI Bus %d Device %d I/O Address 0x%X\n",
- NULL, Bus, Device, IO_Address);
- continue;
- }
- if ((BaseAddress1 & PCI_BASE_ADDRESS_SPACE)
- != PCI_BASE_ADDRESS_SPACE_MEMORY)
- {
- BusLogic_Error("BusLogic: Base Address1 0x%X not Memory for "
- "MultiMaster Host Adapter\n", NULL, BaseAddress1);
- BusLogic_Error("at PCI Bus %d Device %d PCI Address 0x%X\n",
- NULL, Bus, Device, PCI_Address);
- continue;
- }
- if (IRQ_Channel == 0 || IRQ_Channel >= NR_IRQS)
- {
- BusLogic_Error("BusLogic: IRQ Channel %d illegal for "
- "MultiMaster Host Adapter\n", NULL, IRQ_Channel);
- BusLogic_Error("at PCI Bus %d Device %d I/O Address 0x%X\n",
- NULL, Bus, Device, IO_Address);
- continue;
- }
- if (BusLogic_GlobalOptions.TraceProbe)
- {
- BusLogic_Notice("BusLogic: PCI MultiMaster Host Adapter "
- "detected at\n", NULL);
- BusLogic_Notice("BusLogic: PCI Bus %d Device %d I/O Address "
- "0x%X PCI Address 0x%X\n", NULL,
- Bus, Device, IO_Address, PCI_Address);
- }
- /*
- Issue the Inquire PCI Host Adapter Information command to determine
- the ISA Compatible I/O Port. If the ISA Compatible I/O Port is
- known and enabled, note that the particular Standard ISA I/O
- Address should not be probed.
- */
- HostAdapter->IO_Address = IO_Address;
- if (BusLogic_Command(HostAdapter,
- BusLogic_InquirePCIHostAdapterInformation,
- NULL, 0, &PCIHostAdapterInformation,
- sizeof(PCIHostAdapterInformation))
- == sizeof(PCIHostAdapterInformation))
- {
- if (PCIHostAdapterInformation.ISACompatibleIOPort < 6)
- StandardAddressSeen[PCIHostAdapterInformation
- .ISACompatibleIOPort] = true;
- }
- else PCIHostAdapterInformation.ISACompatibleIOPort =
- BusLogic_IO_Disable;
- /*
- Issue the Modify I/O Address command to disable the ISA Compatible
- I/O Port.
- */
- ModifyIOAddressRequest = BusLogic_IO_Disable;
- BusLogic_Command(HostAdapter, BusLogic_ModifyIOAddress,
- &ModifyIOAddressRequest,
- sizeof(ModifyIOAddressRequest), NULL, 0);
- /*
- For the first MultiMaster Host Adapter enumerated, issue the Fetch
- Host Adapter Local RAM command to read byte 45 of the AutoSCSI area,
- for the setting of the "Use Bus And Device # For PCI Scanning Seq."
- option. Issue the Inquire Board ID command since this option is
- only valid for the BT-948/958/958D.
- */
- if (!ForceBusDeviceScanningOrderChecked)
- {
- BusLogic_FetchHostAdapterLocalRAMRequest_T
- FetchHostAdapterLocalRAMRequest;
- BusLogic_AutoSCSIByte45_T AutoSCSIByte45;
- BusLogic_BoardID_T BoardID;
- FetchHostAdapterLocalRAMRequest.ByteOffset =
- BusLogic_AutoSCSI_BaseOffset + 45;
- FetchHostAdapterLocalRAMRequest.ByteCount =
- sizeof(AutoSCSIByte45);
- BusLogic_Command(HostAdapter,
- BusLogic_FetchHostAdapterLocalRAM,
- &FetchHostAdapterLocalRAMRequest,
- sizeof(FetchHostAdapterLocalRAMRequest),
- &AutoSCSIByte45, sizeof(AutoSCSIByte45));
- BusLogic_Command(HostAdapter, BusLogic_InquireBoardID,
- NULL, 0, &BoardID, sizeof(BoardID));
- if (BoardID.FirmwareVersion1stDigit == '5')
- ForceBusDeviceScanningOrder =
- AutoSCSIByte45.ForceBusDeviceScanningOrder;
- ForceBusDeviceScanningOrderChecked = true;
- }
- /*
- Determine whether this MultiMaster Host Adapter has its ISA
- Compatible I/O Port enabled and is assigned the Primary I/O Address.
- If it does, then it is the Primary MultiMaster Host Adapter and must
- be recognized first. If it does not, then it is added to the list
- for probing after any Primary MultiMaster Host Adapter is probed.
- */
- if (PCIHostAdapterInformation.ISACompatibleIOPort == BusLogic_IO_330)
- {
- PrimaryProbeInfo->HostAdapterType = BusLogic_MultiMaster;
- PrimaryProbeInfo->HostAdapterBusType = BusLogic_PCI_Bus;
- PrimaryProbeInfo->IO_Address = IO_Address;
- PrimaryProbeInfo->PCI_Address = PCI_Address;
- PrimaryProbeInfo->Bus = Bus;
- PrimaryProbeInfo->Device = Device;
- PrimaryProbeInfo->IRQ_Channel = IRQ_Channel;
- PCIMultiMasterCount++;
- }
- else if (BusLogic_ProbeInfoCount < BusLogic_MaxHostAdapters)
- {
- BusLogic_ProbeInfo_T *ProbeInfo =
- &BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount++];
- ProbeInfo->HostAdapterType = BusLogic_MultiMaster;
- ProbeInfo->HostAdapterBusType = BusLogic_PCI_Bus;
- ProbeInfo->IO_Address = IO_Address;
- ProbeInfo->PCI_Address = PCI_Address;
- ProbeInfo->Bus = Bus;
- ProbeInfo->Device = Device;
- ProbeInfo->IRQ_Channel = IRQ_Channel;
- NonPrimaryPCIMultiMasterCount++;
- PCIMultiMasterCount++;
- }
- else BusLogic_Warning("BusLogic: Too many Host Adapters "
- "detected\n", NULL);
- }
+ while ((PCI_Device = pci_find_device(PCI_VENDOR_ID_BUSLOGIC,
+ PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER,
+ PCI_Device)) != NULL)
+ {
+ BusLogic_HostAdapter_T *HostAdapter = PrototypeHostAdapter;
+ BusLogic_PCIHostAdapterInformation_T PCIHostAdapterInformation;
+ BusLogic_ModifyIOAddressRequest_T ModifyIOAddressRequest;
+ unsigned char Bus = PCI_Device->bus->number;
+ unsigned char Device = PCI_Device->devfn >> 3;
+ unsigned int IRQ_Channel = PCI_Device->irq;
+ unsigned long BaseAddress0 = PCI_Device->base_address[0];
+ unsigned long BaseAddress1 = PCI_Device->base_address[1];
+ BusLogic_IO_Address_T IO_Address =
+ BaseAddress0 & PCI_BASE_ADDRESS_IO_MASK;
+ BusLogic_PCI_Address_T PCI_Address =
+ BaseAddress1 & PCI_BASE_ADDRESS_MEM_MASK;
+ if ((BaseAddress0 & PCI_BASE_ADDRESS_SPACE)
+ != PCI_BASE_ADDRESS_SPACE_IO)
+ {
+ BusLogic_Error("BusLogic: Base Address0 0x%X not I/O for "
+ "MultiMaster Host Adapter\n", NULL, BaseAddress0);
+ BusLogic_Error("at PCI Bus %d Device %d I/O Address 0x%X\n",
+ NULL, Bus, Device, IO_Address);
+ continue;
+ }
+ if ((BaseAddress1 & PCI_BASE_ADDRESS_SPACE)
+ != PCI_BASE_ADDRESS_SPACE_MEMORY)
+ {
+ BusLogic_Error("BusLogic: Base Address1 0x%X not Memory for "
+ "MultiMaster Host Adapter\n", NULL, BaseAddress1);
+ BusLogic_Error("at PCI Bus %d Device %d PCI Address 0x%X\n",
+ NULL, Bus, Device, PCI_Address);
+ continue;
+ }
+ if (IRQ_Channel == 0)
+ {
+ BusLogic_Error("BusLogic: IRQ Channel %d illegal for "
+ "MultiMaster Host Adapter\n", NULL, IRQ_Channel);
+ BusLogic_Error("at PCI Bus %d Device %d I/O Address 0x%X\n",
+ NULL, Bus, Device, IO_Address);
+ continue;
+ }
+ if (BusLogic_GlobalOptions.TraceProbe)
+ {
+ BusLogic_Notice("BusLogic: PCI MultiMaster Host Adapter "
+ "detected at\n", NULL);
+ BusLogic_Notice("BusLogic: PCI Bus %d Device %d I/O Address "
+ "0x%X PCI Address 0x%X\n", NULL,
+ Bus, Device, IO_Address, PCI_Address);
+ }
+ /*
+ Issue the Inquire PCI Host Adapter Information command to determine
+ the ISA Compatible I/O Port. If the ISA Compatible I/O Port is
+ known and enabled, note that the particular Standard ISA I/O
+ Address should not be probed.
+ */
+ HostAdapter->IO_Address = IO_Address;
+ BusLogic_InterruptReset(HostAdapter);
+ if (BusLogic_Command(HostAdapter,
+ BusLogic_InquirePCIHostAdapterInformation,
+ NULL, 0, &PCIHostAdapterInformation,
+ sizeof(PCIHostAdapterInformation))
+ == sizeof(PCIHostAdapterInformation))
+ {
+ if (PCIHostAdapterInformation.ISACompatibleIOPort < 6)
+ StandardAddressSeen[PCIHostAdapterInformation
+ .ISACompatibleIOPort] = true;
+ }
+ else PCIHostAdapterInformation.ISACompatibleIOPort =
+ BusLogic_IO_Disable;
+ /*
+ Issue the Modify I/O Address command to disable the ISA Compatible
+ I/O Port.
+ */
+ ModifyIOAddressRequest = BusLogic_IO_Disable;
+ BusLogic_Command(HostAdapter, BusLogic_ModifyIOAddress,
+ &ModifyIOAddressRequest,
+ sizeof(ModifyIOAddressRequest), NULL, 0);
+ /*
+ For the first MultiMaster Host Adapter enumerated, issue the Fetch
+ Host Adapter Local RAM command to read byte 45 of the AutoSCSI area,
+ for the setting of the "Use Bus And Device # For PCI Scanning Seq."
+ option. Issue the Inquire Board ID command since this option is
+ only valid for the BT-948/958/958D.
+ */
+ if (!ForceBusDeviceScanningOrderChecked)
+ {
+ BusLogic_FetchHostAdapterLocalRAMRequest_T
+ FetchHostAdapterLocalRAMRequest;
+ BusLogic_AutoSCSIByte45_T AutoSCSIByte45;
+ BusLogic_BoardID_T BoardID;
+ FetchHostAdapterLocalRAMRequest.ByteOffset =
+ BusLogic_AutoSCSI_BaseOffset + 45;
+ FetchHostAdapterLocalRAMRequest.ByteCount =
+ sizeof(AutoSCSIByte45);
+ BusLogic_Command(HostAdapter,
+ BusLogic_FetchHostAdapterLocalRAM,
+ &FetchHostAdapterLocalRAMRequest,
+ sizeof(FetchHostAdapterLocalRAMRequest),
+ &AutoSCSIByte45, sizeof(AutoSCSIByte45));
+ BusLogic_Command(HostAdapter, BusLogic_InquireBoardID,
+ NULL, 0, &BoardID, sizeof(BoardID));
+ if (BoardID.FirmwareVersion1stDigit == '5')
+ ForceBusDeviceScanningOrder =
+ AutoSCSIByte45.ForceBusDeviceScanningOrder;
+ ForceBusDeviceScanningOrderChecked = true;
+ }
+ /*
+ Determine whether this MultiMaster Host Adapter has its ISA
+ Compatible I/O Port enabled and is assigned the Primary I/O Address.
+ If it does, then it is the Primary MultiMaster Host Adapter and must
+ be recognized first. If it does not, then it is added to the list
+ for probing after any Primary MultiMaster Host Adapter is probed.
+ */
+ if (PCIHostAdapterInformation.ISACompatibleIOPort == BusLogic_IO_330)
+ {
+ PrimaryProbeInfo->HostAdapterType = BusLogic_MultiMaster;
+ PrimaryProbeInfo->HostAdapterBusType = BusLogic_PCI_Bus;
+ PrimaryProbeInfo->IO_Address = IO_Address;
+ PrimaryProbeInfo->PCI_Address = PCI_Address;
+ PrimaryProbeInfo->Bus = Bus;
+ PrimaryProbeInfo->Device = Device;
+ PrimaryProbeInfo->IRQ_Channel = IRQ_Channel;
+ PCIMultiMasterCount++;
+ }
+ else if (BusLogic_ProbeInfoCount < BusLogic_MaxHostAdapters)
+ {
+ BusLogic_ProbeInfo_T *ProbeInfo =
+ &BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount++];
+ ProbeInfo->HostAdapterType = BusLogic_MultiMaster;
+ ProbeInfo->HostAdapterBusType = BusLogic_PCI_Bus;
+ ProbeInfo->IO_Address = IO_Address;
+ ProbeInfo->PCI_Address = PCI_Address;
+ ProbeInfo->Bus = Bus;
+ ProbeInfo->Device = Device;
+ ProbeInfo->IRQ_Channel = IRQ_Channel;
+ NonPrimaryPCIMultiMasterCount++;
+ PCIMultiMasterCount++;
+ }
+ else BusLogic_Warning("BusLogic: Too many Host Adapters "
+ "detected\n", NULL);
+ }
/*
If the AutoSCSI "Use Bus And Device # For PCI Scanning Seq." option is ON
for the first enumerated MultiMaster Host Adapter, and if that host adapter
@@ -1020,6 +973,36 @@ static int BusLogic_InitializeMultiMasterProbeInfo(BusLogic_HostAdapter_T
: check_region(0x134, BusLogic_MultiMasterAddressCount) == 0))
BusLogic_AppendProbeAddressISA(0x134);
}
+ /*
+ Iterate over the older non-compliant MultiMaster PCI Host Adapters,
+ noting the PCI bus location and assigned IRQ Channel.
+ */
+ PCI_Device = NULL;
+ while ((PCI_Device = pci_find_device(PCI_VENDOR_ID_BUSLOGIC,
+ PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER_NC,
+ PCI_Device)) != NULL)
+ {
+ unsigned char Bus = PCI_Device->bus->number;
+ unsigned char Device = PCI_Device->devfn >> 3;
+ unsigned int IRQ_Channel = PCI_Device->irq;
+ BusLogic_IO_Address_T IO_Address =
+ PCI_Device->base_address[0] & PCI_BASE_ADDRESS_IO_MASK;
+ if (IO_Address == 0 || IRQ_Channel == 0) continue;
+ for (i = 0; i < BusLogic_ProbeInfoCount; i++)
+ {
+ BusLogic_ProbeInfo_T *ProbeInfo = &BusLogic_ProbeInfoList[i];
+ if (ProbeInfo->IO_Address == IO_Address &&
+ ProbeInfo->HostAdapterType == BusLogic_MultiMaster)
+ {
+ ProbeInfo->HostAdapterBusType = BusLogic_PCI_Bus;
+ ProbeInfo->PCI_Address = 0;
+ ProbeInfo->Bus = Bus;
+ ProbeInfo->Device = Device;
+ ProbeInfo->IRQ_Channel = IRQ_Channel;
+ break;
+ }
+ }
+ }
return PCIMultiMasterCount;
}
@@ -1035,87 +1018,82 @@ static int BusLogic_InitializeFlashPointProbeInfo(BusLogic_HostAdapter_T
*PrototypeHostAdapter)
{
int FlashPointIndex = BusLogic_ProbeInfoCount, FlashPointCount = 0;
- unsigned char Bus, DeviceFunction;
- unsigned int BaseAddress0, BaseAddress1;
- unsigned char IRQ_Channel;
- BusLogic_IO_Address_T IO_Address;
- BusLogic_PCI_Address_T PCI_Address;
- unsigned short Index = 0;
+ PCI_Device_T *PCI_Device = NULL;
/*
Interrogate PCI Configuration Space for any FlashPoint Host Adapters.
*/
- while (pcibios_find_device(PCI_VENDOR_ID_BUSLOGIC,
- PCI_DEVICE_ID_BUSLOGIC_FLASHPOINT,
- Index++, &Bus, &DeviceFunction) == 0)
- if (pcibios_read_config_dword(Bus, DeviceFunction,
- PCI_BASE_ADDRESS_0, &BaseAddress0) == 0 &&
- pcibios_read_config_dword(Bus, DeviceFunction,
- PCI_BASE_ADDRESS_1, &BaseAddress1) == 0 &&
- pcibios_read_config_byte(Bus, DeviceFunction,
- PCI_INTERRUPT_LINE, &IRQ_Channel) == 0)
- {
- unsigned char Device = DeviceFunction >> 3;
- IO_Address = BaseAddress0 & PCI_BASE_ADDRESS_IO_MASK;
- PCI_Address = BaseAddress1 & PCI_BASE_ADDRESS_MEM_MASK;
+ while ((PCI_Device = pci_find_device(PCI_VENDOR_ID_BUSLOGIC,
+ PCI_DEVICE_ID_BUSLOGIC_FLASHPOINT,
+ PCI_Device)) != NULL)
+ {
+ unsigned char Bus = PCI_Device->bus->number;
+ unsigned char Device = PCI_Device->devfn >> 3;
+ unsigned int IRQ_Channel = PCI_Device->irq;
+ unsigned long BaseAddress0 = PCI_Device->base_address[0];
+ unsigned long BaseAddress1 = PCI_Device->base_address[1];
+ BusLogic_IO_Address_T IO_Address =
+ BaseAddress0 & PCI_BASE_ADDRESS_IO_MASK;
+ BusLogic_PCI_Address_T PCI_Address =
+ BaseAddress1 & PCI_BASE_ADDRESS_MEM_MASK;
#ifndef CONFIG_SCSI_OMIT_FLASHPOINT
- if ((BaseAddress0 & PCI_BASE_ADDRESS_SPACE)
- != PCI_BASE_ADDRESS_SPACE_IO)
- {
- BusLogic_Error("BusLogic: Base Address0 0x%X not I/O for "
- "FlashPoint Host Adapter\n", NULL, BaseAddress0);
- BusLogic_Error("at PCI Bus %d Device %d I/O Address 0x%X\n",
- NULL, Bus, Device, IO_Address);
- continue;
- }
- if ((BaseAddress1 & PCI_BASE_ADDRESS_SPACE)
- != PCI_BASE_ADDRESS_SPACE_MEMORY)
- {
- BusLogic_Error("BusLogic: Base Address1 0x%X not Memory for "
- "FlashPoint Host Adapter\n", NULL, BaseAddress1);
- BusLogic_Error("at PCI Bus %d Device %d PCI Address 0x%X\n",
- NULL, Bus, Device, PCI_Address);
- continue;
- }
- if (IRQ_Channel == 0 || IRQ_Channel >= NR_IRQS)
- {
- BusLogic_Error("BusLogic: IRQ Channel %d illegal for "
- "FlashPoint Host Adapter\n", NULL, IRQ_Channel);
- BusLogic_Error("at PCI Bus %d Device %d I/O Address 0x%X\n",
- NULL, Bus, Device, IO_Address);
- continue;
- }
- if (BusLogic_GlobalOptions.TraceProbe)
- {
- BusLogic_Notice("BusLogic: FlashPoint Host Adapter "
- "detected at\n", NULL);
- BusLogic_Notice("BusLogic: PCI Bus %d Device %d I/O Address "
- "0x%X PCI Address 0x%X\n", NULL,
- Bus, Device, IO_Address, PCI_Address);
- }
- if (BusLogic_ProbeInfoCount < BusLogic_MaxHostAdapters)
- {
- BusLogic_ProbeInfo_T *ProbeInfo =
- &BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount++];
- ProbeInfo->HostAdapterType = BusLogic_FlashPoint;
- ProbeInfo->HostAdapterBusType = BusLogic_PCI_Bus;
- ProbeInfo->IO_Address = IO_Address;
- ProbeInfo->PCI_Address = PCI_Address;
- ProbeInfo->Bus = Bus;
- ProbeInfo->Device = Device;
- ProbeInfo->IRQ_Channel = IRQ_Channel;
- FlashPointCount++;
- }
- else BusLogic_Warning("BusLogic: Too many Host Adapters "
- "detected\n", NULL);
+ if ((BaseAddress0 & PCI_BASE_ADDRESS_SPACE)
+ != PCI_BASE_ADDRESS_SPACE_IO)
+ {
+ BusLogic_Error("BusLogic: Base Address0 0x%X not I/O for "
+ "FlashPoint Host Adapter\n", NULL, BaseAddress0);
+ BusLogic_Error("at PCI Bus %d Device %d I/O Address 0x%X\n",
+ NULL, Bus, Device, IO_Address);
+ continue;
+ }
+ if ((BaseAddress1 & PCI_BASE_ADDRESS_SPACE)
+ != PCI_BASE_ADDRESS_SPACE_MEMORY)
+ {
+ BusLogic_Error("BusLogic: Base Address1 0x%X not Memory for "
+ "FlashPoint Host Adapter\n", NULL, BaseAddress1);
+ BusLogic_Error("at PCI Bus %d Device %d PCI Address 0x%X\n",
+ NULL, Bus, Device, PCI_Address);
+ continue;
+ }
+ if (IRQ_Channel == 0)
+ {
+ BusLogic_Error("BusLogic: IRQ Channel %d illegal for "
+ "FlashPoint Host Adapter\n", NULL, IRQ_Channel);
+ BusLogic_Error("at PCI Bus %d Device %d I/O Address 0x%X\n",
+ NULL, Bus, Device, IO_Address);
+ continue;
+ }
+ if (BusLogic_GlobalOptions.TraceProbe)
+ {
+ BusLogic_Notice("BusLogic: FlashPoint Host Adapter "
+ "detected at\n", NULL);
+ BusLogic_Notice("BusLogic: PCI Bus %d Device %d I/O Address "
+ "0x%X PCI Address 0x%X\n", NULL,
+ Bus, Device, IO_Address, PCI_Address);
+ }
+ if (BusLogic_ProbeInfoCount < BusLogic_MaxHostAdapters)
+ {
+ BusLogic_ProbeInfo_T *ProbeInfo =
+ &BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount++];
+ ProbeInfo->HostAdapterType = BusLogic_FlashPoint;
+ ProbeInfo->HostAdapterBusType = BusLogic_PCI_Bus;
+ ProbeInfo->IO_Address = IO_Address;
+ ProbeInfo->PCI_Address = PCI_Address;
+ ProbeInfo->Bus = Bus;
+ ProbeInfo->Device = Device;
+ ProbeInfo->IRQ_Channel = IRQ_Channel;
+ FlashPointCount++;
+ }
+ else BusLogic_Warning("BusLogic: Too many Host Adapters "
+ "detected\n", NULL);
#else
- BusLogic_Error("BusLogic: FlashPoint Host Adapter detected at "
- "PCI Bus %d Device %d\n", NULL, Bus, Device);
- BusLogic_Error("BusLogic: I/O Address 0x%X PCI Address 0x%X, "
- "but FlashPoint\n", NULL, IO_Address, PCI_Address);
- BusLogic_Error("BusLogic: support was omitted in this kernel "
- "configuration.\n", NULL);
+ BusLogic_Error("BusLogic: FlashPoint Host Adapter detected at "
+ "PCI Bus %d Device %d\n", NULL, Bus, Device);
+ BusLogic_Error("BusLogic: I/O Address 0x%X PCI Address 0x%X, "
+ "but FlashPoint\n", NULL, IO_Address, PCI_Address);
+ BusLogic_Error("BusLogic: support was omitted in this kernel "
+ "configuration.\n", NULL);
#endif
- }
+ }
/*
The FlashPoint BIOS will scan for FlashPoint Host Adapters in the order of
increasing PCI Bus and Device Number, so sort the probe information into
@@ -1147,7 +1125,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)
{
@@ -1227,10 +1205,13 @@ static boolean BusLogic_Failure(BusLogic_HostAdapter_T *HostAdapter,
{
BusLogic_AnnounceDriver(HostAdapter);
if (HostAdapter->HostAdapterBusType == BusLogic_PCI_Bus)
- BusLogic_Error("While configuring BusLogic PCI Host Adapter at\n"
- "Bus %d Device %d I/O Address 0x%X PCI Address 0x%X:\n",
- HostAdapter, HostAdapter->Bus, HostAdapter->Device,
- HostAdapter->IO_Address, HostAdapter->PCI_Address);
+ {
+ BusLogic_Error("While configuring BusLogic PCI Host Adapter at\n",
+ HostAdapter);
+ BusLogic_Error("Bus %d Device %d I/O Address 0x%X PCI Address 0x%X:\n",
+ HostAdapter, HostAdapter->Bus, HostAdapter->Device,
+ HostAdapter->IO_Address, HostAdapter->PCI_Address);
+ }
else BusLogic_Error("While configuring BusLogic Host Adapter at "
"I/O Address 0x%X:\n", HostAdapter,
HostAdapter->IO_Address);
@@ -1447,12 +1428,11 @@ static boolean BusLogic_HardwareResetHostAdapter(BusLogic_HostAdapter_T
/*
BusLogic_CheckHostAdapter checks to be sure this really is a BusLogic
- Host Adapter. It also determines the IRQ Channel for non-PCI Host Adapters.
+ Host Adapter.
*/
static boolean BusLogic_CheckHostAdapter(BusLogic_HostAdapter_T *HostAdapter)
{
- BusLogic_Configuration_T Configuration;
BusLogic_ExtendedSetupInformation_T ExtendedSetupInformation;
BusLogic_RequestedReplyLength_T RequestedReplyLength;
boolean Result = true;
@@ -1461,31 +1441,6 @@ static boolean BusLogic_CheckHostAdapter(BusLogic_HostAdapter_T *HostAdapter)
*/
if (BusLogic_FlashPointHostAdapterP(HostAdapter)) return true;
/*
- Issue the Inquire Configuration command if the IRQ Channel is unknown.
- */
- if (HostAdapter->IRQ_Channel == 0)
- {
- if (BusLogic_Command(HostAdapter, BusLogic_InquireConfiguration,
- NULL, 0, &Configuration, sizeof(Configuration))
- == sizeof(Configuration))
- {
- if (Configuration.IRQ_Channel9)
- HostAdapter->IRQ_Channel = 9;
- else if (Configuration.IRQ_Channel10)
- HostAdapter->IRQ_Channel = 10;
- else if (Configuration.IRQ_Channel11)
- HostAdapter->IRQ_Channel = 11;
- else if (Configuration.IRQ_Channel12)
- HostAdapter->IRQ_Channel = 12;
- else if (Configuration.IRQ_Channel14)
- HostAdapter->IRQ_Channel = 14;
- else if (Configuration.IRQ_Channel15)
- HostAdapter->IRQ_Channel = 15;
- else Result = false;
- }
- else Result = false;
- }
- /*
Issue the Inquire Extended Setup Information command. Only genuine
BusLogic Host Adapters and true clones support this command. Adaptec 1542C
series Host Adapters that respond to the Geometry Register I/O port will
@@ -1711,11 +1666,27 @@ static boolean BusLogic_ReadHostAdapterConfiguration(BusLogic_HostAdapter_T
*/
HostAdapter->SCSI_ID = Configuration.HostAdapterID;
/*
- Determine the Bus Type and save it in the Host Adapter structure,
- and determine and save the DMA Channel for ISA Host Adapters.
+ Determine the Bus Type and save it in the Host Adapter structure, determine
+ and save the IRQ Channel if necessary, and determine and save the DMA
+ Channel for ISA Host Adapters.
*/
HostAdapter->HostAdapterBusType =
BusLogic_HostAdapterBusTypes[HostAdapter->ModelName[3] - '4'];
+ if (HostAdapter->IRQ_Channel == 0)
+ {
+ if (Configuration.IRQ_Channel9)
+ HostAdapter->IRQ_Channel = 9;
+ else if (Configuration.IRQ_Channel10)
+ HostAdapter->IRQ_Channel = 10;
+ else if (Configuration.IRQ_Channel11)
+ HostAdapter->IRQ_Channel = 11;
+ else if (Configuration.IRQ_Channel12)
+ HostAdapter->IRQ_Channel = 12;
+ else if (Configuration.IRQ_Channel14)
+ HostAdapter->IRQ_Channel = 14;
+ else if (Configuration.IRQ_Channel15)
+ HostAdapter->IRQ_Channel = 15;
+ }
if (HostAdapter->HostAdapterBusType == BusLogic_ISA_Bus)
{
if (Configuration.DMA_Channel5)
@@ -1858,7 +1829,7 @@ static boolean BusLogic_ReadHostAdapterConfiguration(BusLogic_HostAdapter_T
HostAdapter->MaxTargetDevices = (HostAdapter->HostWideSCSI ? 16 : 8);
HostAdapter->MaxLogicalUnits = (HostAdapter->ExtendedLUNSupport ? 32 : 8);
/*
- Select appropriate values for the Mailbox Count, Driver Queue Depth,
+ Select appropriate values for the Mailbox Count, Driver Queue Depth,
Initial CCBs, and Incremental CCBs variables based on whether or not Strict
Round Robin Mode is supported. If Strict Round Robin Mode is supported,
then there is no performance degradation in using the maximum possible
@@ -1950,12 +1921,10 @@ static boolean BusLogic_ReadHostAdapterConfiguration(BusLogic_HostAdapter_T
*/
Common:
/*
- Initialize the Host Adapter Full Model Name and Interrupt Label fields
- from the Model Name.
+ Initialize the Host Adapter Full Model Name from the Model Name.
*/
strcpy(HostAdapter->FullModelName, "BusLogic ");
strcat(HostAdapter->FullModelName, HostAdapter->ModelName);
- strcpy(HostAdapter->InterruptLabel, HostAdapter->FullModelName);
/*
Select an appropriate value for the Tagged Queue Depth either from a
BusLogic Driver Options specification, or based on whether this Host
@@ -1976,6 +1945,12 @@ Common:
if (HostAdapter->BounceBuffersRequired)
HostAdapter->UntaggedQueueDepth = BusLogic_UntaggedQueueDepthBB;
else HostAdapter->UntaggedQueueDepth = BusLogic_UntaggedQueueDepth;
+ if (HostAdapter->DriverOptions != NULL)
+ HostAdapter->CommonQueueDepth =
+ HostAdapter->DriverOptions->CommonQueueDepth;
+ if (HostAdapter->CommonQueueDepth > 0 &&
+ HostAdapter->CommonQueueDepth < HostAdapter->UntaggedQueueDepth)
+ HostAdapter->UntaggedQueueDepth = HostAdapter->CommonQueueDepth;
/*
Tagged Queuing is only allowed if Disconnect/Reconnect is permitted.
Therefore, mask the Tagged Queuing Permitted Default bits with the
@@ -2267,8 +2242,6 @@ static boolean BusLogic_ReportHostAdapterConfiguration(BusLogic_HostAdapter_T
static boolean BusLogic_AcquireResources(BusLogic_HostAdapter_T *HostAdapter)
{
- BusLogic_HostAdapter_T *FirstHostAdapter =
- BusLogic_RegisteredHostAdapters[HostAdapter->IRQ_Channel];
if (HostAdapter->IRQ_Channel == 0)
{
BusLogic_Error("NO LEGAL INTERRUPT CHANNEL ASSIGNED - DETACHING\n",
@@ -2276,24 +2249,14 @@ static boolean BusLogic_AcquireResources(BusLogic_HostAdapter_T *HostAdapter)
return false;
}
/*
- Acquire exclusive or shared access to the IRQ Channel if necessary.
+ Acquire shared access to the IRQ Channel.
*/
- if (FirstHostAdapter->Next == NULL)
- {
- if (request_irq(HostAdapter->IRQ_Channel, BusLogic_InterruptHandler,
- SA_INTERRUPT | SA_SHIRQ,
- HostAdapter->InterruptLabel, NULL) < 0)
- {
- BusLogic_Error("UNABLE TO ACQUIRE IRQ CHANNEL %d - DETACHING\n",
- HostAdapter, HostAdapter->IRQ_Channel);
- return false;
- }
- }
- else if (strlen(FirstHostAdapter->InterruptLabel) + 11
- < sizeof(FirstHostAdapter->InterruptLabel))
+ if (request_irq(HostAdapter->IRQ_Channel, BusLogic_InterruptHandler,
+ SA_SHIRQ, HostAdapter->FullModelName, HostAdapter) < 0)
{
- strcat(FirstHostAdapter->InterruptLabel, " + ");
- strcat(FirstHostAdapter->InterruptLabel, HostAdapter->ModelName);
+ BusLogic_Error("UNABLE TO ACQUIRE IRQ CHANNEL %d - DETACHING\n",
+ HostAdapter, HostAdapter->IRQ_Channel);
+ return false;
}
HostAdapter->IRQ_ChannelAcquired = true;
/*
@@ -2326,14 +2289,11 @@ static boolean BusLogic_AcquireResources(BusLogic_HostAdapter_T *HostAdapter)
static void BusLogic_ReleaseResources(BusLogic_HostAdapter_T *HostAdapter)
{
- BusLogic_HostAdapter_T *FirstHostAdapter =
- BusLogic_RegisteredHostAdapters[HostAdapter->IRQ_Channel];
/*
- Release exclusive or shared access to the IRQ Channel.
+ Release shared access to the IRQ Channel.
*/
if (HostAdapter->IRQ_ChannelAcquired)
- if (FirstHostAdapter->Next == NULL)
- free_irq(HostAdapter->IRQ_Channel, NULL);
+ free_irq(HostAdapter->IRQ_Channel, HostAdapter);
/*
Release exclusive access to the DMA Channel.
*/
@@ -2356,6 +2316,12 @@ static boolean BusLogic_InitializeHostAdapter(BusLogic_HostAdapter_T
BusLogic_SetCCBFormatRequest_T SetCCBFormatRequest;
int TargetID;
/*
+ Initialize the pointers to the first and last CCBs that are queued for
+ completion processing.
+ */
+ HostAdapter->FirstCompletedCCB = NULL;
+ HostAdapter->LastCompletedCCB = NULL;
+ /*
Initialize the Bus Device Reset Pending CCB, Tagged Queuing Active,
Command Successful Flag, Active Commands, and Commands Since Reset
for each Target Device.
@@ -2682,17 +2648,26 @@ static void BusLogic_SelectQueueDepths(SCSI_Host_T *Host,
for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
if (HostAdapter->TargetFlags[TargetID].TargetExists)
{
- int QueueDepth = HostAdapter->UntaggedQueueDepth;
+ int QueueDepth = HostAdapter->QueueDepth[TargetID];
if (HostAdapter->TargetFlags[TargetID].TaggedQueuingSupported &&
(HostAdapter->TaggedQueuingPermitted & (1 << TargetID)))
{
- QueueDepth = HostAdapter->QueueDepth[TargetID];
TaggedDeviceCount++;
if (QueueDepth == 0) AutomaticTaggedDeviceCount++;
}
- else UntaggedDeviceCount++;
- HostAdapter->QueueDepth[TargetID] = QueueDepth;
+ else
+ {
+ UntaggedDeviceCount++;
+ if (QueueDepth == 0 ||
+ QueueDepth > HostAdapter->UntaggedQueueDepth)
+ {
+ QueueDepth = HostAdapter->UntaggedQueueDepth;
+ HostAdapter->QueueDepth[TargetID] = QueueDepth;
+ }
+ }
AllocatedQueueDepth += QueueDepth;
+ if (QueueDepth == 1)
+ HostAdapter->TaggedQueuingPermitted &= ~(1 << TargetID);
}
HostAdapter->TargetDeviceCount = TaggedDeviceCount + UntaggedDeviceCount;
if (AutomaticTaggedDeviceCount > 0)
@@ -2726,7 +2701,7 @@ static void BusLogic_SelectQueueDepths(SCSI_Host_T *Host,
if (HostAdapter == BusLogic_LastRegisteredHostAdapter)
for (HostAdapter = BusLogic_FirstRegisteredHostAdapter;
HostAdapter != NULL;
- HostAdapter = HostAdapter->NextAll)
+ HostAdapter = HostAdapter->Next)
BusLogic_ReportTargetDeviceInfo(HostAdapter);
}
@@ -2828,9 +2803,7 @@ int BusLogic_DetectHostAdapter(SCSI_Host_Template_T *HostTemplate)
Host->select_queue_depths = BusLogic_SelectQueueDepths;
/*
Add Host Adapter to the end of the list of registered BusLogic
- Host Adapters. In order for Command Complete Interrupts to be
- properly dismissed by BusLogic_InterruptHandler, the Host Adapter
- must be registered.
+ Host Adapters.
*/
BusLogic_RegisterHostAdapter(HostAdapter);
/*
@@ -2923,19 +2896,20 @@ int BusLogic_ReleaseHostAdapter(SCSI_Host_T *Host)
static void BusLogic_QueueCompletedCCB(BusLogic_CCB_T *CCB)
{
+ BusLogic_HostAdapter_T *HostAdapter = CCB->HostAdapter;
CCB->Status = BusLogic_CCB_Completed;
CCB->Next = NULL;
- if (BusLogic_FirstCompletedCCB == NULL)
+ if (HostAdapter->FirstCompletedCCB == NULL)
{
- BusLogic_FirstCompletedCCB = CCB;
- BusLogic_LastCompletedCCB = CCB;
+ HostAdapter->FirstCompletedCCB = CCB;
+ HostAdapter->LastCompletedCCB = CCB;
}
else
{
- BusLogic_LastCompletedCCB->Next = CCB;
- BusLogic_LastCompletedCCB = CCB;
+ HostAdapter->LastCompletedCCB->Next = CCB;
+ HostAdapter->LastCompletedCCB = CCB;
}
- CCB->HostAdapter->ActiveCommands[CCB->TargetID]--;
+ HostAdapter->ActiveCommands[CCB->TargetID]--;
}
@@ -3058,25 +3032,23 @@ static void BusLogic_ScanIncomingMailboxes(BusLogic_HostAdapter_T *HostAdapter)
/*
- BusLogic_ProcessCompletedCCBs iterates over the completed CCBs setting
- the SCSI Command Result Codes, deallocating the CCBs, and calling the
- SCSI Subsystem Completion Routines. Interrupts should already have been
- disabled by the caller.
+ BusLogic_ProcessCompletedCCBs iterates over the completed CCBs for Host
+ Adapter setting the SCSI Command Result Codes, deallocating the CCBs, and
+ calling the SCSI Subsystem Completion Routines. The Host Adapter's Lock
+ should already have been acquired by the caller.
*/
-static void BusLogic_ProcessCompletedCCBs(void)
+static void BusLogic_ProcessCompletedCCBs(BusLogic_HostAdapter_T *HostAdapter)
{
- static boolean ProcessCompletedCCBsActive = false;
- if (ProcessCompletedCCBsActive) return;
- ProcessCompletedCCBsActive = true;
- while (BusLogic_FirstCompletedCCB != NULL)
+ if (HostAdapter->ProcessCompletedCCBsActive) return;
+ HostAdapter->ProcessCompletedCCBsActive = true;
+ while (HostAdapter->FirstCompletedCCB != NULL)
{
- BusLogic_CCB_T *CCB = BusLogic_FirstCompletedCCB;
+ BusLogic_CCB_T *CCB = HostAdapter->FirstCompletedCCB;
SCSI_Command_T *Command = CCB->Command;
- BusLogic_HostAdapter_T *HostAdapter = CCB->HostAdapter;
- BusLogic_FirstCompletedCCB = CCB->Next;
- if (BusLogic_FirstCompletedCCB == NULL)
- BusLogic_LastCompletedCCB = NULL;
+ HostAdapter->FirstCompletedCCB = CCB->Next;
+ if (HostAdapter->FirstCompletedCCB == NULL)
+ HostAdapter->LastCompletedCCB = NULL;
/*
Process the Completed CCB.
*/
@@ -3212,7 +3184,7 @@ static void BusLogic_ProcessCompletedCCBs(void)
Command->scsi_done(Command);
}
}
- ProcessCompletedCCBsActive = false;
+ HostAdapter->ProcessCompletedCCBsActive = false;
}
@@ -3225,107 +3197,84 @@ static void BusLogic_InterruptHandler(int IRQ_Channel,
void *DeviceIdentifier,
Registers_T *InterruptRegisters)
{
- BusLogic_HostAdapter_T *FirstHostAdapter =
- BusLogic_RegisteredHostAdapters[IRQ_Channel];
- boolean HostAdapterResetRequired = false;
- BusLogic_HostAdapter_T *HostAdapter;
- BusLogic_Lock_T Lock;
+ BusLogic_HostAdapter_T *HostAdapter =
+ (BusLogic_HostAdapter_T *) DeviceIdentifier;
+ ProcessorFlags_T ProcessorFlags;
/*
- Iterate over the installed BusLogic Host Adapters accepting any Incoming
- Mailbox entries and saving the completed CCBs for processing. This
- interrupt handler is installed as a fast interrupt, so interrupts are
- disabled when the interrupt handler is entered.
+ Acquire exclusive access to Host Adapter.
*/
- for (HostAdapter = FirstHostAdapter;
- HostAdapter != NULL;
- HostAdapter = HostAdapter->Next)
+ BusLogic_AcquireHostAdapterLockIH(HostAdapter, &ProcessorFlags);
+ /*
+ Handle Interrupts appropriately for each Host Adapter type.
+ */
+ if (BusLogic_MultiMasterHostAdapterP(HostAdapter))
{
+ BusLogic_InterruptRegister_T InterruptRegister;
/*
- Acquire exclusive access to Host Adapter.
- */
- BusLogic_AcquireHostAdapterLockID(HostAdapter, &Lock);
- /*
- Handle Interrupts appropriately for each Host Adapter type.
+ Read the Host Adapter Interrupt Register.
*/
- if (BusLogic_MultiMasterHostAdapterP(HostAdapter))
+ InterruptRegister.All = BusLogic_ReadInterruptRegister(HostAdapter);
+ if (InterruptRegister.Bits.InterruptValid)
{
- BusLogic_InterruptRegister_T InterruptRegister;
/*
- Read the Host Adapter Interrupt Register.
+ Acknowledge the interrupt and reset the Host Adapter
+ Interrupt Register.
*/
- InterruptRegister.All = BusLogic_ReadInterruptRegister(HostAdapter);
- if (InterruptRegister.Bits.InterruptValid)
- {
- /*
- Acknowledge the interrupt and reset the Host Adapter
- Interrupt Register.
- */
- BusLogic_InterruptReset(HostAdapter);
- /*
- Process valid External SCSI Bus Reset and Incoming Mailbox
- Loaded Interrupts. Command Complete Interrupts are noted,
- and Outgoing Mailbox Available Interrupts are ignored, as
- they are never enabled.
- */
- if (InterruptRegister.Bits.ExternalBusReset)
- {
- HostAdapter->HostAdapterExternalReset = true;
- HostAdapterResetRequired = true;
- }
- else if (InterruptRegister.Bits.IncomingMailboxLoaded)
- BusLogic_ScanIncomingMailboxes(HostAdapter);
- else if (InterruptRegister.Bits.CommandComplete)
- HostAdapter->HostAdapterCommandCompleted = true;
- }
- }
- else
- {
+ BusLogic_InterruptReset(HostAdapter);
/*
- Check if there is a pending interrupt for this Host Adapter.
+ Process valid External SCSI Bus Reset and Incoming Mailbox
+ Loaded Interrupts. Command Complete Interrupts are noted,
+ and Outgoing Mailbox Available Interrupts are ignored, as
+ they are never enabled.
*/
- if (FlashPoint_InterruptPending(HostAdapter->CardHandle))
- switch (FlashPoint_HandleInterrupt(HostAdapter->CardHandle))
- {
- case FlashPoint_NormalInterrupt:
- break;
- case FlashPoint_ExternalBusReset:
- HostAdapter->HostAdapterExternalReset = true;
- HostAdapterResetRequired = true;
- break;
- case FlashPoint_InternalError:
- BusLogic_Warning("Internal FlashPoint Error detected"
- " - Resetting Host Adapter\n", HostAdapter);
- HostAdapter->HostAdapterInternalError = true;
- HostAdapterResetRequired = true;
- break;
- }
+ if (InterruptRegister.Bits.ExternalBusReset)
+ HostAdapter->HostAdapterExternalReset = true;
+ else if (InterruptRegister.Bits.IncomingMailboxLoaded)
+ BusLogic_ScanIncomingMailboxes(HostAdapter);
+ else if (InterruptRegister.Bits.CommandComplete)
+ HostAdapter->HostAdapterCommandCompleted = true;
}
+ }
+ else
+ {
/*
- Release exclusive access to Host Adapter.
+ Check if there is a pending interrupt for this Host Adapter.
*/
- BusLogic_ReleaseHostAdapterLockID(HostAdapter, &Lock);
+ if (FlashPoint_InterruptPending(HostAdapter->CardHandle))
+ switch (FlashPoint_HandleInterrupt(HostAdapter->CardHandle))
+ {
+ case FlashPoint_NormalInterrupt:
+ break;
+ case FlashPoint_ExternalBusReset:
+ HostAdapter->HostAdapterExternalReset = true;
+ break;
+ case FlashPoint_InternalError:
+ BusLogic_Warning("Internal FlashPoint Error detected"
+ " - Resetting Host Adapter\n", HostAdapter);
+ HostAdapter->HostAdapterInternalError = true;
+ break;
+ }
}
/*
Process any completed CCBs.
*/
- if (BusLogic_FirstCompletedCCB != NULL)
- BusLogic_ProcessCompletedCCBs();
+ if (HostAdapter->FirstCompletedCCB != NULL)
+ BusLogic_ProcessCompletedCCBs(HostAdapter);
/*
- Iterate over the Host Adapters performing any requested
- Host Adapter Resets.
+ Reset the Host Adapter if requested.
*/
- if (HostAdapterResetRequired)
- for (HostAdapter = FirstHostAdapter;
- HostAdapter != NULL;
- HostAdapter = HostAdapter->Next)
- if (HostAdapter->HostAdapterExternalReset ||
- HostAdapter->HostAdapterInternalError)
- {
- BusLogic_ResetHostAdapter(HostAdapter, NULL, 0);
- HostAdapter->HostAdapterExternalReset = false;
- HostAdapter->HostAdapterInternalError = false;
- scsi_mark_host_reset(HostAdapter->SCSI_Host);
- }
+ if (HostAdapter->HostAdapterExternalReset ||
+ HostAdapter->HostAdapterInternalError)
+ {
+ BusLogic_ResetHostAdapter(HostAdapter, NULL, 0);
+ HostAdapter->HostAdapterExternalReset = false;
+ HostAdapter->HostAdapterInternalError = false;
+ scsi_mark_host_reset(HostAdapter->SCSI_Host);
+ }
+ /*
+ Release exclusive access to Host Adapter.
+ */
+ BusLogic_ReleaseHostAdapterLockIH(HostAdapter, &ProcessorFlags);
}
@@ -3389,7 +3338,7 @@ int BusLogic_QueueCommand(SCSI_Command_T *Command,
void *BufferPointer = Command->request_buffer;
int BufferLength = Command->request_bufflen;
int SegmentCount = Command->use_sg;
- BusLogic_Lock_T Lock;
+ ProcessorFlags_T ProcessorFlags;
BusLogic_CCB_T *CCB;
/*
SCSI REQUEST_SENSE commands will be executed automatically by the Host
@@ -3405,7 +3354,7 @@ int BusLogic_QueueCommand(SCSI_Command_T *Command,
/*
Acquire exclusive access to Host Adapter.
*/
- BusLogic_AcquireHostAdapterLock(HostAdapter, &Lock);
+ BusLogic_AcquireHostAdapterLock(HostAdapter, &ProcessorFlags);
/*
Allocate a CCB from the Host Adapter's free list. In the unlikely event
that there are none available and memory allocation fails, wait 1 second
@@ -3586,13 +3535,13 @@ int BusLogic_QueueCommand(SCSI_Command_T *Command,
been called, or it may still be pending.
*/
if (CCB->Status == BusLogic_CCB_Completed)
- BusLogic_ProcessCompletedCCBs();
+ BusLogic_ProcessCompletedCCBs(HostAdapter);
}
/*
Release exclusive access to Host Adapter.
*/
Done:
- BusLogic_ReleaseHostAdapterLock(HostAdapter, &Lock);
+ BusLogic_ReleaseHostAdapterLock(HostAdapter, &ProcessorFlags);
return 0;
}
@@ -3606,7 +3555,7 @@ int BusLogic_AbortCommand(SCSI_Command_T *Command)
BusLogic_HostAdapter_T *HostAdapter =
(BusLogic_HostAdapter_T *) Command->host->hostdata;
int TargetID = Command->target;
- BusLogic_Lock_T Lock;
+ ProcessorFlags_T ProcessorFlags;
BusLogic_CCB_T *CCB;
int Result;
BusLogic_IncrementErrorCounter(
@@ -3614,7 +3563,7 @@ int BusLogic_AbortCommand(SCSI_Command_T *Command)
/*
Acquire exclusive access to Host Adapter.
*/
- BusLogic_AcquireHostAdapterLock(HostAdapter, &Lock);
+ BusLogic_AcquireHostAdapterLock(HostAdapter, &ProcessorFlags);
/*
If this Command has already completed, then no Abort is necessary.
*/
@@ -3707,7 +3656,7 @@ int BusLogic_AbortCommand(SCSI_Command_T *Command)
Result = SCSI_ABORT_PENDING;
if (CCB->Status == BusLogic_CCB_Completed)
{
- BusLogic_ProcessCompletedCCBs();
+ BusLogic_ProcessCompletedCCBs(HostAdapter);
Result = SCSI_ABORT_SUCCESS;
}
}
@@ -3715,7 +3664,7 @@ int BusLogic_AbortCommand(SCSI_Command_T *Command)
Release exclusive access to Host Adapter.
*/
Done:
- BusLogic_ReleaseHostAdapterLock(HostAdapter, &Lock);
+ BusLogic_ReleaseHostAdapterLock(HostAdapter, &ProcessorFlags);
return Result;
}
@@ -3729,7 +3678,7 @@ static int BusLogic_ResetHostAdapter(BusLogic_HostAdapter_T *HostAdapter,
SCSI_Command_T *Command,
unsigned int ResetFlags)
{
- BusLogic_Lock_T Lock;
+ ProcessorFlags_T ProcessorFlags;
BusLogic_CCB_T *CCB;
int TargetID, Result;
boolean HardReset;
@@ -3753,7 +3702,7 @@ static int BusLogic_ResetHostAdapter(BusLogic_HostAdapter_T *HostAdapter,
/*
Acquire exclusive access to Host Adapter.
*/
- BusLogic_AcquireHostAdapterLock(HostAdapter, &Lock);
+ BusLogic_AcquireHostAdapterLock(HostAdapter, &ProcessorFlags);
/*
If this is an Asynchronous Reset and this Command has already completed,
then no Reset is necessary.
@@ -3876,7 +3825,7 @@ static int BusLogic_ResetHostAdapter(BusLogic_HostAdapter_T *HostAdapter,
Release exclusive access to Host Adapter.
*/
Done:
- BusLogic_ReleaseHostAdapterLock(HostAdapter, &Lock);
+ BusLogic_ReleaseHostAdapterLock(HostAdapter, &ProcessorFlags);
return Result;
}
@@ -3892,14 +3841,14 @@ static int BusLogic_SendBusDeviceReset(BusLogic_HostAdapter_T *HostAdapter,
{
int TargetID = Command->target;
BusLogic_CCB_T *CCB, *XCCB;
- BusLogic_Lock_T Lock;
+ ProcessorFlags_T ProcessorFlags;
int Result = -1;
BusLogic_IncrementErrorCounter(
&HostAdapter->TargetStatistics[TargetID].BusDeviceResetsRequested);
/*
Acquire exclusive access to Host Adapter.
*/
- BusLogic_AcquireHostAdapterLock(HostAdapter, &Lock);
+ BusLogic_AcquireHostAdapterLock(HostAdapter, &ProcessorFlags);
/*
If this is an Asynchronous Reset and this Command has already completed,
then no Reset is necessary.
@@ -4051,7 +4000,7 @@ static int BusLogic_SendBusDeviceReset(BusLogic_HostAdapter_T *HostAdapter,
if (BusLogic_FlashPointHostAdapterP(HostAdapter))
if (CCB->Status == BusLogic_CCB_Completed)
{
- BusLogic_ProcessCompletedCCBs();
+ BusLogic_ProcessCompletedCCBs(HostAdapter);
Result = SCSI_RESET_SUCCESS;
}
/*
@@ -4064,7 +4013,7 @@ Done:
/*
Release exclusive access to Host Adapter.
*/
- BusLogic_ReleaseHostAdapterLock(HostAdapter, &Lock);
+ BusLogic_ReleaseHostAdapterLock(HostAdapter, &ProcessorFlags);
return Result;
}
@@ -4260,7 +4209,7 @@ int BusLogic_ProcDirectoryInfo(char *ProcBuffer, char **StartPointer,
if (WriteFlag) return 0;
for (HostAdapter = BusLogic_FirstRegisteredHostAdapter;
HostAdapter != NULL;
- HostAdapter = HostAdapter->NextAll)
+ HostAdapter = HostAdapter->Next)
if (HostAdapter->HostNumber == HostNumber) break;
if (HostAdapter == NULL)
{
@@ -4567,14 +4516,18 @@ static boolean BusLogic_ParseKeyword(char **StringPointer, char *Keyword)
QueueDepth:<integer>
The "QueueDepth:" or QD:" option specifies the Queue Depth to use for all
- Target Devices that support Tagged Queuing. If no Queue Depth option is
- provided, the Queue Depth will be determined automatically based on the
- Host Adapter's Total Queue Depth and the number, type, speed, and
+ Target Devices that support Tagged Queuing, as well as the maximum Queue
+ Depth for devices that do not support Tagged Queuing. If no Queue Depth
+ option is provided, the Queue Depth will be determined automatically based
+ on the Host Adapter's Total Queue Depth and the number, type, speed, and
capabilities of the detected Target Devices. For Host Adapters that
require ISA Bounce Buffers, the Queue Depth is automatically set by default
- to BusLogic_QueueDepthBounceBuffers to avoid excessive preallocation of DMA
- Bounce Buffer memory. Target Devices that do not support Tagged Queuing
- always use a Queue Depth of BusLogic_UntaggedQueueDepth.
+ to BusLogic_TaggedQueueDepthBB or BusLogic_UntaggedQueueDepthBB to avoid
+ excessive preallocation of DMA Bounce Buffer memory. Target Devices that
+ do not support Tagged Queuing always have their Queue Depth set to
+ BusLogic_UntaggedQueueDepth or BusLogic_UntaggedQueueDepthBB, unless a
+ lower Queue Depth option is provided. A Queue Depth of 1 automatically
+ disables Tagged Queuing.
QueueDepth:[<integer>,<integer>...]
@@ -4826,6 +4779,7 @@ static void BusLogic_ParseDriverOptions(char *OptionsString)
NULL, QueueDepth);
return;
}
+ DriverOptions->CommonQueueDepth = QueueDepth;
for (TargetID = 0;
TargetID < BusLogic_MaxTargetDevices;
TargetID++)
diff --git a/drivers/scsi/BusLogic.h b/drivers/scsi/BusLogic.h
index ef7a8dcca..654550aed 100644
--- a/drivers/scsi/BusLogic.h
+++ b/drivers/scsi/BusLogic.h
@@ -2,7 +2,7 @@
Linux Driver for BusLogic MultiMaster and FlashPoint SCSI Host Adapters
- Copyright 1995 by Leonard N. Zubkoff <lnz@dandelion.com>
+ Copyright 1995-1998 by Leonard N. Zubkoff <lnz@dandelion.com>
This program is free software; you may redistribute and/or modify it under
the terms of the GNU General Public License Version 2 as published by the
@@ -36,8 +36,10 @@
typedef kdev_t KernelDevice_T;
typedef struct proc_dir_entry PROC_DirectoryEntry_T;
+typedef unsigned long ProcessorFlags_T;
typedef struct pt_regs Registers_T;
typedef struct partition PartitionTable_T;
+typedef struct pci_dev PCI_Device_T;
typedef Scsi_Host_Template SCSI_Host_Template_T;
typedef struct Scsi_Host SCSI_Host_T;
typedef struct scsi_device SCSI_Device_T;
@@ -966,16 +968,6 @@ typedef unsigned char BusLogic_RequestedReplyLength_T;
/*
- Define the Lock data structure. Until a true symmetric multiprocessing
- kernel with fine grained locking is available, acquiring the lock is
- implemented as saving the processor flags and disabling interrupts, and
- releasing the lock restores the saved processor flags.
-*/
-
-typedef unsigned long BusLogic_Lock_T;
-
-
-/*
Define the Outgoing Mailbox Action Codes.
*/
@@ -1252,6 +1244,7 @@ typedef struct BusLogic_DriverOptions
unsigned short TaggedQueuingPermittedMask;
unsigned short BusSettleTime;
BusLogic_LocalOptions_T LocalOptions;
+ unsigned char CommonQueueDepth;
unsigned char QueueDepth[BusLogic_MaxTargetDevices];
BusLogic_ErrorRecoveryStrategy_T
ErrorRecoveryStrategy[BusLogic_MaxTargetDevices];
@@ -1373,7 +1366,6 @@ typedef struct BusLogic_HostAdapter
unsigned char ModelName[9];
unsigned char FirmwareVersion[6];
unsigned char FullModelName[18];
- unsigned char InterruptLabel[68];
unsigned char Bus;
unsigned char Device;
unsigned char IRQ_Channel;
@@ -1400,7 +1392,8 @@ typedef struct BusLogic_HostAdapter
boolean HostAdapterInitialized:1;
boolean HostAdapterExternalReset:1;
boolean HostAdapterInternalError:1;
- volatile boolean HostAdapterCommandCompleted:1;
+ boolean ProcessCompletedCCBsActive;
+ volatile boolean HostAdapterCommandCompleted;
unsigned short HostAdapterScatterGatherLimit;
unsigned short DriverScatterGatherLimit;
unsigned short MaxTargetDevices;
@@ -1412,6 +1405,7 @@ typedef struct BusLogic_HostAdapter
unsigned short DriverQueueDepth;
unsigned short HostAdapterQueueDepth;
unsigned short UntaggedQueueDepth;
+ unsigned short CommonQueueDepth;
unsigned short BusSettleTime;
unsigned short SynchronousPermitted;
unsigned short FastPermitted;
@@ -1428,9 +1422,10 @@ typedef struct BusLogic_HostAdapter
FlashPoint_Info_T FlashPointInfo;
FlashPoint_CardHandle_T CardHandle;
struct BusLogic_HostAdapter *Next;
- struct BusLogic_HostAdapter *NextAll;
BusLogic_CCB_T *All_CCBs;
BusLogic_CCB_T *Free_CCBs;
+ BusLogic_CCB_T *FirstCompletedCCB;
+ BusLogic_CCB_T *LastCompletedCCB;
BusLogic_CCB_T *BusDeviceResetPendingCCB[BusLogic_MaxTargetDevices];
BusLogic_ErrorRecoveryStrategy_T
ErrorRecoveryStrategy[BusLogic_MaxTargetDevices];
@@ -1512,10 +1507,8 @@ SCSI_Inquiry_T;
static inline
void BusLogic_AcquireHostAdapterLock(BusLogic_HostAdapter_T *HostAdapter,
- BusLogic_Lock_T *Lock)
+ ProcessorFlags_T *ProcessorFlags)
{
- save_flags(*Lock);
- cli();
}
@@ -1525,33 +1518,34 @@ void BusLogic_AcquireHostAdapterLock(BusLogic_HostAdapter_T *HostAdapter,
static inline
void BusLogic_ReleaseHostAdapterLock(BusLogic_HostAdapter_T *HostAdapter,
- BusLogic_Lock_T *Lock)
+ ProcessorFlags_T *ProcessorFlags)
{
- restore_flags(*Lock);
}
/*
- BusLogic_AcquireHostAdapterLockID acquires exclusive access to Host Adapter,
- but is only called when interrupts are disabled.
+ BusLogic_AcquireHostAdapterLockIH acquires exclusive access to Host Adapter,
+ but is only called from the interrupt handler.
*/
static inline
-void BusLogic_AcquireHostAdapterLockID(BusLogic_HostAdapter_T *HostAdapter,
- BusLogic_Lock_T *Lock)
+void BusLogic_AcquireHostAdapterLockIH(BusLogic_HostAdapter_T *HostAdapter,
+ ProcessorFlags_T *ProcessorFlags)
{
+ spin_lock_irqsave(&io_request_lock, *ProcessorFlags);
}
/*
- BusLogic_ReleaseHostAdapterLockID releases exclusive access to Host Adapter,
- but is only called when interrupts are disabled.
+ BusLogic_ReleaseHostAdapterLockIH releases exclusive access to Host Adapter,
+ but is only called from the interrupt handler.
*/
static inline
-void BusLogic_ReleaseHostAdapterLockID(BusLogic_HostAdapter_T *HostAdapter,
- BusLogic_Lock_T *Lock)
+void BusLogic_ReleaseHostAdapterLockIH(BusLogic_HostAdapter_T *HostAdapter,
+ ProcessorFlags_T *ProcessorFlags)
{
+ spin_unlock_irqrestore(&io_request_lock, *ProcessorFlags);
}
@@ -1683,8 +1677,8 @@ static inline void *Bus_to_Virtual(BusLogic_BusAddress_T BusAddress)
/*
Virtual_to_32Bit_Virtual maps between Kernel Virtual Addresses and
- 32 Bit Kernel Virtual Addresses. This avoids compilation warnings
- on 64 Bit architectures.
+ 32 bit Kernel Virtual Addresses. This avoids compilation warnings
+ on 64 bit architectures.
*/
static inline
@@ -1749,17 +1743,6 @@ static inline void BusLogic_IncrementSizeBucket(BusLogic_CommandSizeBuckets_T
/*
- Define compatibility macros between Linux 2.0 and Linux 2.1.
-*/
-
-#if LINUX_VERSION_CODE < 0x20100
-
-#define MODULE_PARM(Variable, Type)
-
-#endif
-
-
-/*
Define the version number of the FlashPoint Firmware (SCCB Manager).
*/
diff --git a/drivers/scsi/Config.in b/drivers/scsi/Config.in
index 96e04f796..ddee59507 100644
--- a/drivers/scsi/Config.in
+++ b/drivers/scsi/Config.in
@@ -24,14 +24,12 @@ dep_tristate 'Adaptec AHA1542 support' CONFIG_SCSI_AHA1542 $CONFIG_SCSI
dep_tristate 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 $CONFIG_SCSI
dep_tristate 'Adaptec AIC7xxx support' CONFIG_SCSI_AIC7XXX $CONFIG_SCSI
if [ "$CONFIG_SCSI_AIC7XXX" != "n" ]; then
- bool ' Enable tagged command queueing' CONFIG_AIC7XXX_TAGGED_QUEUEING Y
bool ' Override driver defaults for commands per LUN' CONFIG_OVERRIDE_CMDS N
if [ "$CONFIG_OVERRIDE_CMDS" != "n" ]; then
- int ' Maximum number of commands per LUN' CONFIG_AIC7XXX_CMDS_PER_LUN 8
+ int ' Maximum number of commands per LUN' CONFIG_AIC7XXX_CMDS_PER_LUN 24
fi
- bool ' Enable SCB paging' CONFIG_AIC7XXX_PAGE_ENABLE N
bool ' Collect statistics to report in /proc' CONFIG_AIC7XXX_PROC_STATS N
- int ' Delay in seconds after SCSI bus reset' CONFIG_AIC7XXX_RESET_DELAY 15
+ int ' Delay in seconds after SCSI bus reset' CONFIG_AIC7XXX_RESET_DELAY 5
fi
dep_tristate 'AdvanSys SCSI support' CONFIG_SCSI_ADVANSYS $CONFIG_SCSI
dep_tristate 'Always IN2000 SCSI support' CONFIG_SCSI_IN2000 $CONFIG_SCSI
diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c
index ba1753147..2a339f426 100644
--- a/drivers/scsi/NCR5380.c
+++ b/drivers/scsi/NCR5380.c
@@ -491,11 +491,11 @@ static __inline__ void run_main(void) {
*/
#ifndef USLEEP_SLEEP
/* 20 ms (reasonable hard disk speed) */
-#define USLEEP_SLEEP 2
+#define USLEEP_SLEEP (20*HZ/1000)
#endif
/* 300 RPM (floppy speed) */
#ifndef USLEEP_POLL
-#define USLEEP_POLL 20
+#define USLEEP_POLL (200*HZ/1000)
#endif
static struct Scsi_Host * expires_first = NULL;
@@ -644,7 +644,7 @@ __initfunc(static int NCR5380_probe_irq (struct Scsi_Host *instance, int possibl
== 0))
trying_irqs |= mask;
- timeout = jiffies + 25;
+ timeout = jiffies + (250*HZ/1000);
probe_irq = IRQ_NONE;
/*
@@ -820,7 +820,7 @@ int NCR5380_proc_info (
SPRINTF("PAS16 release=%d", PAS16_PUBLIC_RELEASE);
#endif
- SPRINTF("\nBase Addr: 0x%05X ", (int)instance->base);
+ SPRINTF("\nBase Addr: 0x%05lX ", (long)instance->base);
SPRINTF("io_port: %04x ", (int)instance->io_port);
if (instance->irq == IRQ_NONE)
SPRINTF("IRQ: None.\n");
@@ -1003,7 +1003,7 @@ __initfunc(static void NCR5380_init (struct Scsi_Host *instance, int flags)) {
case 5:
printk("scsi%d: SCSI bus busy, waiting up to five seconds\n",
instance->host_no);
- timeout = jiffies + 500;
+ timeout = jiffies + 5*HZ;
while (jiffies < timeout && (NCR5380_read(STATUS_REG) & SR_BSY));
break;
case 2:
@@ -1279,6 +1279,9 @@ static void NCR5380_main (void) {
}
#ifndef DONT_USE_INTR
+#include <linux/blk.h>
+#include <asm/spinlock.h>
+
/*
* Function : void NCR5380_intr (int irq)
*
@@ -1390,6 +1393,16 @@ static void NCR5380_intr (int irq, void *dev_id, struct pt_regs * regs) {
} /* if (instance->irq == irq) */
} while (!done);
}
+
+
+static void do_NCR5380_intr (int irq, void *dev_id, struct pt_regs * regs) {
+ unsigned long flags;
+
+ spin_lock_irqsave(&io_request_lock, flags);
+ NCR5380_intr(irq, dev_id, regs);
+ spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
#endif
#ifdef NCR5380_STATS
@@ -1619,7 +1632,7 @@ static int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd,
* selection.
*/
- timeout = jiffies + 25;
+ timeout = jiffies + (250*HZ/1000);
/*
* XXX very interesting - we're seeing a bounce where the BSY we
diff --git a/drivers/scsi/NCR5380.h b/drivers/scsi/NCR5380.h
index 50708cfca..d84534dd4 100644
--- a/drivers/scsi/NCR5380.h
+++ b/drivers/scsi/NCR5380.h
@@ -286,6 +286,7 @@ static void NCR5380_init (struct Scsi_Host *instance, int flags);
static void NCR5380_information_transfer (struct Scsi_Host *instance);
#ifndef DONT_USE_INTR
static void NCR5380_intr (int irq, void *dev_id, struct pt_regs * regs);
+static void do_NCR5380_intr (int irq, void *dev_id, struct pt_regs * regs);
#endif
static void NCR5380_main (void);
static void NCR5380_print_options (struct Scsi_Host *instance);
@@ -314,29 +315,33 @@ static int NCR5380_transfer_dma (struct Scsi_Host *instance,
static int NCR5380_transfer_pio (struct Scsi_Host *instance,
unsigned char *phase, int *count, unsigned char **data);
-#if (defined(REAL_DMA) || defined(REAL_DMA_POLL)) && defined(i386)
-static __inline__ int NCR5380_i386_dma_setup (struct Scsi_Host *instance,
+#if (defined(REAL_DMA) || defined(REAL_DMA_POLL))
+
+#if defined(i386) || defined(__alpha__)
+
+static __inline__ int NCR5380_pc_dma_setup (struct Scsi_Host *instance,
unsigned char *ptr, unsigned int count, unsigned char mode) {
unsigned limit;
+ unsigned long bus_addr = virt_to_bus(ptr);
if (instance->dma_channel <=3) {
if (count > 65536)
count = 65536;
- limit = 65536 - (((unsigned) ptr) & 0xFFFF);
+ limit = 65536 - (bus_addr & 0xFFFF);
} else {
if (count > 65536 * 2)
count = 65536 * 2;
- limit = 65536* 2 - (((unsigned) ptr) & 0x1FFFF);
+ limit = 65536* 2 - (bus_addr & 0x1FFFF);
}
if (count > limit) count = limit;
- if ((count & 1) || (((unsigned) ptr) & 1))
+ if ((count & 1) || (bus_addr & 1))
panic ("scsi%d : attempted unaligned DMA transfer\n", instance->host_no);
cli();
disable_dma(instance->dma_channel);
clear_dma_ff(instance->dma_channel);
- set_dma_addr(instance->dma_channel, (unsigned int) ptr);
+ set_dma_addr(instance->dma_channel, bus_addr);
set_dma_count(instance->dma_channel, count);
set_dma_mode(instance->dma_channel, mode);
enable_dma(instance->dma_channel);
@@ -344,17 +349,17 @@ static __inline__ int NCR5380_i386_dma_setup (struct Scsi_Host *instance,
return count;
}
-static __inline__ int NCR5380_i386_dma_write_setup (struct Scsi_Host *instance,
+static __inline__ int NCR5380_pc_dma_write_setup (struct Scsi_Host *instance,
unsigned char *src, unsigned int count) {
- return NCR5380_i386_dma_setup (instance, src, count, DMA_MODE_WRITE);
+ return NCR5380_pc_dma_setup (instance, src, count, DMA_MODE_WRITE);
}
-static __inline__ int NCR5380_i386_dma_read_setup (struct Scsi_Host *instance,
+static __inline__ int NCR5380_pc_dma_read_setup (struct Scsi_Host *instance,
unsigned char *src, unsigned int count) {
- return NCR5380_i386_dma_setup (instance, src, count, DMA_MODE_READ);
+ return NCR5380_pc_dma_setup (instance, src, count, DMA_MODE_READ);
}
-static __inline__ int NCR5380_i386_dma_residual (struct Scsi_Host *instance) {
+static __inline__ int NCR5380_pc_dma_residual (struct Scsi_Host *instance) {
register int tmp;
cli();
clear_dma_ff(instance->dma_channel);
@@ -362,7 +367,8 @@ static __inline__ int NCR5380_i386_dma_residual (struct Scsi_Host *instance) {
sti();
return tmp;
}
-#endif /* defined(REAL_DMA) && defined(i386) */
+#endif /* defined(i386) || defined(__alpha__) */
+#endif /* defined(REAL_DMA) */
#endif __KERNEL_
#endif /* ndef ASM */
#endif /* NCR5380_H */
diff --git a/drivers/scsi/NCR53c406a.c b/drivers/scsi/NCR53c406a.c
index d2529b17e..a133a7d72 100644
--- a/drivers/scsi/NCR53c406a.c
+++ b/drivers/scsi/NCR53c406a.c
@@ -52,6 +52,7 @@
#include <asm/irq.h>
#include <linux/blk.h>
+#include <asm/spinlock.h>
#include "scsi.h"
#include "hosts.h"
#include "sd.h"
@@ -171,6 +172,7 @@ enum Phase {
/* Static function prototypes */
static void NCR53c406a_intr(int, void *, struct pt_regs *);
+static void do_NCR53c406a_intr(int, void *, struct pt_regs *);
static void internal_done(Scsi_Cmnd *);
static void wait_intr(void);
static void chip_init(void);
@@ -226,7 +228,8 @@ static void *addresses[] = {
#endif USE_BIOS
/* possible i/o port addresses */
-static unsigned short ports[] = { 0x230, 0x330 };
+static unsigned short ports[] =
+ { 0x230, 0x330, 0x280, 0x290, 0x330, 0x340, 0x300, 0x310, 0x348, 0x350 };
#define PORT_COUNT (sizeof( ports ) / sizeof( unsigned short ))
/* possible interrupt channels */
@@ -538,7 +541,7 @@ NCR53c406a_detect(Scsi_Host_Template * tpnt)){
request_region(port_base, 0x10, "NCR53c406a");
if(irq_level > 0) {
- if(request_irq(irq_level, NCR53c406a_intr, 0, "NCR53c406a", NULL)){
+ if(request_irq(irq_level, do_NCR53c406a_intr, 0, "NCR53c406a", NULL)){
printk("NCR53c406a: unable to allocate IRQ %d\n", irq_level);
return 0;
}
@@ -764,6 +767,15 @@ NCR53c406a_biosparm(Scsi_Disk *disk, kdev_t dev, int* info_array){
}
static void
+do_NCR53c406a_intr(int unused, void *dev_id, struct pt_regs *regs){
+ unsigned long flags;
+
+ spin_lock_irqsave(&io_request_lock, flags);
+ NCR53c406a_intr(0, dev_id, regs);
+ spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
+ static void
NCR53c406a_intr(int unused, void *dev_id, struct pt_regs *regs){
DEB(unsigned char fifo_size;)
DEB(unsigned char seq_reg;)
diff --git a/drivers/scsi/README.BusLogic b/drivers/scsi/README.BusLogic
index 60fa4011c..05ac7412c 100644
--- a/drivers/scsi/README.BusLogic
+++ b/drivers/scsi/README.BusLogic
@@ -1,10 +1,10 @@
BusLogic MultiMaster and FlashPoint SCSI Driver for Linux
- Version 2.0.11 for Linux 2.0
+ Version 2.0.12 for Linux 2.0
PRODUCTION RELEASE
- 31 January 1998
+ 29 March 1998
Leonard N. Zubkoff
Dandelion Digital
@@ -429,14 +429,18 @@ following options are available:
QueueDepth:<integer>
The "QueueDepth:" or QD:" option specifies the Queue Depth to use for all
- Target Devices that support Tagged Queuing. If no Queue Depth option is
- provided, the Queue Depth will be determined automatically based on the
- Host Adapter's Total Queue Depth and the number, type, speed, and
+ Target Devices that support Tagged Queuing, as well as the maximum Queue
+ Depth for devices that do not support Tagged Queuing. If no Queue Depth
+ option is provided, the Queue Depth will be determined automatically based
+ on the Host Adapter's Total Queue Depth and the number, type, speed, and
capabilities of the detected Target Devices. For Host Adapters that
require ISA Bounce Buffers, the Queue Depth is automatically set by default
- to BusLogic_QueueDepthBounceBuffers to avoid excessive preallocation of DMA
- Bounce Buffer memory. Target Devices that do not support Tagged Queuing
- always use a Queue Depth of BusLogic_UntaggedQueueDepth.
+ to BusLogic_TaggedQueueDepthBB or BusLogic_UntaggedQueueDepthBB to avoid
+ excessive preallocation of DMA Bounce Buffer memory. Target Devices that
+ do not support Tagged Queuing always have their Queue Depth set to
+ BusLogic_UntaggedQueueDepth or BusLogic_UntaggedQueueDepthBB, unless a
+ lower Queue Depth option is provided. A Queue Depth of 1 automatically
+ disables Tagged Queuing.
QueueDepth:[<integer>,<integer>...]
@@ -587,7 +591,7 @@ To install the new BusLogic SCSI driver, you may use the following commands,
replacing "/usr/src" with wherever you keep your Linux kernel source tree:
cd /usr/src
- tar -xvzf BusLogic-2.0.11.tar.gz
+ tar -xvzf BusLogic-2.0.12.tar.gz
mv README.* LICENSE.* BusLogic.[ch] FlashPoint.c linux/drivers/scsi
patch -p < BusLogic.patch
cd linux
diff --git a/drivers/scsi/README.aic7xxx b/drivers/scsi/README.aic7xxx
index 5ec8a51d2..7cbe9fbdc 100644
--- a/drivers/scsi/README.aic7xxx
+++ b/drivers/scsi/README.aic7xxx
@@ -1,8 +1,7 @@
AIC7xxx Driver for Linux
- July 20, 1997
Introduction
-------------------------
+----------------------------
The AIC7xxx SCSI driver adds support for Adaptec (http://www.adaptec.com)
SCSI controllers and chipsets. Major portions of the driver and driver
development are shared between both Linux and FreeBSD. Support for the
@@ -11,32 +10,42 @@ linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD
2.1.0 or later.
Supported cards/chipsets
- ------------------------
+ ----------------------------
Adaptec Cards
- -----------------------
- AHA-274x
- AHA-2842
+ ----------------------------
+ AHA-274x
+ AHA-274xT
+ AHA-2842
+ AHA-2910B
AHA-2940
AHA-2940W
AHA-2940U
- AHA-2940UW
+ AHA-2940UW
+ AHA-2940AU
AHA-2944D
AHA-2944WD
+ AHA-2944UD
+ AHA-2944UWD
AHA-3940
+ AHA-3940U
AHA-3940W
+ AHA-3940UW
AHA-3985
+ AHA-3985U
AHA-3985W
+ AHA-3985UW
Motherboard Chipsets
- -----------------------
+ ----------------------------
AIC-777x
AIC-785x
AIC-786x
AIC-787x
AIC-788x
+ AIC-7895
Bus Types
- -----------------------
+ ----------------------------
W - Wide SCSI, SCSI-3, 16bit bus, 68pin connector, will also support
SCSI-1/SCSI-2 50pin devices, transfer rates up to 20MB/s.
U - Ultra SCSI, transfer rates up to 40MB/s.
@@ -50,23 +59,28 @@ linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD
AHA-398x - PCI RAID controllers with three separate SCSI controllers
on-board.
- NOTE: The AHA-2920 is NOT a AIC-7xxx based controller, and is not
+ NOTE: The AHA-2920 is NOT an AIC-7xxx based controller, and is not
handled by this driver.
People
- ------------------------
- Justin T Gibbs gibbs@freefall.FreeBSD.org (BSD Driver Author)
- Dan Eischen deischen@iworks.InterWorks.org (Linux Driver Co-maintainer)
- Dean Gehnert deang@teleport.com (Linux FTP/patch maintainer)
- Jess Johnson jester@frenzy.com (AIC7xxx FAQ author)
- Doug Ledford dledford@dialnet.net (Stress tester/bug squasher)
-
+ ------------------------------
+ Justin T Gibbs gibbs@plutotech.com
+ (BSD Driver Author)
+ Dan Eischen deischen@iworks.InterWorks.org
+ (Original Linux Driver Co-maintainer)
+ Dean Gehnert deang@teleport.com
+ (Original Linux FTP/patch maintainer)
+ Jess Johnson jester@frenzy.com
+ (AIC7xxx FAQ author)
+ Doug Ledford dledford@dialnet.net
+ (Current Linux aic7xxx-5.x.x Driver/Patch/FTP/FAQ maintainer)
+
Special thanks go to John Aycock (aycock@cpsc.ucalgary.ca), the original
author of the driver. John has since retired from the project. Thanks
again for all his work!
-
+
Mailing list
- ------------------------
+ ------------------------------
There is a mailing list available for users who want to track development
and converse with other users and developers. This list is for both
FreeBSD and Linux support of the AIC7xxx chipsets.
@@ -84,20 +98,150 @@ linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD
Send regular messages and replies to: AIC7xxx@FreeBSD.ORG
- Command line options ("aic7xxx=option[,option...]")
- ---------------------------------------------------
+ Boot Command line options
+ ------------------------------
"aic7xxx=no_reset" - Eliminate the SCSI reset delay during startup.
Some SCSI devices need some extra time to reset.
- "aic7xxx=extended" - Force extended translation.
- "aic7xxx=ultra" - Force Ultra mode
- "aic7xxx=irq_trigger:[0,1]" - Edge (0) or Level (1) triggered
- interrupts. AFAIK, the driver only works with level triggered
- interrupts. This only applies to EISA adapters.
- "aic7xxx=verbose" - Enable more bootup messages. PLEASE use this
- if you have problems with the driver.
+ "aic7xxx=reverse_scan" - Have the driver register the SCSI cards in the
+ reverse of the normal order. This may help those people who have more
+ than one PCI Adaptec controller force the correct controller to be
+ scsi0 under linux so that their boot hard drive is also sda under
+ linux
+ "aic7xxx=extended" - Force the driver to detect extended drive translation
+ on your controller. This helps those people who have cards without
+ a SEEPROM make sure that linux and all other operating systems think
+ the same way about your hard drives.
+ "aic7xxx=irq_trigger:x" - Replace x with either 0 or 1 to force the kernel
+ to use the correct IRQ type for your card. This only applies to EISA
+ based controllers. On these controllers, 0 is for Edge triggered
+ interrupts, and 1 is for Level triggered interrupts. If you aren't
+ sure or don't know which IRQ trigger type your EISA card uses, then
+ let the kernel autodetect the trigger type.
+ "aic7xxx=verbose" - This option can be used in one of two ways. If you
+ simply specify aic7xxx=verbose, then the kernel will automatically pick
+ the default set of verbose messages for you to see. Alternatively, you
+ can specify the command as "aic7xxx=verbose:0xXXXX" where the X entries
+ are replaced with hexadecimal digits. This option is a bit field type
+ option. For a full listing of the available options, search for the
+ #define VERBOSE_xxxxxx lines in the aic7xxx.c file. If you want verbose
+ messages, then it is recommended that you simply use the aic7xxx=verbose
+ variant of this command.
+ "aic7xxx=7895_irq_hack:x" - This option enables some work around code to
+ fix a bug in the Tyan Thunder II motherboard BIOS. The BIOS
+ incorrectly sets the IRQs on the two channels of the 7895 to two
+ different values even though the motherboard hardware doesn't support
+ this mode of operation. The valid values for x are: 0 to force
+ both channels to use the IRQ assigned to Channel A, 1 to force both
+ channels to use the IRQ assigned to Channel B, and -1 will disable
+ this horrible abomination of a hack. The default is disabled (-1).
+ "aic7xxx=tag_info:{{8,8..},{8,8..},..}" - This option is used to enable
+ tagged queueing on specific devices. As of driver version 5.0.6, we
+ now globally enable tagged queueing by default, but we also disable
+ tagged queueing on all individual devices by default. In order to
+ enable tagged queueing for certian devices at boot time, a user may
+ use this boot param. The driver will then parse this message out
+ and enable the specific device entries that are present based upon
+ the value given. The param line is parsed in the following manner:
+
+ { - first instance indicates the start of this parameter values
+ second instance is the start of entries for a particular
+ device entry
+ } - end the entries for a particular host adapter, or end the entire
+ set of parameter entries
+ , - move to next entry. Inside of a set of device entries, this
+ moves us to the next device on the list. Outside of device
+ entries, this moves us to the next host adapter
+ . - Same effect as , but is safe to use with insmod.
+ x - the number to enter into the array at this position.
+ 0 = Enable tagged queueing on this device and use the default
+ queue depth
+ 1-254 = Enable tagged queueing on this device and use this
+ number as the queue depth
+ 255 = Disable tagged queueing on this device.
+ Note: anything above 32 for an actual queue depth is wasteful
+ and not recommended.
+
+ A few examples of how this can be used:
+
+ tag_info:{{8,12,,0,,255,4}}
+ This line will only effect the first aic7xxx card registered. It
+ will set scsi id 0 to a queue depth of 8, id 1 to 12, leave id 2
+ at the default, set id 3 to tagged queueing enabled and use the
+ default queue depth, id 4 default, id 5 disabled, and id 6 to 4.
+ Any not specified entries stay at the default value, repeated
+ commas with no value specified will simply increment to the next id
+ without changing anything for the missing values.
+
+ tag_info:{{8,8},,{8,8}}
+ First adapter, scsi id 0 to 8, id 1 to 8, remainder stay at their
+ default. Second adapter stays entirely at default. Third
+ adapter, id 0 to 8, id 1 to 8, remainder at default (identical to
+ first adapter).
+
+ tag_info:{,,,{,,,64}}
+ First, second, and third adapters at default values. Fourth
+ adapter, id 3 to 64. Notice that leading commas simply increment
+ what the first number effects, and there are no need for trailing
+ commas. When you close out an adapter, or the entire entry,
+ anything not explicitly set stays at the default value.
+
+ A final note on this option. The scanner I used for this isn't
+ perfect or highly robust. If you mess the line up, the worst that
+ should happen is that the line will get ignored. If you don't
+ close out the entire entry with the final bracket, then any other
+ aic7xxx options after this will get ignored. So, in general, be
+ sure of what you are entering, and after you have it right, just
+ add it to the lilo.conf file so there won't be any mistakes. As
+ a means of checking this parser, the entire tag_info array for
+ each card is now printed out in the /proc/scsi/aic7xxx/x file. You
+ can use that to verify that your options were parsed correctly.
+
+ Boot command line options may be combined to form the proper set of options
+ a user might need. For example, the following is valid:
+
+ aic7xxx=verbose,extended,irq_trigger:1
+
+ The only requirement is that individual options be separated by a comma on
+ the command line.
+
+ Module Loading command options
+ ------------------------------
+ When loading the aic7xxx driver as a module, the exact same options are
+ available to the user. However, the syntax to specify the options changes
+ slightly. For insmod, you need to wrap the aic7xxx= argument in quotes
+ and replace all ',' with '.'. So, for example, a valid insmod line
+ would be:
+
+ insmod aic7xxx aic7xxx='verbose.irq_trigger:1.extended'
+
+ This line should result in the *exact* same behaviour as if you typed
+ it in at the lilo prompt and the driver was compiled into the kernel
+ instead of being a module. The reason for the single quote is so that
+ the shell won't try to interpret anything in the line, such as {.
+ Insmod assumes any options starting with a letter instead of a number
+ is a character string (which is what we want) and by switching all of
+ the commas to periods, insmod won't interpret this as more than one
+ string and write junk into our binary image. I consider it a bug in
+ the insmod program that even if you wrap your string in quotes (quotes
+ that pass the shell mind you and that insmod sees) it still treates
+ a comma inside of those quotes as starting a new variable, resulting
+ in memory scribbles if you don't switch the commas to periods.
+
+
+ Kernel Compile options
+ ------------------------------
+ The various kernel compile time options for this driver are now fairly
+ well documented in the file Documentation/Configure.help. In order to
+ see this documentation, you need to use one of the advanced configuration
+ programs (menuconfig and xconfig). If you are using the "make menuconfig"
+ method of configuring your kernel, then you would simply highlight the
+ option in question and hit the F1 key. If you are using the "make xconfig"
+ method of configuring your kernel, then simply click on the help button next
+ to the option you have questions about. The help information from the
+ Configure.help file will then get automatically displayed.
/proc support
- ------------------------
+ ------------------------------
The /proc support for the AIC7xxx can be found in the /proc/scsi/aic7xxx/
directory. That directory contains a file for each SCSI controller in
the system. Each file presents the current configuration and transfer
@@ -107,45 +251,19 @@ linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD
Matthew Jacob for statistics support.
FTP sites
- ------------------------
- ftp://ftp.teleport.com/users/deang/Linux/aic7xxx/
- - Main Linux AIC7xxx driver release/pre-release site
- - Experimental/development patches and bootdisks
+ ------------------------------
ftp://ftp.dialnet.net/pub/linux/aic7xxx/
+ - Primary site for Doug Ledford developed driver releases
- US Linux mirror of Teleport site
+ ftp://ftp.pcnet.com/users/eischen/Linux/
+ - Dan Eischen's driver distribution area
ftp://ekf2.vsb.cz/pub/linux/kernel/aic7xxx/ftp.teleport.com/
- European Linux mirror of Teleport site
- ftp://ftp.pcnet.com/users/eischen/Linux/
- - Daniel Eischens experimental/development ftp site that is
- also home of the Linux aic7xxx sequencer assembler source.
-
- Sequencer assembler
- ------------------------
- The sequencer assembler is no longer being distributed with the
- Linux kernel. The sequencer assembler (aic7xxx_asm) is now being
- maintained by Justin Gibbs under a BSD copyright (which pretty
- much lets you do anything you want with it). I keep a Linux
- version of the assembler at my ftp site should you wish to hack
- the sequencer code (ftp://ftp.pcnet.com/users/eischen/Linux/).
- Please note that you do NOT need the assembler to build a kernel
- with aic7xxx support. The assembler generates the code that is
- downloaded to the aic7xxx controllers; this code IS part of the
- Linux kernel (aic7xxx_seq.h and aic7xxx_reg.h).
-
- Problems compiling the kernel with aic7xxx support
- --------------------------------------------------
- This is probably due to having modified the sequencer files in
- some way. If you are not modifying the sequencer source (in
- drivers/scsi/aic7xxx/aic7xxx.seq), then you can just re-extract
- the necessary files from your kernel tarball. Otherwise, visit
- my anonymous ftp site (ftp.pcnet.com) and grab the sequencer
- assembler source.
Dean W. Gehnert
deang@teleport.com
-(Modified by D. Eischen, 7/20/97)
-
-$Revision: 3.1a $
+$Revision: 3.0 $
+Modified by Doug Ledford 1998
diff --git a/drivers/scsi/README.in2000 b/drivers/scsi/README.in2000
index 861d6efb2..8c48f0ff3 100644
--- a/drivers/scsi/README.in2000
+++ b/drivers/scsi/README.in2000
@@ -1,4 +1,11 @@
+UPDATE NEWS: version 1.32 - 28 Mar 98
+
+ Removed the check for legal IN2000 hardware versions:
+ It appears that the driver works fine with serial
+ EPROMs (the 8-pin chip that defines hardware rev) as
+ old as 2.1, so we'll assume that all cards are OK.
+
UPDATE NEWS: version 1.31 - 6 Jul 97
Fixed a bug that caused incorrect SCSI status bytes to be
diff --git a/drivers/scsi/a2091.c b/drivers/scsi/a2091.c
index fedb3ed66..eb440ca6d 100644
--- a/drivers/scsi/a2091.c
+++ b/drivers/scsi/a2091.c
@@ -12,6 +12,7 @@
#include <asm/amigahw.h>
#include <linux/zorro.h>
#include <asm/irq.h>
+#include <asm/spinlock.h>
#include "scsi.h"
#include "hosts.h"
@@ -35,7 +36,6 @@ static void a2091_intr (int irq, void *dummy, struct pt_regs *fp)
{
unsigned int status;
struct Scsi_Host *instance;
-
for (instance = first_instance; instance &&
instance->hostt == a2091_template; instance = instance->next)
{
@@ -54,6 +54,15 @@ static void a2091_intr (int irq, void *dummy, struct pt_regs *fp)
}
}
+static void do_a2091_intr (int irq, void *dummy, struct pt_regs *fp)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&io_request_lock, flags);
+ a2091_intr(irq, dummy, fp);
+ spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
static int dma_setup (Scsi_Cmnd *cmd, int dir_in)
{
unsigned short cntr = CNTR_PDMD | CNTR_INTEN;
@@ -220,7 +229,7 @@ __initfunc(int a2091_detect(Scsi_Host_Template *tpnt))
if (num_a2091++ == 0) {
first_instance = instance;
a2091_template = instance->hostt;
- request_irq(IRQ_AMIGA_PORTS, a2091_intr, 0, "A2091 SCSI", a2091_intr);
+ request_irq(IRQ_AMIGA_PORTS, do_a2091_intr, 0, "A2091 SCSI", a2091_intr);
}
DMA(instance)->CNTR = CNTR_PDMD | CNTR_INTEN;
zorro_config_board(key, 0);
diff --git a/drivers/scsi/a3000.c b/drivers/scsi/a3000.c
index fdc7fd41d..099d33704 100644
--- a/drivers/scsi/a3000.c
+++ b/drivers/scsi/a3000.c
@@ -11,6 +11,7 @@
#include <asm/amigaints.h>
#include <asm/amigahw.h>
#include <asm/irq.h>
+#include <asm/spinlock.h>
#include "scsi.h"
#include "hosts.h"
@@ -35,7 +36,6 @@ static void a3000_intr (int irq, void *dummy, struct pt_regs *fp)
if (!(status & ISTR_INT_P))
return;
-
if (status & ISTR_INTS)
{
/* disable PORTS interrupt */
@@ -48,6 +48,14 @@ static void a3000_intr (int irq, void *dummy, struct pt_regs *fp)
}
}
+static void do_a3000_intr (int irq, void *dummy, struct pt_regs *fp)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&io_request_lock, flags);
+ a3000_intr(irq, dummy, fp);
+ spin_unlock_irqrestore(&io_request_lock, flags);
+}
static int dma_setup (Scsi_Cmnd *cmd, int dir_in)
{
unsigned short cntr = CNTR_PDMD | CNTR_INTEN;
@@ -186,7 +194,7 @@ __initfunc(int a3000_detect(Scsi_Host_Template *tpnt))
DMA(a3000_host)->DAWR = DAWR_A3000;
wd33c93_init(a3000_host, (wd33c93_regs *)&(DMA(a3000_host)->SASR),
dma_setup, dma_stop, WD33C93_FS_12_15);
- request_irq(IRQ_AMIGA_PORTS, a3000_intr, 0, "A3000 SCSI", a3000_intr);
+ request_irq(IRQ_AMIGA_PORTS, do_a3000_intr, 0, "A3000 SCSI", a3000_intr);
DMA(a3000_host)->CNTR = CNTR_PDMD | CNTR_INTEN;
called = 1;
diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c
index 315de3935..c67a96258 100644
--- a/drivers/scsi/advansys.c
+++ b/drivers/scsi/advansys.c
@@ -598,7 +598,7 @@
Erik Ratcliffe <erik@caldera.com> has done testing of the
AdvanSys driver in the Caldera releases.
- Rik van Riel <H.H.vanRiel@fys.ruu.nl> provided a patch to
+ Rik van Riel <H.H.vanRiel@phys.uu.nl> provided a patch to
AscWaitTixISRDone() which he found necessary to make the
driver work with a SCSI-1 disk.
@@ -668,6 +668,9 @@
#include <linux/blk.h>
#include <linux/stat.h>
#endif /* version >= v1.3.0 */
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,95)
+#include <asm/spinlock.h>
+#endif
#include "scsi.h"
#include "hosts.h"
#include "sd.h"
@@ -3841,8 +3844,11 @@ STATIC int asc_proc_copy(off_t, off_t, char *, int , char *, int);
#endif /* version >= v1.3.0 */
#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,70)
STATIC void advansys_interrupt(int, struct pt_regs *);
-#else /* version >= v1.3.70 */
+#elif LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,95)
+STATIC void advansys_interrupt(int, void *, struct pt_regs *);
+#else /* version >= 2.1.95 */
STATIC void advansys_interrupt(int, void *, struct pt_regs *);
+STATIC void do_advansys_interrupt(int, void *, struct pt_regs *);
#endif /* version >= v1.3.70 */
#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
STATIC void advansys_select_queue_depths(struct Scsi_Host *,
@@ -4880,10 +4886,14 @@ advansys_detect(Scsi_Host_Template *tpnt)
#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,70)
if ((ret = request_irq(shp->irq, advansys_interrupt,
SA_INTERRUPT, "advansys")) != 0)
-#else /* version >= v1.3.70 */
+#elif LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,95)
if ((ret = request_irq(shp->irq, advansys_interrupt,
SA_INTERRUPT | (share_irq == TRUE ? SA_SHIRQ : 0),
"advansys", boardp)) != 0)
+#else /* version >= 2.1.95 */
+ if ((ret = request_irq(shp->irq, do_advansys_interrupt,
+ SA_INTERRUPT | (share_irq == TRUE ? SA_SHIRQ : 0),
+ "advansys", boardp)) != 0)
#endif /* version >= v1.3.70 */
{
ASC_PRINT2(
@@ -6205,6 +6215,18 @@ advansys_interrupt(int irq, void *dev_id, struct pt_regs *regs)
return;
}
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,95)
+static void
+do_advansys_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&io_request_lock, flags);
+ advansys_interrupt(irq, dev_id, regs);
+ spin_unlock_irqrestore(&io_request_lock, flags);
+}
+#endif
+
#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
/*
* Set the number of commands to queue per device for the
diff --git a/drivers/scsi/aha1542.c b/drivers/scsi/aha1542.c
index c291a95e6..c0003a18d 100644
--- a/drivers/scsi/aha1542.c
+++ b/drivers/scsi/aha1542.c
@@ -30,6 +30,7 @@
#include <linux/proc_fs.h>
#include <asm/dma.h>
#include <asm/system.h>
+#include <asm/spinlock.h>
#include <asm/io.h>
#include <linux/blk.h>
#include "scsi.h"
@@ -129,6 +130,8 @@ static struct Scsi_Host * aha_host[7] = {NULL,}; /* One for each IRQ level (9-1
static void setup_mailboxes(int base_io, struct Scsi_Host * shpnt);
static int aha1542_restart(struct Scsi_Host * shost);
+static void aha1542_intr_handle(int irq, void *dev_id, struct pt_regs *regs);
+static void do_aha1542_intr_handle(int irq, void *dev_id, struct pt_regs *regs);
#define aha1542_intr_reset(base) outb(IRST, CONTROL(base))
@@ -363,6 +366,16 @@ static int aha1542_test_port(int bse, struct Scsi_Host * shpnt)
return 0; /* 0 = not ok */
}
+/* A quick wrapper for do_aha1542_intr_handle to grab the spin lock */
+static void do_aha1542_intr_handle(int irq, void *dev_id, struct pt_regs *regs)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&io_request_lock, flags);
+ aha1542_intr_handle(irq, dev_id, regs);
+ spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
/* A "high" level interrupt handler */
static void aha1542_intr_handle(int irq, void *dev_id, struct pt_regs *regs)
{
@@ -1013,7 +1026,7 @@ int aha1542_detect(Scsi_Host_Template * tpnt)
DEB(printk("aha1542_detect: enable interrupt channel %d\n", irq_level));
save_flags(flags);
cli();
- if (request_irq(irq_level,aha1542_intr_handle, 0, "aha1542", NULL)) {
+ if (request_irq(irq_level,do_aha1542_intr_handle, 0, "aha1542", NULL)) {
printk("Unable to allocate IRQ for adaptec controller.\n");
restore_flags(flags);
goto unregister;
diff --git a/drivers/scsi/aha1740.c b/drivers/scsi/aha1740.c
index 802dd3fba..a9ec8f76a 100644
--- a/drivers/scsi/aha1740.c
+++ b/drivers/scsi/aha1740.c
@@ -228,6 +228,9 @@ void aha1740_intr_handle(int irq, void *dev_id, struct pt_regs * regs)
struct ecb *ecbptr;
Scsi_Cmnd *SCtmp;
unsigned int base;
+ unsigned long flags;
+
+ spin_lock_irqsave(&io_request_lock, flags);
if (!aha_host[irq - 9])
panic("aha1740.c: Irq from unknown host!\n");
@@ -304,6 +307,8 @@ void aha1740_intr_handle(int irq, void *dev_id, struct pt_regs * regs)
}
number_serviced++;
}
+
+ spin_unlock_irqrestore(&io_request_lock, flags);
}
int aha1740_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
diff --git a/drivers/scsi/aic7xxx.c b/drivers/scsi/aic7xxx.c
index 7839a2399..cc265ecb7 100644
--- a/drivers/scsi/aic7xxx.c
+++ b/drivers/scsi/aic7xxx.c
@@ -38,7 +38,7 @@
* Parts of this driver were also based on the FreeBSD driver by
* Justin T. Gibbs. His copyright follows:
*
- * --------------------------------------------------------------------------
+ * --------------------------------------------------------------------------
* Copyright (c) 1994-1997 Justin Gibbs.
* All rights reserved.
*
@@ -96,6 +96,73 @@
* $Id: aic7xxx.c,v 4.1 1997/06/12 08:23:42 deang Exp $
*-M*************************************************************************/
+/*+M**************************************************************************
+ *
+ * Further driver modifications made by Doug Ledford <dledford@dialnet.net>
+ *
+ * Copyright (c) 1997-1998 Doug Ledford
+ *
+ * These changes are released under the same licensing terms as the FreeBSD
+ * driver written by Justin Gibbs. Please see his Copyright notice above
+ * for the exact terms and conditions covering my changes as well as the
+ * warranty statement.
+ *
+ * Modifications made to the aic7xxx.c,v 4.1 driver from Dan Eischen include
+ * but are not limited to:
+ *
+ * 1: Import of the latest FreeBSD sequencer code for this driver
+ * 2: Modification of kernel code to accomodate different sequencer semantics
+ * 3: Extensive changes throughout kernel portion of driver to improve
+ * abort/reset processing and error hanndling
+ * 4: Other work contributed by various people on the Internet
+ * 5: Changes to printk information and verbosity selection code
+ * 6: General reliability related changes, especially in IRQ management
+ * 7: Modifications to the default probe/attach order for supported cards
+ * 8: SMP friendliness has been improved
+ *
+ * Overall, this driver represents a significant departure from the official
+ * aic7xxx driver released by Dan Eischen in two ways. First, in the code
+ * itself. A diff between the two version of the driver is now a several
+ * thousand line diff. Second, in approach to solving the same problem. The
+ * problem is importing the FreeBSD aic7xxx driver code to linux can be a
+ * difficult and time consuming process, that also can be error prone. Dan
+ * Eischen's official driver uses the approach that the linux and FreeBSD
+ * drivers should be as identical as possible. To that end, his next version
+ * of this driver will be using a mid-layer code library that he is developing
+ * to moderate communications between the linux mid-level SCSI code and the
+ * low level FreeBSD driver. He intends to be able to essentially drop the
+ * FreeBSD driver into the linux kernel with only a few minor tweaks to some
+ * include files and the like and get things working, making for fast easy
+ * imports of the FreeBSD code into linux.
+ *
+ * I disagree with Dan's approach. Not that I don't think his way of doing
+ * things would be nice, easy to maintain, and create a more uniform driver
+ * between FreeBSD and Linux. I have no objection to those issues. My
+ * disagreement is on the needed functionality. There simply are certain
+ * things that are done differently in FreeBSD than linux that will cause
+ * problems for this driver regardless of any middle ware Dan implements.
+ * The biggest example of this at the moment is interrupt semantics. Linux
+ * doesn't provide the same protection techniques as FreeBSD does, nor can
+ * they be easily implemented in any middle ware code since they would truly
+ * belong in the kernel proper and would effect all drivers. For the time
+ * being, I see issues such as these as major stumbling blocks to the
+ * reliability of code based upon such middle ware. Therefore, I choose to
+ * use a different approach to importing the FreeBSD code that doesn't
+ * involve any middle ware type code. My approach is to import the sequencer
+ * code from FreeBSD wholesale. Then, to only make changes in the kernel
+ * portion of the driver as they are needed for the new sequencer semantics.
+ * In this way, the portion of the driver that speaks to the rest of the
+ * linux kernel is fairly static and can be changed/modified to solve
+ * any problems one might encounter without concern for the FreeBSD driver.
+ *
+ * Note: If time and experience should prove me wrong that the middle ware
+ * code Dan writes is reliable in its operation, then I'll retract my above
+ * statements. But, for those that don't know, I'm from Missouri (in the US)
+ * and our state motto is "The Show-Me State". Well, before I will put
+ * faith into it, you'll have to show me that it works :)
+ *
+ *_M*************************************************************************/
+
#ifdef MODULE
#include <linux/module.h>
#endif
@@ -103,16 +170,18 @@
#include <stdarg.h>
#include <asm/io.h>
#include <asm/irq.h>
+#include <linux/version.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/ioport.h>
-#include <linux/bios32.h>
#include <linux/delay.h>
#include <linux/sched.h>
#include <linux/pci.h>
#include <linux/proc_fs.h>
#include <linux/blk.h>
+#include <linux/tqueue.h>
+#include <linux/tasks.h>
#include "sd.h"
#include "scsi.h"
#include "hosts.h"
@@ -122,10 +191,11 @@
#include "aic7xxx/scsi_message.h"
#include "aic7xxx_reg.h"
#include "aic7xxx_seq.h"
+
#include <linux/stat.h>
-#include <linux/malloc.h> /* for kmalloc() */
+#include <linux/malloc.h> /* for kmalloc() */
-#include <linux/config.h> /* for CONFIG_PCI */
+#include <linux/config.h> /* for CONFIG_PCI */
/*
* To generate the correct addresses for the controller to issue
@@ -139,13 +209,13 @@ struct proc_dir_entry proc_scsi_aic7xxx = {
0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL
};
-#define AIC7XXX_C_VERSION "$Revision: 4.1 $"
+#define AIC7XXX_C_VERSION "5.0.13"
#define NUMBER(arr) (sizeof(arr) / sizeof(arr[0]))
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
#define MAX(a,b) (((a) > (b)) ? (a) : (b))
#define ALL_TARGETS -1
-#define ALL_CHANNELS '\0'
+#define ALL_CHANNELS -1
#define ALL_LUNS -1
#define MAX_TARGETS 16
#define MAX_LUNS 8
@@ -156,75 +226,78 @@ struct proc_dir_entry proc_scsi_aic7xxx = {
# define FALSE 0
#endif
+#ifndef KERNEL_VERSION
+# define KERNEL_VERSION(x,y,z) (((x)<<16)+((y)<<8)+(z))
+#endif
+
/*
- * Defines for PCI bus support, testing twin bus support, DMAing of
- * SCBs, tagged queueing, commands (SCBs) per lun, and SCSI bus reset
- * delay time.
- *
- * o PCI bus support - this has been implemented and working since
- * the December 1, 1994 release of this driver. If you don't have
- * a PCI bus, then you can configure your kernel without PCI
- * support because all PCI dependent code is bracketed with
- * "#ifdef CONFIG_PCI ... #endif CONFIG_PCI".
- *
- * o Twin bus support - this has been tested and does work. It is
- * not an option anymore.
- *
- * o Tagged queueing - this driver is capable of tagged queueing
- * but I am unsure as to how well the higher level driver implements
- * tagged queueing. Therefore, the maximum commands per lun is
- * set to 2. If you want to implement tagged queueing, ensure
- * this define is not commented out.
- *
- * o Commands per lun - If tagged queueing is enabled, then you
- * may want to try increasing AIC7XXX_CMDS_PER_LUN to more
- * than 2. By default, we limit the SCBs per LUN to 2 with
- * or without tagged queueing enabled. If tagged queueing is
- * disabled, the sequencer will keep the 2nd SCB in the input
- * queue until the first one completes - so it is OK to to have
- * more than 1 SCB queued. If tagged queueing is enabled, then
- * the sequencer will attempt to send the 2nd SCB to the device
- * while the first SCB is executing and the device is disconnected.
- * For adapters limited to 4 SCBs, you may want to actually
- * decrease the commands per LUN to 1, if you often have more
- * than 2 devices active at the same time. This will allocate
- * 1 SCB for each device and ensure that there will always be
- * a free SCB for up to 4 devices active at the same time.
- * When SCB paging is enabled, set the commands per LUN to 8
- * or higher (see SCB paging support below). Note that if
- * AIC7XXX_CMDS_PER_LUN is not defined and tagged queueing is
- * enabled, the driver will attempt to set the commands per
- * LUN using its own heuristic based on the number of available
- * SCBs.
- *
- * o 3985 support - The 3985 adapter is much like the 3940, but has
- * three 7870 controllers as opposed to two for the 3940. It will
- * be probed and recognized as three different adapters, but all
- * three controllers can share the same external bank of 255 SCBs.
- * If you enable AIC7XXX_USE_EXT_SCBRAM, then the driver will attempt
- * to use and share the common bank of SCBs between the three
- * controllers of the 3985. This is experimental and hasn't been
- * been tested. By default, we do not use external SCB RAM, and
- * force the controllers to use their own internal bank of 16 SCBs.
- * Please let us know if using the external SCB array works.
- *
- * o SCB paging support - SCB paging is enabled by defining
- * AIC7XXX_PAGE_ENABLE. Support for this was taken from the
- * FreeBSD driver (by Justin Gibbs) and allows for up to 255
- * active SCBs. This will increase performance when tagged
- * queueing is enabled. Note that you should increase the
- * AIC7XXX_CMDS_PER_LUN to 8 as most tagged queueing devices
- * allow at least this many.
- *
- * Note that sharing of IRQs is not an option any longer. Linux supports
- * it so we support it.
- *
- * Daniel M. Eischen, deischen@iworks.InterWorks.org, 01/26/96
+ * We need the bios32.h file if we are kernel version 2.1.92 or less. The
+ * full set of pci_* changes wasn't in place until 2.1.93
*/
-/* Uncomment this for tagged queueing. */
-#ifdef CONFIG_AIC7XXX_TAGGED_QUEUEING
-#define AIC7XXX_TAGGED_QUEUEING
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,1,92)
+# if defined(__sparc_v9__) || defined(__powerpc__)
+# error "PPC and Sparc platforms are only support under 2.1.x and above"
+# endif
+# include <linux/bios32.h>
+#endif
+
+#if !defined(__alpha__)
+# define MMAPIO
+#endif
+
+#if defined(__powerpc__)
+# ifdef mb
+# undef mb
+# endif
+# define mb() \
+ __asm__ __volatile__("eieio" ::: "memory")
+#elif defined(__i386__)
+# ifdef mb
+# undef mb
+# endif
+# define mb() \
+ __asm__ __volatile__("lock ; addl $0,0(%%esp)": : :"memory")
+#elif defined(__alpha__)
+# ifdef mb
+# undef mb
+# endif
+# define mb() \
+ __asm__ __volatile__("mb": : :"memory")
+#endif
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,0)
+# include <asm/spinlock.h>
+# include <linux/smp.h>
+# define cpuid smp_processor_id()
+# if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+# define DRIVER_LOCK_INIT \
+ spin_lock_init(&p->spin_lock);
+# define DRIVER_LOCK \
+ if(!p->cpu_lock_count[cpuid]) { \
+ spin_lock_irqsave(&p->spin_lock, cpu_flags); \
+ p->cpu_lock_count[cpuid]++; \
+ } else { \
+ p->cpu_lock_count[cpuid]++; \
+ }
+# define DRIVER_UNLOCK \
+ if(--p->cpu_lock_count[cpuid] == 0) \
+ spin_unlock_irqrestore(&p->spin_lock, cpu_flags);
+# else
+# define DRIVER_LOCK_INIT
+# define DRIVER_LOCK
+# define DRIVER_UNLOCK
+# endif
+#else
+# define cpuid 0
+# define DRIVER_LOCK_INIT
+# define DRIVER_LOCK \
+ save_flags(cpu_flags); \
+ cli();
+# define DRIVER_UNLOCK \
+ restore_flags(cpu_flags);
+# define le32_to_cpu(x) (x)
+# define cpu_to_le32(x) (x)
#endif
/*
@@ -239,7 +312,7 @@ struct proc_dir_entry proc_scsi_aic7xxx = {
#ifdef CONFIG_AIC7XXX_RESET_DELAY
#define AIC7XXX_RESET_DELAY CONFIG_AIC7XXX_RESET_DELAY
#else
-#define AIC7XXX_RESET_DELAY 15
+#define AIC7XXX_RESET_DELAY 5
#endif
/*
@@ -253,32 +326,18 @@ struct proc_dir_entry proc_scsi_aic7xxx = {
#endif
/*
- * Enable SCB paging.
- */
-#ifdef CONFIG_AIC7XXX_PAGE_ENABLE
-#define AIC7XXX_PAGE_ENABLE
-#endif
-
-/*
- * Uncomment the following to enable use of the external bank
- * of 255 SCBs. For 3985 adapters, this will also enable sharing
- * of the SCB array across all three controllers.
- */
-#ifdef CONFIG_AIC7XXX_USE_EXT_SCBRAM
-#define AIC7XXX_USE_EXT_SCBRAM
-#endif
-
-/*
- * For debugging the abort/reset code.
- */
-#define AIC7XXX_DEBUG_ABORT
-
-/*
- * For general debug messages
- */
-#define AIC7XXX_DEBUG
-
-/*
+ * NOTE: Uncommenting the define below no longer has any effect, the
+ * tagged queue value array is always active now. I've added
+ * a setup option to set this particular array and I'm hoping
+ * insmod will be smart enough to set it properly as well. It's
+ * by use of this array that a person can disable tagged queueing.
+ * The DEFAULT_TAG_COMMANDS define has been changed to disable
+ * tagged queueing by default, so if your devices can handle tagged
+ * queueing you will need to add a line to their lilo.conf file like:
+ * append="aic7xxx=verbose,tag_info:{{32,32,32,32},{32,32,32,32}}"
+ * which will result in the first four devices on the first two
+ * controllers being set to a tagged queue depth of 32.
+ *
* Set this for defining the number of tagged commands on a device
* by device, and controller by controller basis. The first set
* of tagged commands will be used for the first detected aic7xxx
@@ -293,37 +352,36 @@ struct proc_dir_entry proc_scsi_aic7xxx = {
*
* When AIC7XXX_CMDS_PER_LUN is not defined, the driver will use its
* own algorithm to determine the commands/LUN. If SCB paging is
- * enabled, the commands/LUN is 8. When SCB paging is not enabled,
- * then commands/LUN is 8 for adapters with 16 or more hardware SCBs
- * and 4 commands/LUN for adapters with 3 or 4 SCBs.
- *
+ * enabled, which is always now, the default is 8 commands per lun
+ * that indicates it supports tagged queueing. All non-tagged devices
+ * use an internal queue depth of 3, with no more than one of those
+ * three commands active at one time.
*/
/* #define AIC7XXX_TAGGED_QUEUEING_BY_DEVICE */
-#ifdef AIC7XXX_TAGGED_QUEUEING_BY_DEVICE
typedef struct
{
- unsigned char tag_commands[16]; /* Allow for wide/twin channel adapters. */
+ unsigned char tag_commands[16]; /* Allow for wide/twin adapters. */
} adapter_tag_info_t;
/*
- * Make a define that will tell the driver to use it's own algorithm
- * for determining commands/LUN (see Determining commands per LUN
- * above).
+ * Make a define that will tell the driver not to use tagged queueing
+ * by default.
*/
-#define DEFAULT_TAG_COMMANDS {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+#define DEFAULT_TAG_COMMANDS {255, 255, 255, 255, 255, 255, 255, 255,\
+ 255, 255, 255, 255, 255, 255, 255, 255}
/*
* Modify this as you see fit for your system. By setting tag_commands
* to 0, the driver will use it's own algorithm for determining the
- * number of commands to use (see above). When -1, the driver will
+ * number of commands to use (see above). When 255, the driver will
* not enable tagged queueing for that particular device. When positive
- * (> 0) the values in the array are used for the queue_depth. Note
- * that the maximum value for an entry is 127.
+ * (> 0) and (< 255) the values in the array are used for the queue_depth.
+ * Note that the maximum value for an entry is 254, but you're insane if
+ * you try to use that many commands on one device.
*
- * In this example, the first line will enable tagged queueing for all
- * the devices on the first probed aic7xxx adapter and tells the driver
- * to use it's own algorithm for determining commands/LUN.
+ * In this example, the first line will disable tagged queueing for all
+ * the devices on the first probed aic7xxx adapter.
*
* The second line enables tagged queueing with 4 commands/LUN for IDs
* (1, 2-11, 13-15), disables tagged queueing for ID 12, and tells the
@@ -336,107 +394,42 @@ typedef struct
* for IDs 1 and 4, 127 commands/LUN for ID 8, and 4 commands/LUN for
* IDs 2, 5-7, and 9-15.
*/
+
+/*
adapter_tag_info_t aic7xxx_tag_info[] =
{
{DEFAULT_TAG_COMMANDS},
- {{4, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, -1, 4, 4, 4}},
+ {{4, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 255, 4, 4, 4}},
{DEFAULT_TAG_COMMANDS},
- {{-1, 16, 4, -1, 16, 4, 4, 4, 127, 4, 4, 4, 4, 4, 4, 4}}
+ {{255, 16, 4, 255, 16, 4, 4, 4, 127, 4, 4, 4, 4, 4, 4, 4}}
};
-#endif
-
-/*
- * Don't define this unless you have problems with the driver
- * interrupt handler. The old method would register the drivers
- * interrupt handler as a "fast" type interrupt handler that would
- * lock out other interrupts. Since this driver can spend a lot
- * of time in the interrupt handler, this is _not_ a good idea.
- * It also conflicts with some of the more common ethernet drivers
- * that don't use fast interrupts. Currently, Linux does not allow
- * IRQ sharing unless both drivers can agree on the type of interrupt
- * handler.
- */
-/* #define AIC7XXX_OLD_ISR_TYPE */
-
-
-/*
- * Controller type and options
- */
-typedef enum {
- AIC_NONE,
- AIC_7770, /* EISA aic7770 on motherboard */
- AIC_7771, /* EISA aic7771 on 274x */
- AIC_284x, /* VLB aic7770 on 284x, BIOS disabled */
- AIC_7850, /* PCI aic7850 */
- AIC_7855, /* PCI aic7855 */
- AIC_7860, /* PCI aic7860 (7850 Ultra) */
- AIC_7861, /* PCI aic7861 on 2940AU */
- AIC_7870, /* PCI aic7870 on motherboard */
- AIC_7871, /* PCI aic7871 on 294x */
- AIC_7872, /* PCI aic7872 on 3940 */
- AIC_7873, /* PCI aic7873 on 3985 */
- AIC_7874, /* PCI aic7874 on 294x Differential */
- AIC_7880, /* PCI aic7880 on motherboard */
- AIC_7881, /* PCI aic7881 on 294x Ultra */
- AIC_7882, /* PCI aic7882 on 3940 Ultra */
- AIC_7883, /* PCI aic7883 on 3985 Ultra */
- AIC_7884 /* PCI aic7884 on 294x Ultra Differential */
-} aha_chip_type;
-
-typedef enum {
- AIC_777x, /* AIC-7770 based */
- AIC_785x, /* AIC-7850 based (3 SCBs)*/
- AIC_786x, /* AIC-7860 based (7850 ultra) */
- AIC_787x, /* AIC-7870 based */
- AIC_788x /* AIC-7880 based (ultra) */
-} aha_chip_class_type;
-
-typedef enum {
- AIC_SINGLE, /* Single Channel */
- AIC_TWIN, /* Twin Channel */
- AIC_WIDE /* Wide Channel */
-} aha_bus_type;
-
-typedef enum {
- AIC_UNKNOWN,
- AIC_ENABLED,
- AIC_DISABLED
-} aha_status_type;
-
-typedef enum {
- LIST_HEAD,
- LIST_SECOND
-} insert_type;
-
-typedef enum {
- ABORT_RESET_INACTIVE,
- ABORT_RESET_PENDING,
- ABORT_RESET_SUCCESS
-} aha_abort_reset_type;
+*/
/*
* Define an array of board names that can be indexed by aha_type.
* Don't forget to change this when changing the types!
*/
static const char *board_names[] = {
- "AIC-7xxx Unknown", /* AIC_NONE */
- "Adaptec AIC-7770 SCSI host adapter", /* AIC_7770 */
- "Adaptec AHA-274X SCSI host adapter", /* AIC_7771 */
- "Adaptec AHA-284X SCSI host adapter", /* AIC_284x */
- "Adaptec AIC-7850 SCSI host adapter", /* AIC_7850 */
- "Adaptec AIC-7855 SCSI host adapter", /* AIC_7855 */
- "Adaptec AIC-7860 Ultra SCSI host adapter", /* AIC_7860 */
- "Adaptec AHA-2940A Ultra SCSI host adapter", /* AIC_7861 */
- "Adaptec AIC-7870 SCSI host adapter", /* AIC_7870 */
- "Adaptec AHA-294X SCSI host adapter", /* AIC_7871 */
- "Adaptec AHA-394X SCSI host adapter", /* AIC_7872 */
- "Adaptec AHA-398X SCSI host adapter", /* AIC_7873 */
- "Adaptec AHA-2944 SCSI host adapter", /* AIC_7874 */
- "Adaptec AIC-7880 Ultra SCSI host adapter", /* AIC_7880 */
- "Adaptec AHA-294X Ultra SCSI host adapter", /* AIC_7881 */
- "Adaptec AHA-394X Ultra SCSI host adapter", /* AIC_7882 */
- "Adaptec AHA-398X Ultra SCSI host adapter", /* AIC_7883 */
- "Adaptec AHA-2944 Ultra SCSI host adapter" /* AIC_7884 */
+ "AIC-7xxx Unknown", /* AIC_NONE */
+ "Adaptec AIC-7810 Hardware RAID Controller", /* AIC_7810 */
+ "Adaptec AIC-7770 SCSI host adapter", /* AIC_7770 */
+ "Adaptec AHA-274X SCSI host adapter", /* AIC_7771 */
+ "Adaptec AHA-284X SCSI host adapter", /* AIC_284x */
+ "Adaptec AIC-7850 SCSI host adapter", /* AIC_7850 */
+ "Adaptec AIC-7855 SCSI host adapter", /* AIC_7855 */
+ "Adaptec AIC-7860 Ultra SCSI host adapter", /* AIC_7860 */
+ "Adaptec AHA-2940A Ultra SCSI host adapter", /* AIC_7861 */
+ "Adaptec AIC-7870 SCSI host adapter", /* AIC_7870 */
+ "Adaptec AHA-294X SCSI host adapter", /* AIC_7871 */
+ "Adaptec AHA-394X SCSI host adapter", /* AIC_7872 */
+ "Adaptec AHA-398X SCSI host adapter", /* AIC_7873 */
+ "Adaptec AHA-2944 SCSI host adapter", /* AIC_7874 */
+ "Adaptec AIC-7880 Ultra SCSI host adapter", /* AIC_7880 */
+ "Adaptec AHA-294X Ultra SCSI host adapter", /* AIC_7881 */
+ "Adaptec AHA-394X Ultra SCSI host adapter", /* AIC_7882 */
+ "Adaptec AHA-398X Ultra SCSI host adapter", /* AIC_7883 */
+ "Adaptec AHA-2944 Ultra SCSI host adapter", /* AIC_7884 */
+ "Adaptec AIC-7895 Ultra SCSI host adapter" /* AIC_7895 */
};
/*
@@ -461,58 +454,58 @@ static const char *board_names[] = {
#define DID_RETRY_COMMAND DID_ERROR
#define HSCSIID 0x07
-#define HWSCSIID 0x0F
#define SCSI_RESET 0x040
/*
* EISA/VL-bus stuff
*/
-#define MINSLOT 1
-#define MAXSLOT 15
-#define SLOTBASE(x) ((x) << 12)
+#define MINSLOT 1
+#define MAXSLOT 15
+#define SLOTBASE(x) ((x) << 12)
#define BASE_TO_SLOT(x) ((x) >> 12)
/*
* Standard EISA Host ID regs (Offset from slot base)
*/
-#define HID0 0x80 /* 0,1: msb of ID2, 2-7: ID1 */
-#define HID1 0x81 /* 0-4: ID3, 5-7: LSB ID2 */
-#define HID2 0x82 /* product */
-#define HID3 0x83 /* firmware revision */
+#define HID0 0x80 /* 0,1: msb of ID2, 2-7: ID1 */
+#define HID1 0x81 /* 0-4: ID3, 5-7: LSB ID2 */
+#define HID2 0x82 /* product */
+#define HID3 0x83 /* firmware revision */
/*
* AIC-7770 I/O range to reserve for a card
*/
-#define MINREG 0xC00
-#define MAXREG 0xCBF
+#define MINREG 0xC00
+#define MAXREG 0xCBF
-#define INTDEF 0x5C /* Interrupt Definition Register */
+#define INTDEF 0x5C /* Interrupt Definition Register */
/*
* AIC-78X0 PCI registers
*/
-#define CLASS_PROGIF_REVID 0x08
-#define DEVREVID 0x000000FFul
-#define PROGINFC 0x0000FF00ul
-#define SUBCLASS 0x00FF0000ul
-#define BASECLASS 0xFF000000ul
-
-#define CSIZE_LATTIME 0x0C
-#define CACHESIZE 0x0000003Ful /* only 5 bits */
-#define LATTIME 0x0000FF00ul
-
-#define DEVCONFIG 0x40
-#define MPORTMODE 0x00000400ul /* aic7870 only */
-#define RAMPSM 0x00000200ul /* aic7870 only */
-#define VOLSENSE 0x00000100ul
-#define SCBRAMSEL 0x00000080ul
-#define MRDCEN 0x00000040ul
-#define EXTSCBTIME 0x00000020ul /* aic7870 only */
-#define EXTSCBPEN 0x00000010ul /* aic7870 only */
-#define BERREN 0x00000008ul
-#define DACEN 0x00000004ul
-#define STPWLEVEL 0x00000002ul
-#define DIFACTNEGEN 0x00000001ul /* aic7870 only */
+#define CLASS_PROGIF_REVID 0x08
+#define DEVREVID 0x000000FFul
+#define PROGINFC 0x0000FF00ul
+#define SUBCLASS 0x00FF0000ul
+#define BASECLASS 0xFF000000ul
+
+#define CSIZE_LATTIME 0x0C
+#define CACHESIZE 0x0000003Ful /* only 5 bits */
+#define LATTIME 0x0000FF00ul
+
+#define DEVCONFIG 0x40
+#define SCBSIZE32 0x00010400ul /* aic789X only */
+#define MPORTMODE 0x00000400ul /* aic7870 only */
+#define RAMPSM 0x00000200ul /* aic7870 only */
+#define VOLSENSE 0x00000100ul
+#define SCBRAMSEL 0x00000080ul
+#define MRDCEN 0x00000040ul
+#define EXTSCBTIME 0x00000020ul /* aic7870 only */
+#define EXTSCBPEN 0x00000010ul /* aic7870 only */
+#define BERREN 0x00000008ul
+#define DACEN 0x00000004ul
+#define STPWLEVEL 0x00000002ul
+#define DIFACTNEGEN 0x00000001ul /* aic7870 only */
/*
@@ -536,69 +529,72 @@ struct seeprom_config {
/*
* SCSI ID Configuration Flags
*/
-#define CFXFER 0x0007 /* synchronous transfer rate */
-#define CFSYNCH 0x0008 /* enable synchronous transfer */
-#define CFDISC 0x0010 /* enable disconnection */
-#define CFWIDEB 0x0020 /* wide bus device (wide card) */
-/* UNUSED 0x00C0 */
-#define CFSTART 0x0100 /* send start unit SCSI command */
-#define CFINCBIOS 0x0200 /* include in BIOS scan */
-#define CFRNFOUND 0x0400 /* report even if not found */
-/* UNUSED 0xF800 */
- unsigned short device_flags[16]; /* words 0-15 */
+#define CFXFER 0x0007 /* synchronous transfer rate */
+#define CFSYNCH 0x0008 /* enable synchronous transfer */
+#define CFDISC 0x0010 /* enable disconnection */
+#define CFWIDEB 0x0020 /* wide bus device (wide card) */
+#define CFSYNCHISULTRA 0x0040 /* CFSYNC is an ultra offset */
+/* UNUSED 0x0080 */
+#define CFSTART 0x0100 /* send start unit SCSI command */
+#define CFINCBIOS 0x0200 /* include in BIOS scan */
+#define CFRNFOUND 0x0400 /* report even if not found */
+#define CFMULTILUN 0x0800 /* probe mult luns in BIOS scan */
+/* UNUSED 0xF000 */
+ unsigned short device_flags[16]; /* words 0-15 */
/*
* BIOS Control Bits
*/
-#define CFSUPREM 0x0001 /* support all removable drives */
-#define CFSUPREMB 0x0002 /* support removable drives for boot only */
-#define CFBIOSEN 0x0004 /* BIOS enabled */
-/* UNUSED 0x0008 */
-#define CFSM2DRV 0x0010 /* support more than two drives */
-#define CF284XEXTEND 0x0020 /* extended translation (284x cards) */
-/* UNUSED 0x0040 */
-#define CFEXTEND 0x0080 /* extended translation enabled */
-/* UNUSED 0xFF00 */
- unsigned short bios_control; /* word 16 */
+#define CFSUPREM 0x0001 /* support all removable drives */
+#define CFSUPREMB 0x0002 /* support removable drives for boot only */
+#define CFBIOSEN 0x0004 /* BIOS enabled */
+/* UNUSED 0x0008 */
+#define CFSM2DRV 0x0010 /* support more than two drives */
+#define CF284XEXTEND 0x0020 /* extended translation (284x cards) */
+/* UNUSED 0x0040 */
+#define CFEXTEND 0x0080 /* extended translation enabled */
+/* UNUSED 0xFF00 */
+ unsigned short bios_control; /* word 16 */
/*
* Host Adapter Control Bits
*/
-#define CFAUTOTERM 0x0001 /* Perform Auto termination */
-#define CFULTRAEN 0x0002 /* Ultra SCSI speed enable (Ultra cards) */
-#define CF284XSELTO 0x0003 /* Selection timeout (284x cards) */
-#define CF284XFIFO 0x000C /* FIFO Threshold (284x cards) */
-#define CFSTERM 0x0004 /* SCSI low byte termination */
-#define CFWSTERM 0x0008 /* SCSI high byte termination (wide card) */
-#define CFSPARITY 0x0010 /* SCSI parity */
-#define CF284XSTERM 0x0020 /* SCSI low byte termination (284x cards) */
-#define CFRESETB 0x0040 /* reset SCSI bus at boot */
-/* UNUSED 0xFF80 */
- unsigned short adapter_control; /* word 17 */
+#define CFAUTOTERM 0x0001 /* Perform Auto termination */
+#define CFULTRAEN 0x0002 /* Ultra SCSI speed enable (Ultra cards) */
+#define CF284XSELTO 0x0003 /* Selection timeout (284x cards) */
+#define CF284XFIFO 0x000C /* FIFO Threshold (284x cards) */
+#define CFSTERM 0x0004 /* SCSI low byte termination */
+#define CFWSTERM 0x0008 /* SCSI high byte termination (wide card) */
+#define CFSPARITY 0x0010 /* SCSI parity */
+#define CF284XSTERM 0x0020 /* SCSI low byte termination (284x cards) */
+#define CFRESETB 0x0040 /* reset SCSI bus at boot */
+#define CFBPRIMARY 0x0100 /* Channel B primary on 7895 chipsets */
+/* UNUSED 0xFE80 */
+ unsigned short adapter_control; /* word 17 */
/*
* Bus Release, Host Adapter ID
*/
-#define CFSCSIID 0x000F /* host adapter SCSI ID */
-/* UNUSED 0x00F0 */
-#define CFBRTIME 0xFF00 /* bus release time */
- unsigned short brtime_id; /* word 18 */
+#define CFSCSIID 0x000F /* host adapter SCSI ID */
+/* UNUSED 0x00F0 */
+#define CFBRTIME 0xFF00 /* bus release time */
+ unsigned short brtime_id; /* word 18 */
/*
* Maximum targets
*/
-#define CFMAXTARG 0x00FF /* maximum targets */
-/* UNUSED 0xFF00 */
- unsigned short max_targets; /* word 19 */
+#define CFMAXTARG 0x00FF /* maximum targets */
+/* UNUSED 0xFF00 */
+ unsigned short max_targets; /* word 19 */
- unsigned short res_1[11]; /* words 20-30 */
- unsigned short checksum; /* word 31 */
+ unsigned short res_1[11]; /* words 20-30 */
+ unsigned short checksum; /* word 31 */
};
-#define SELBUS_MASK 0x0a
-#define SELNARROW 0x00
-#define SELBUSB 0x08
-#define SINGLE_BUS 0x00
+#define SELBUS_MASK 0x0a
+#define SELNARROW 0x00
+#define SELBUSB 0x08
+#define SINGLE_BUS 0x00
#define SCB_TARGET(scb) \
(((scb)->hscb->target_channel_lun & TID) >> 4)
@@ -613,60 +609,22 @@ struct seeprom_config {
* condition in this location. This then will modify a DID_OK status
* into an appropriate error for the higher-level SCSI code.
*/
-#define aic7xxx_error(cmd) ((cmd)->SCp.Status)
+#define aic7xxx_error(cmd) ((cmd)->SCp.Status)
/*
* Keep track of the targets returned status.
*/
-#define aic7xxx_status(cmd) ((cmd)->SCp.sent_command)
+#define aic7xxx_status(cmd) ((cmd)->SCp.sent_command)
/*
* The position of the SCSI commands scb within the scb array.
*/
-#define aic7xxx_position(cmd) ((cmd)->SCp.have_data_in)
+#define aic7xxx_position(cmd) ((cmd)->SCp.have_data_in)
/*
- * "Static" structures. Note that these are NOT initialized
- * to zero inside the kernel - we have to initialize them all
- * explicitly.
- *
- * We support multiple adapter cards per interrupt, but keep a
- * linked list of Scsi_Host structures for each IRQ. On an interrupt,
- * use the IRQ as an index into aic7xxx_boards[] to locate the card
- * information.
+ * So we can keep track of our host structs
*/
-static struct Scsi_Host *aic7xxx_boards[NR_IRQS + 1];
-
-/*
- * When we detect and register the card, it is possible to
- * have the card raise a spurious interrupt. Because we need
- * to support multiple cards, we cannot tell which card caused
- * the spurious interrupt. And, we might not even have added
- * the card info to the linked list at the time the spurious
- * interrupt gets raised. This variable is suppose to keep track
- * of when we are registering a card and how many spurious
- * interrupts we have encountered.
- *
- * 0 - do not allow spurious interrupts.
- * 1 - allow 1 spurious interrupt
- * 2 - have 1 spurious interrupt, do not allow any more.
- *
- * I've made it an integer instead of a boolean in case we
- * want to allow more than one spurious interrupt for debugging
- * purposes. Otherwise, it could just go from true to false to
- * true (or something like that).
- *
- * When the driver detects the cards, we'll set the count to 1
- * for each card detection and registration. After the registration
- * of a card completes, we'll set the count back to 0. So far, it
- * seems to be enough to allow a spurious interrupt only during
- * card registration; if a spurious interrupt is going to occur,
- * this is where it happens.
- *
- * We should be able to find a way to avoid getting the spurious
- * interrupt. But until we do, we have to keep this ugly code.
- */
-static int aic7xxx_spurious_count;
+static struct aic7xxx_host *first_aic7xxx = NULL;
/*
* As of Linux 2.1, the mid-level SCSI code uses virtual addresses
@@ -681,14 +639,14 @@ struct hw_scatterlist {
/*
* Maximum number of SG segments these cards can support.
*/
-#define AIC7XXX_MAX_SG 27
+#define AIC7XXX_MAX_SG 128
/*
* The maximum number of SCBs we could have for ANY type
* of card. DON'T FORGET TO CHANGE THE SCB MASK IN THE
* SEQUENCER CODE IF THIS IS MODIFIED!
*/
-#define AIC7XXX_MAXSCB 255
+#define AIC7XXX_MAXSCB 255
struct aic7xxx_hwscb {
@@ -704,53 +662,118 @@ struct aic7xxx_hwscb {
/*16*/ unsigned int data_count;
/*20*/ unsigned int SCSI_cmd_pointer;
/*24*/ unsigned char SCSI_cmd_length;
-/*25*/ u_char tag; /* Index into our kernel SCB array.
- * Also used as the tag for tagged I/O
- */
-#define SCB_PIO_TRANSFER_SIZE 26 /* amount we need to upload/download
- * via PIO to initialize a transaction.
- */
-/*26*/ unsigned char next; /* Used to thread SCBs awaiting selection
- * or disconnected down in the sequencer.
- */
+/*25*/ unsigned char tag; /* Index into our kernel SCB array.
+ * Also used as the tag for tagged I/O
+ */
+#define SCB_PIO_TRANSFER_SIZE 26 /* amount we need to upload/download
+ * via PIO to initialize a transaction.
+ */
+/*26*/ unsigned char next; /* Used to thread SCBs awaiting selection
+ * or disconnected down in the sequencer.
+ */
/*27*/ unsigned char prev;
-/*28*/ unsigned int pad; /*
- * Unused by the kernel, but we require
- * the padding so that the array of
- * hardware SCBs is alligned on 32 byte
- * boundaries so the sequencer can index
- */
+/*28*/ unsigned int pad; /*
+ * Unused by the kernel, but we require
+ * the padding so that the array of
+ * hardware SCBs is alligned on 32 byte
+ * boundaries so the sequencer can index
+ */
};
typedef enum {
- SCB_FREE = 0x0000,
- SCB_ACTIVE = 0x0001,
- SCB_ABORTED = 0x0002,
- SCB_DEVICE_RESET = 0x0004,
- SCB_SENSE = 0x0008,
- SCB_TIMEDOUT = 0x0010,
- SCB_QUEUED_FOR_DONE = 0x0020,
- SCB_RECOVERY_SCB = 0x0040,
- SCB_WAITINGQ = 0x0080,
- SCB_ASSIGNEDQ = 0x0100,
- SCB_SENTORDEREDTAG = 0x0200,
- SCB_MSGOUT_SDTR = 0x0400,
- SCB_MSGOUT_WDTR = 0x0800,
- SCB_ABORT = 0x1000,
- SCB_QUEUED_ABORT = 0x2000
+ SCB_FREE = 0x0000,
+ SCB_WDTR_16BIT = 0x0001,
+ SCB_WAITINGQ = 0x0002,
+ SCB_ACTIVE = 0x0004,
+ SCB_SENSE = 0x0008,
+ SCB_ABORT = 0x0010,
+ SCB_DEVICE_RESET = 0x0020,
+ SCB_RESET = 0x0040,
+ SCB_RECOVERY_SCB = 0x0080,
+ SCB_WAS_BUSY = 0x0100,
+ SCB_MSGOUT_SDTR = 0x0400,
+ SCB_MSGOUT_WDTR = 0x0800,
+ SCB_MSGOUT_WDTR_8BIT = 0x0800,
+ SCB_MSGOUT_WDTR_16BIT = 0x0801,
+ SCB_MSGOUT_BITS = SCB_MSGOUT_SDTR | SCB_MSGOUT_WDTR_16BIT,
+ SCB_QUEUED_ABORT = 0x1000,
+ SCB_QUEUED_FOR_DONE = 0x2000
} scb_flag_type;
+typedef enum {
+ AHC_FNONE = 0x00000000,
+ AHC_PAGESCBS = 0x00000001,
+ AHC_CHANNEL_B_PRIMARY = 0x00000002,
+ AHC_USEDEFAULTS = 0x00000004,
+ AHC_INDIRECT_PAGING = 0x00000008,
+ AHC_CHNLB = 0x00000020,
+ AHC_CHNLC = 0x00000040,
+ AHC_EXTEND_TRANS_A = 0x00000100,
+ AHC_EXTEND_TRANS_B = 0x00000200,
+ AHC_TERM_ENB_A = 0x00000400,
+ AHC_TERM_ENB_B = 0x00000800,
+ AHC_HANDLING_REQINITS = 0x00001000,
+ AHC_TARGETMODE = 0x00002000,
+ AHC_NEWEEPROM_FMT = 0x00004000,
+ /*
+ * Here ends the FreeBSD defined flags and here begins the linux defined
+ * flags. NOTE: I did not preserve the old flag name during this change
+ * specifically to force me to evaluate what flags were being used properly
+ * and what flags weren't. This way, I could clean up the flag usage on
+ * a use by use basis. Doug Ledford
+ */
+ AHC_A_SCANNED = 0x00100000,
+ AHC_B_SCANNED = 0x00200000,
+ AHC_MULTI_CHANNEL = 0x00400000,
+ AHC_BIOS_ENABLED = 0x00800000,
+ AHC_ABORT_PENDING = 0x02000000,
+ AHC_RESET_PENDING = 0x04000000,
+ AHC_IN_ISR = 0x10000000,
+ AHC_IN_ABORT = 0x20000000,
+ AHC_IN_RESET = 0x40000000
+} ahc_flag_type;
+
+typedef enum {
+ AHC_NONE = 0x00000000,
+ AHC_ULTRA = 0x00000001,
+ AHC_WIDE = 0x00000002,
+ AHC_TWIN = 0x00000008,
+ AHC_AIC7770 = 0x00000010,
+ AHC_AIC7850 = 0x00000020,
+ AHC_AIC7860 = 0x00000021,
+ AHC_AIC7870 = 0x00000040,
+ AHC_AIC7880 = 0x00000041,
+ AHC_AIC7895 = 0x00000081,
+ AHC_AIC78x0 = 0x000000E0,
+ AHC_274 = 0x00000110,
+ AHC_284 = 0x00000210,
+ AHC_294AU = 0x00000421,
+ AHC_294 = 0x00000440,
+ AHC_294U = 0x00000441,
+ AHC_394 = 0x00000840,
+ AHC_394U = 0x00000841,
+ AHC_394AU = 0x00000881,
+ AHC_398 = 0x00001040,
+ AHC_398U = 0x00001041,
+ AHC_39x = 0x00001880
+} ahc_type;
+
struct aic7xxx_scb {
struct aic7xxx_hwscb *hscb; /* corresponding hardware scb */
- Scsi_Cmnd *cmd; /* Scsi_Cmnd for this scb */
+ Scsi_Cmnd *cmd; /* Scsi_Cmnd for this scb */
struct aic7xxx_scb *q_next; /* next scb in queue */
- scb_flag_type flags; /* current state of scb */
- struct hw_scatterlist *sg_list; /* SG list in adapter format */
+ scb_flag_type flags; /* current state of scb */
+ struct hw_scatterlist *sg_list; /* SG list in adapter format */
+ unsigned char tag_action;
unsigned char sg_count;
- unsigned char sense_cmd[6]; /*
+ unsigned char sense_cmd[6]; /*
* Allocate 6 characters for
* sense command.
*/
+ unsigned int sg_length; /* We init this during buildscb so we
+ * don't have to calculate anything
+ * during underflow/overflow/stat code
+ */
};
/*
@@ -768,7 +791,7 @@ static struct {
{ ILLHADDR, "Illegal Host Access" },
{ ILLSADDR, "Illegal Sequencer Address referenced" },
{ ILLOPCODE, "Illegal Opcode in sequencer program" },
- { PARERR, "Sequencer Ram Parity Error" }
+ { SQPARERR, "Sequencer Ram Parity Error" }
};
static unsigned char
@@ -784,58 +807,110 @@ typedef struct {
unsigned char maxhscbs; /* hardware scbs */
unsigned char maxscbs; /* max scbs including pageable scbs */
struct aic7xxx_scb *scb_array[AIC7XXX_MAXSCB];
- unsigned int reserve[100];
} scb_data_type;
+typedef struct {
+ unsigned char period;
+ unsigned char offset;
+} syncinfo_type;
+
/*
- * Define a structure used for each host adapter, only one per IRQ.
+ * Define a structure used for each host adapter. Note, in order to avoid
+ * problems with architectures I can't test on (because I don't have one,
+ * such as the Alpha based systems) which happen to give faults for
+ * non-aligned memory accesses, care was taken to align this structure
+ * in a way that gauranteed all accesses larger than 8 bits were aligned
+ * on the appropriate boundary. It's also organized to try and be more
+ * cache line efficient. Be careful when changing this lest you might hurt
+ * overall performance and bring down the wrath of the masses.
*/
struct aic7xxx_host {
+ /*
+ * This is the first 64 bytes in the host struct
+ */
+
struct Scsi_Host *host; /* pointer to scsi host */
+ struct aic7xxx_host *next; /* allow for multiple IRQs */
int host_no; /* SCSI host number */
- int instance; /* aic7xxx instance number */
- int scsi_id; /* host adapter SCSI ID */
- int scsi_id_b; /* channel B for twin adapters */
- int irq; /* IRQ for this adapter */
- int base; /* card base address */
- unsigned int mbase; /* I/O memory address */
+ unsigned long base; /* card base address */
volatile unsigned char *maddr; /* memory mapped address */
-#define A_SCANNED 0x0001
-#define B_SCANNED 0x0002
-#define EXTENDED_TRANSLATION 0x0004
-#define FLAGS_CHANNEL_B_PRIMARY 0x0008
-#define MULTI_CHANNEL 0x0010
-#define ULTRA_ENABLED 0x0020
-#define PAGE_ENABLED 0x0040
-#define USE_DEFAULTS 0x0080
-#define BIOS_ENABLED 0x0100
-#define IN_ISR 0x0200
-#define IN_TIMEOUT 0x0400
-#define SHARED_SCBDATA 0x0800
-#define HAVE_SEEPROM 0x1000
- unsigned int flags;
- unsigned int isr_count; /* Interrupt count */
- unsigned short needsdtr_copy; /* default config */
- unsigned short needsdtr;
- unsigned short sdtr_pending;
- unsigned short needwdtr_copy; /* default config */
- unsigned short needwdtr;
- unsigned short wdtr_pending;
- unsigned short orderedtag;
- unsigned short discenable; /* Targets allowed to disconnect */
- aha_chip_type chip_type; /* card type */
- aha_chip_class_type chip_class;
- aha_bus_type bus_type; /* normal/twin/wide bus */
- unsigned char chan_num; /* for 39xx, channel number */
+ unsigned long mbase; /* I/O memory address */
+ volatile ahc_flag_type flags;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,0)
+ spinlock_t spin_lock;
+#endif
+ volatile unsigned char cpu_lock_count[NR_CPUS];
+ ahc_type type; /* card type */
+ unsigned long last_reset;
+ unsigned long isr_count; /* Interrupt count */
+ unsigned long spurious_int;
+ unsigned short discenable; /* Targets allowed to disconnect */
+ unsigned short tagenable; /* Targets using tagged I/O */
+ unsigned short orderedtag; /* Ordered Q tags allowed */
+ volatile unsigned char activescbs; /* active scbs */
+ unsigned char max_activescbs;
unsigned char unpause; /* unpause value for HCNTRL */
unsigned char pause; /* pause value for HCNTRL */
- unsigned char qcntmask;
- unsigned char qfullcount;
- unsigned char cmdoutcnt;
- unsigned char curqincnt;
- struct Scsi_Host *next; /* allow for multiple IRQs */
- unsigned char activescbs; /* active scbs */
- scb_queue_type waiting_scbs; /*
+ volatile unsigned char qoutfifonext;
+ volatile unsigned char qinfifonext;
+
+ /*
+ * MAX_TARGETS is currently == 16, so that makes these entries the next
+ * 64 bytes
+ */
+
+#define DEVICE_PRESENT 0x01
+#define BUS_DEVICE_RESET_PENDING 0x02
+#define DEVICE_TIMEOUT 0x04
+#define DEVICE_PRINT_SDTR 0x08
+#define DEVICE_PRINT_WDTR 0x10
+#define DEVICE_SUCCESS 0x20
+#define DEVICE_TAGGED_SUCCESS 0x40
+ volatile unsigned char dev_flags[MAX_TARGETS];
+ volatile unsigned char dev_active_cmds[MAX_TARGETS];
+ unsigned char dev_temp_queue_depth[MAX_TARGETS];
+ unsigned char dev_commands_sent[MAX_TARGETS];
+
+ /*
+ * The next 64....
+ */
+
+ long dev_last_reset[MAX_TARGETS];
+
+ /*
+ * The next 64....
+ */
+
+ unsigned char dev_mid_level_queue_depth[MAX_TARGETS];
+ unsigned char dev_last_queue_full[MAX_TARGETS];
+ unsigned char dev_last_queue_full_count[MAX_TARGETS];
+ unsigned char dev_max_queue_depth[MAX_TARGETS];
+
+ /*
+ * The next 128....
+ */
+
+ volatile scb_queue_type delayed_scbs[MAX_TARGETS];
+
+ /*
+ *
+ */
+
+ struct timer_list dev_timer[MAX_TARGETS];
+
+ /*
+ * The next 64....
+ */
+
+ unsigned char msg_buf[9]; /* The message for the target */
+ unsigned char msg_type;
+#define MSG_TYPE_NONE 0x00
+#define MSG_TYPE_INITIATOR_MSGOUT 0x01
+#define MSG_TYPE_INITIATOR_MSGIN 0x02
+ unsigned char msg_len; /* Length of message */
+ unsigned char msg_index; /* Index into msg_buf array */
+ syncinfo_type syncinfo[MAX_TARGETS];
+ volatile scb_queue_type waiting_scbs; /*
* SCBs waiting for space in
* the QINFIFO.
*/
@@ -845,14 +920,41 @@ struct aic7xxx_host {
Scsi_Cmnd *head;
Scsi_Cmnd *tail;
} completeq;
- struct aic7xxx_device_status {
- long last_reset;
-#define DEVICE_SUCCESS 0x01
-#define BUS_DEVICE_RESET_PENDING 0x02
- int flags;
- int commands_sent;
- int active_cmds;
- } device_status[16];
+
+
+ /*
+ * We put the less frequently used host structure items after the more
+ * frequently used items to try and ease the burden on the cache subsystem.
+ * These entries are not *commonly* accessed, whereas the preceding entries
+ * are accessed very often. The only exceptions are the qinfifo, qoutfifo,
+ * and untagged_scbs array. But, they are often accessed only once and each
+ * access into these arrays is likely to blow a cache line, so they are put
+ * down here so we can minimize the number of cache lines required to hold
+ * the preceeding entries.
+ */
+
+ volatile unsigned char untagged_scbs[256];
+ volatile unsigned char qoutfifo[256];
+ volatile unsigned char qinfifo[256];
+ unsigned short needsdtr;
+ unsigned short sdtr_pending;
+ unsigned short needwdtr;
+ unsigned short wdtr_pending;
+ int instance; /* aic7xxx instance number */
+ int scsi_id; /* host adapter SCSI ID */
+ int scsi_id_b; /* channel B for twin adapters */
+ unsigned int bios_address;
+ int board_name_index;
+ unsigned long reset_start;
+ unsigned short needsdtr_copy; /* default config */
+ unsigned short needwdtr_copy; /* default config */
+ unsigned short ultraenb; /* Ultra mode target list */
+ unsigned short bios_control; /* bios control - SEEPROM */
+ unsigned short adapter_control; /* adapter control - SEEPROM */
+ unsigned char pci_bus;
+ unsigned char pci_device_fn;
+ unsigned char irq; /* IRQ for this adapter */
+
#ifdef AIC7XXX_PROC_STATS
/*
* Statistics Kept:
@@ -864,6 +966,10 @@ struct aic7xxx_host {
* < 512, 512, 1-2K, 2-4K, 4-8K, 8-16K, 16-32K, 32-64K, 64K-128K, > 128K
*
* Total amounts read/written above 512 bytes (amts under ignored)
+ *
+ * NOTE: Enabling this feature is likely to cause a noticeable performance
+ * decrease as the accesses into the stats structures blows apart multiple
+ * cache lines and is CPU time consuming.
*/
struct aic7xxx_xferstats {
long xfers; /* total xfer count */
@@ -885,7 +991,7 @@ struct aic7xxx_host {
static struct {
short period;
/* Rates in Ultra mode have bit 8 of sxfr set */
-#define ULTRA_SXFR 0x100
+#define ULTRA_SXFR 0x100
short rate;
const char *english;
} aic7xxx_syncrates[] = {
@@ -905,55 +1011,34 @@ static struct {
static int num_aic7xxx_syncrates =
sizeof(aic7xxx_syncrates) / sizeof(aic7xxx_syncrates[0]);
-#ifdef CONFIG_PCI
-static int number_of_3940s = 0;
-static int number_of_3985s = 0;
-#endif /* CONFIG_PCI */
-
-#ifdef AIC7XXX_DEBUG
-
-#if 0
-static void
-debug_scb(struct aic7xxx_scb *scb)
-{
- struct aic7xxx_hwscb *hscb = scb->hscb;
-
- printk("scb:%p control:0x%x tcl:0x%x cmdlen:%d cmdpointer:0x%lx\n",
- scb,
- hscb->control,
- hscb->target_channel_lun,
- hscb->SCSI_cmd_length,
- hscb->SCSI_cmd_pointer );
- printk(" datlen:%d data:0x%lx segs:0x%x segp:0x%lx\n",
- hscb->data_count,
- hscb->data_pointer,
- hscb->SG_segment_count,
- hscb->SG_list_pointer);
- printk(" sg_addr:%lx sg_len:%ld\n",
- hscb->sg_list[0].address,
- hscb->sg_list[0].length);
-}
-#endif
-
-#else
-# define debug_scb(x)
-#endif AIC7XXX_DEBUG
-
-#define TCL_OF_SCB(scb) (((scb->hscb)->target_channel_lun >> 4) & 0xf), \
- (((scb->hscb)->target_channel_lun >> 3) & 0x01), \
+#define CTL_OF_SCB(scb) (((scb->hscb)->target_channel_lun >> 3) & 0x1), \
+ (((scb->hscb)->target_channel_lun >> 4) & 0xf), \
((scb->hscb)->target_channel_lun & 0x07)
-#define TC_OF_SCB(scb) (((scb->hscb)->target_channel_lun >> 4) & 0xf), \
- (((scb->hscb)->target_channel_lun >> 3) & 0x01)
-
-#define CHAN_TO_INT(chan) ((chan) == 'A' ? 0 : 1)
+#define CTL_OF_CMD(cmd) ((cmd->channel) & 0x01), \
+ ((cmd->target) & 0x0f), \
+ ((cmd->lun) & 0x07)
#define TARGET_INDEX(cmd) ((cmd)->target | ((cmd)->channel << 3))
/*
+ * A nice little define to make doing our printks a little easier
+ */
+
+#define WARN_LEAD KERN_WARNING "(scsi%d:%d:%d:%d) "
+#define INFO_LEAD KERN_INFO "(scsi%d:%d:%d:%d) "
+
+/*
* XXX - these options apply unilaterally to _all_ 274x/284x/294x
* cards in the system. This should be fixed.
*/
+static int aic7xxx_7895_irq_hack = -1; /* This enables a hack to fix
+ * IRQ settings on buggy 7895
+ * MB controller setups
+ * -1 == Disable this hack
+ * 0 == Use the Channel A IRQ
+ * 1 == Use the Channel B IRQ
+ */
static unsigned int aic7xxx_extended = 0; /* extended translation on? */
static unsigned int aic7xxx_no_reset = 0; /* no resetting of SCSI bus */
static int aic7xxx_irq_trigger = -1; /*
@@ -961,8 +1046,96 @@ static int aic7xxx_irq_trigger = -1; /*
* 0 use edge triggered
* 1 use level triggered
*/
-static int aic7xxx_enable_ultra = 0; /* enable ultra SCSI speeds */
-static int aic7xxx_verbose = 0; /* verbose messages */
+static int aic7xxx_reverse_scan = 0; /*
+ * Set this to anything but 0
+ * to make the probe code
+ * reverse the order of PCI
+ * devices
+ */
+static int aic7xxx_override_term = 0; /*
+ * Set this to non-0 to make the
+ * driver override any BIOS
+ * configured termination
+ * settings based upon the
+ * results of the cable detect
+ * logic. This only applies
+ * to cards that have cable
+ * detection logic and a SEEPROM
+ */
+static int aic7xxx_panic_on_abort = 0; /*
+ * Set this to non-0 in order
+ * to force the driver to panic
+ * the kernel and print out
+ * debugging info on an abort
+ * or reset call into the
+ * driver.
+ */
+
+/*
+ * So that insmod can find the variable and make it point to something
+ */
+#ifdef MODULE
+static char * aic7xxx = NULL;
+
+/*
+ * Just in case someone uses commas to separate items on the insmod
+ * command line, we define a dummy buffer here to avoid having insmod
+ * write wild stuff into our code segment
+ */
+static char dummy_buffer[60] = "Please don't trounce on me insmod!!\n";
+
+#endif
+
+/*
+ * See the comments earlier in the file for what this item is all about
+ * If you have more than 4 controllers, you will need to increase the
+ * the number of items in the array below. Additionally, if you don't
+ * want to have lilo pass a humongous config line to the aic7xxx driver,
+ * then you can get in and manually adjust these instead of leaving them
+ * at the default. Pay attention to the comments earlier in this file
+ * concerning this array if you are going to hand modify these values.
+ */
+static adapter_tag_info_t aic7xxx_tag_info[] =
+{
+ {DEFAULT_TAG_COMMANDS},
+ {DEFAULT_TAG_COMMANDS},
+ {DEFAULT_TAG_COMMANDS},
+ {DEFAULT_TAG_COMMANDS},
+ {DEFAULT_TAG_COMMANDS},
+ {DEFAULT_TAG_COMMANDS},
+ {DEFAULT_TAG_COMMANDS},
+ {DEFAULT_TAG_COMMANDS},
+ {DEFAULT_TAG_COMMANDS},
+ {DEFAULT_TAG_COMMANDS},
+ {DEFAULT_TAG_COMMANDS},
+ {DEFAULT_TAG_COMMANDS},
+ {DEFAULT_TAG_COMMANDS},
+ {DEFAULT_TAG_COMMANDS},
+ {DEFAULT_TAG_COMMANDS},
+ {DEFAULT_TAG_COMMANDS}
+};
+
+#define VERBOSE_NORMAL 0x0000
+#define VERBOSE_NEGOTIATION 0x0001
+#define VERBOSE_SEQINT 0x0002
+#define VERBOSE_SCSIINT 0x0004
+#define VERBOSE_PROBE 0x0008
+#define VERBOSE_PROBE2 0x0010
+#define VERBOSE_QUEUE 0x0020
+#define VERBOSE_MINOR_ERROR 0x0040
+#define VERBOSE_QUEUE_FULL 0x0080
+#define VERBOSE_ABORT 0x0f00
+#define VERBOSE_ABORT_MID 0x0100
+#define VERBOSE_ABORT_FIND 0x0200
+#define VERBOSE_ABORT_PROCESS 0x0400
+#define VERBOSE_ABORT_RETURN 0x0800
+#define VERBOSE_RESET 0xf000
+#define VERBOSE_RESET_MID 0x1000
+#define VERBOSE_RESET_FIND 0x2000
+#define VERBOSE_RESET_PROCESS 0x4000
+#define VERBOSE_RESET_RETURN 0x8000
+static int aic7xxx_verbose = VERBOSE_NORMAL | VERBOSE_NEGOTIATION |
+ VERBOSE_PROBE; /* verbose messages */
/****************************************************************************
@@ -972,52 +1145,44 @@ static int aic7xxx_verbose = 0; /* verbose messages */
*
***************************************************************************/
+
static inline unsigned char
aic_inb(struct aic7xxx_host *p, long port)
{
- if (p->maddr != NULL)
- return (p->maddr[port]);
+ unsigned char x;
+ if(p->maddr)
+ x = p->maddr[port];
else
- return (inb(p->base + port));
+ x = inb(p->base + port);
+ mb();
+ return(x);
}
static inline void
aic_outb(struct aic7xxx_host *p, unsigned char val, long port)
{
- if (p->maddr != NULL)
+ if(p->maddr)
p->maddr[port] = val;
else
outb(val, p->base + port);
+ mb();
}
static inline void
aic_outsb(struct aic7xxx_host *p, long port, unsigned char *valp, size_t size)
{
- if (p->maddr != NULL)
+ if(p->maddr)
{
-#ifdef __alpha__
int i;
for (i=0; i < size; i++)
{
p->maddr[port] = valp[i];
}
-#else
- __asm __volatile("
- cld;
- 1: lodsb;
- movb %%al,(%0);
- loop 1b" :
- :
- "r" (p->maddr + port),
- "S" (valp), "c" (size) :
- "%esi", "%ecx", "%eax");
-#endif
}
else
- {
outsb(p->base + port, valp, size);
- }
+ mb();
}
/*+F*************************************************************************
@@ -1034,6 +1199,7 @@ aic7xxx_setup(char *s, int *dummy)
{
int i, n;
char *p;
+ char *end;
static struct {
const char *name;
@@ -1042,25 +1208,112 @@ aic7xxx_setup(char *s, int *dummy)
{ "extended", &aic7xxx_extended },
{ "no_reset", &aic7xxx_no_reset },
{ "irq_trigger", &aic7xxx_irq_trigger },
- { "ultra", &aic7xxx_enable_ultra },
{ "verbose", &aic7xxx_verbose },
- { NULL, NULL }
+ { "reverse_scan",&aic7xxx_reverse_scan },
+ { "7895_irq_hack", &aic7xxx_7895_irq_hack },
+ { "override_term", &aic7xxx_override_term },
+ { "panic_on_abort", &aic7xxx_panic_on_abort },
+ { "tag_info", NULL }
};
- for (p = strtok(s, ","); p; p = strtok(NULL, ","))
+ end = strchr(s, '\0');
+
+ for (p = strtok(s, ",."); p; p = strtok(NULL, ",."))
{
- for (i = 0; options[i].name; i++)
+ for (i = 0; i < NUMBER(options); i++)
{
n = strlen(options[i].name);
if (!strncmp(options[i].name, p, n))
{
- if (p[n] == ':')
+ if (!strncmp(p, "tag_info", n))
+ {
+ if (p[n] == ':')
+ {
+ char *base;
+ char *tok, *tok_end, *tok_end2;
+ char tok_list[] = { '.', ',', '{', '}', '\0' };
+ int i, instance = -1, device = -1;
+ unsigned char done = FALSE;
+
+ base = p;
+ tok = base + n + 1; /* Forward us just past the ':' */
+ tok_end = strchr(tok, '\0');
+ if (tok_end < end)
+ *tok_end = ',';
+ while(!done)
+ {
+ switch(*tok)
+ {
+ case '{':
+ if (instance == -1)
+ instance = 0;
+ else if (device == -1)
+ device = 0;
+ tok++;
+ break;
+ case '}':
+ if (device != -1)
+ device = -1;
+ else if (instance != -1)
+ instance = -1;
+ tok++;
+ break;
+ case ',':
+ case '.':
+ if (instance == -1)
+ done = TRUE;
+ else if (device >= 0)
+ device++;
+ else if (instance >= 0)
+ instance++;
+ if ( (device >= MAX_TARGETS) ||
+ (instance >= NUMBER(aic7xxx_tag_info)) )
+ done = TRUE;
+ tok++;
+ if (!done)
+ {
+ base = tok;
+ }
+ break;
+ case '\0':
+ done = TRUE;
+ break;
+ default:
+ done = TRUE;
+ tok_end = strchr(tok, '\0');
+ for(i=0; tok_list[i]; i++)
+ {
+ tok_end2 = strchr(tok, tok_list[i]);
+ if ( (tok_end2) && (tok_end2 < tok_end) )
+ {
+ tok_end = tok_end2;
+ done = FALSE;
+ }
+ }
+ if ( (instance >= 0) && (device >= 0) &&
+ (instance < NUMBER(aic7xxx_tag_info)) &&
+ (device < MAX_TARGETS) )
+ aic7xxx_tag_info[instance].tag_commands[device] =
+ simple_strtoul(tok, NULL, 0) & 0xff;
+ tok = tok_end;
+ break;
+ }
+ }
+ while((p != base) && (p != NULL))
+ p = strtok(NULL, ",.");
+ }
+ }
+ else if (p[n] == ':')
{
*(options[i].flag) = simple_strtoul(p + n + 1, NULL, 0);
}
+ else if (!strncmp(p, "verbose", n))
+ {
+ *(options[i].flag) = 0xff69;
+ }
else
{
- *(options[i].flag) = !0;
+ *(options[i].flag) = ~(*(options[i].flag));
}
}
}
@@ -1079,8 +1332,8 @@ aic7xxx_setup(char *s, int *dummy)
static inline void
pause_sequencer(struct aic7xxx_host *p)
{
- outb(p->pause, p->base + HCNTRL);
- while ((inb(p->base + HCNTRL) & PAUSE) == 0)
+ aic_outb(p, p->pause, HCNTRL);
+ while ((aic_inb(p, HCNTRL) & PAUSE) == 0)
{
;
}
@@ -1098,9 +1351,10 @@ static inline void
unpause_sequencer(struct aic7xxx_host *p, int unpause_always)
{
if (unpause_always ||
- ((inb(p->base + INTSTAT) & (SCSIINT | SEQINT | BRKADRINT)) == 0))
+ ( !(aic_inb(p, INTSTAT) & (SCSIINT | SEQINT | BRKADRINT)) &&
+ !(p->flags & AHC_HANDLING_REQINITS) ) )
{
- outb(p->unpause, p->base + HCNTRL);
+ aic_outb(p, p->unpause, HCNTRL);
}
}
@@ -1116,17 +1370,16 @@ static inline void
restart_sequencer(struct aic7xxx_host *p)
{
/* Set the sequencer address to 0. */
- outb(0, p->base + SEQADDR0);
- outb(0, p->base + SEQADDR1);
+ aic_outb(p, 0, SEQADDR0);
+ aic_outb(p, 0, SEQADDR1);
/*
* Reset and unpause the sequencer. The reset is suppose to
- * start the sequencer running, but we do an unpause to make
- * sure.
+ * start the sequencer running, so we immediately do a pause_sequencer
+ * since some of our code expects the sequencer paused after a restart
*/
- outb(SEQRESET | FASTMODE, p->base + SEQCTL);
-
- unpause_sequencer(p, /*unpause_always*/ TRUE);
+ aic_outb(p, SEQRESET | FASTMODE, SEQCTL);
+ pause_sequencer(p);
}
@@ -1178,11 +1431,12 @@ static void
aic7xxx_download_instr(struct aic7xxx_host *p, int options, int instrptr)
{
unsigned char opcode;
- struct ins_format3 *instr;
+ struct ins_format3 instr;
+ unsigned char dconsts[4] = { 0, 0, 0, 0 };
- instr = (struct ins_format3 *) &seqprog[instrptr * 4];
+ instr = *(struct ins_format3 *) &seqprog[instrptr * 4];
/* Pull the opcode */
- opcode = instr->opcode_addr >> 1;
+ opcode = (instr.opcode_addr & ~DOWNLOAD_CONST_IMMEDIATE) >> 1;
switch (opcode)
{
case AIC_OP_JMP:
@@ -1195,15 +1449,13 @@ aic7xxx_download_instr(struct aic7xxx_host *p, int options, int instrptr)
case AIC_OP_JZ:
{
int address_offset;
- struct ins_format3 new_instr;
unsigned int address;
struct patch *patch;
int i;
address_offset = 0;
- new_instr = *instr; /* Strucure copy */
- address = new_instr.address;
- address |= (new_instr.opcode_addr & ADDR_HIGH_BIT) << 8;
+ address = instr.address;
+ address |= (instr.opcode_addr & ADDR_HIGH_BIT) << 8;
for (i = 0; i < NUMBER(patches); i++)
{
patch = &patches[i];
@@ -1217,20 +1469,23 @@ aic7xxx_download_instr(struct aic7xxx_host *p, int options, int instrptr)
}
}
address -= address_offset;
- new_instr.address = address &0xFF;
- new_instr.opcode_addr &= ~ADDR_HIGH_BIT;
- new_instr.opcode_addr |= (address >> 8) & ADDR_HIGH_BIT;
- outsb(p->base + SEQRAM, &new_instr.immediate, 4);
- break;
+ instr.address = address & 0xFF;
+ instr.opcode_addr &= ~ADDR_HIGH_BIT;
+ instr.opcode_addr |= (address >> 8) & ADDR_HIGH_BIT;
}
-
+ /* Fall through */
case AIC_OP_OR:
case AIC_OP_AND:
case AIC_OP_XOR:
case AIC_OP_ADD:
case AIC_OP_ADC:
+ if (instr.opcode_addr & DOWNLOAD_CONST_IMMEDIATE)
+ {
+ instr.immediate = dconsts[instr.immediate];
+ }
+ instr.opcode_addr &= ~DOWNLOAD_CONST_IMMEDIATE;
case AIC_OP_ROL:
- outsb(p->base + SEQRAM, &instr->immediate, 4);
+ aic_outsb(p, SEQRAM, &instr.immediate, 4);
break;
default:
@@ -1255,23 +1510,60 @@ aic7xxx_loadseq(struct aic7xxx_host *p)
int i;
int downloaded;
- if (aic7xxx_verbose)
+ if (aic7xxx_verbose & VERBOSE_PROBE)
{
- printk(KERN_INFO "aic7xxx: Downloading sequencer code...");
+ printk(KERN_INFO "(scsi%d) Downloading sequencer code...", p->host_no);
}
+ if (aic7xxx_verbose & VERBOSE_PROBE2)
+ printk("\n");
options = 1; /* Code for all options. */
downloaded = 0;
- if ((p->flags & ULTRA_ENABLED) != 0)
+ if (p->type & AHC_ULTRA)
+ {
options |= ULTRA;
- if (p->bus_type == AIC_TWIN)
+ if (aic7xxx_verbose & VERBOSE_PROBE2)
+ printk(KERN_INFO "(scsi%d) Will download code for option ULTRA\n",
+ p->host_no);
+ }
+ if (p->type & AHC_TWIN)
+ {
options |= TWIN_CHANNEL;
- if (p->scb_data->maxscbs > p->scb_data->maxhscbs)
+ if (aic7xxx_verbose & VERBOSE_PROBE2)
+ printk(KERN_INFO "(scsi%d) Will download code for option "
+ "TWIN_CHANNEL\n", p->host_no);
+ }
+ if (p->type & AHC_WIDE)
+ {
+ options |= WIDE;
+ if (aic7xxx_verbose & VERBOSE_PROBE2)
+ printk(KERN_INFO "(scsi%d) Will download code for option WIDE\n",
+ p->host_no);
+ }
+ /* if (p->scb_data->maxscbs > p->scb_data->maxhscbs) this should always
+ be true, don't test,
+ just do. */
+ {
options |= SCB_PAGING;
+ if (aic7xxx_verbose & VERBOSE_PROBE2)
+ printk(KERN_INFO "(scsi%d) Will download code for option SCB_PAGING\n",
+ p->host_no);
+ }
+ /* We don't actually support target mode yet, so leave this out
+ if (p->flags & AHC_TARGETMODE)
+ options |= TARGET_MODE; */
+
+ if ( (options & ~(ULTRA|TWIN_CHANNEL|WIDE|SCB_PAGING|0x01)) )
+ {
+ printk(KERN_INFO "(scsi%d) Unknown bits set in the options field, "
+ "correcting.\n", p->host_no);
+ options &= ULTRA|TWIN_CHANNEL|WIDE|SCB_PAGING|0x01;
+ }
+
cur_patch = patches;
- outb(PERRORDIS | LOADRAM, p->base + SEQCTL);
- outb(0, p->base + SEQADDR0);
- outb(0, p->base + SEQADDR1);
+ aic_outb(p, PERRORDIS | LOADRAM, SEQCTL);
+ aic_outb(p, 0, SEQADDR0);
+ aic_outb(p, 0, SEQADDR1);
for (i = 0; i < sizeof(seqprog) / 4; i++)
{
@@ -1285,13 +1577,16 @@ aic7xxx_loadseq(struct aic7xxx_host *p)
downloaded++;
}
- outb(FASTMODE, p->base + SEQCTL);
- outb(0, p->base + SEQADDR0);
- outb(0, p->base + SEQADDR1);
+ aic_outb(p, FASTMODE, SEQCTL);
+ aic_outb(p, 0, SEQADDR0);
+ aic_outb(p, 0, SEQADDR1);
- if (aic7xxx_verbose)
+ if (aic7xxx_verbose & VERBOSE_PROBE2)
+ printk(KERN_INFO "(scsi%d) Download complete,", p->host_no);
+
+ if (aic7xxx_verbose & VERBOSE_PROBE)
{
- printk(" %d instructions downloaded\n", downloaded);
+ printk(" %d instructions downloaded\n", downloaded);
}
}
@@ -1307,7 +1602,7 @@ aic7xxx_loadseq(struct aic7xxx_host *p)
static void
aic7xxx_delay(int seconds)
{
- int i;
+ unsigned int i;
/*
* Call udelay() for 1 millisecond inside a loop for
@@ -1321,116 +1616,33 @@ aic7xxx_delay(int seconds)
/*+F*************************************************************************
* Function:
- * rcs_version
- *
- * Description:
- * Return a string containing just the RCS version number from either
- * an Id or Revision RCS clause.
- *-F*************************************************************************/
-const char *
-rcs_version(const char *version_info)
-{
- static char buf[10];
- char *bp, *ep;
-
- bp = NULL;
- strcpy(buf, "????");
- if (!strncmp(version_info, "$Id: ", 5))
- {
- if ((bp = strchr(version_info, ' ')) != NULL)
- {
- bp++;
- if ((bp = strchr(bp, ' ')) != NULL)
- {
- bp++;
- }
- }
- }
- else
- {
- if (!strncmp(version_info, "$Revision: ", 11))
- {
- if ((bp = strchr(version_info, ' ')) != NULL)
- {
- bp++;
- }
- }
- }
-
- if (bp != NULL)
- {
- if ((ep = strchr(bp, ' ')) != NULL)
- {
- register int len = ep - bp;
-
- strncpy(buf, bp, len);
- buf[len] = '\0';
- }
- }
-
- return buf;
-}
-
-/*+F*************************************************************************
- * Function:
* aic7xxx_info
*
* Description:
* Return a string describing the driver.
*-F*************************************************************************/
const char *
-aic7xxx_info(struct Scsi_Host *notused)
+aic7xxx_info(struct Scsi_Host *dooh)
{
- static char buffer[128];
-
- strcpy(buffer, "Adaptec AHA274x/284x/294x (EISA/VLB/PCI-Fast SCSI) ");
- strcat(buffer, rcs_version(AIC7XXX_C_VERSION));
- strcat(buffer, "/");
- strcat(buffer, rcs_version(AIC7XXX_H_VERSION));
-#if 0
- strcat(buffer, "/");
- strcat(buffer, rcs_version(AIC7XXX_SEQ_VER));
-#endif
+ static char buffer[256];
+ char *bp;
+ struct aic7xxx_host *p;
- return buffer;
+ bp = &buffer[0];
+ p = (struct aic7xxx_host *)dooh->hostdata;
+ memset(bp, 0, sizeof(buffer));
+ strcpy(bp, "Adaptec AHA274x/284x/294x (EISA/VLB/PCI-Fast SCSI) ");
+ strcat(bp, AIC7XXX_C_VERSION);
+ strcat(bp, "/");
+ strcat(bp, AIC7XXX_H_VERSION);
+ strcat(bp, "\n");
+ strcat(bp, " <");
+ strcat(bp, board_names[p->board_name_index]);
+ strcat(bp, ">");
+
+ return(bp);
}
-/*+F*************************************************************************
- * Function:
- * aic7xxx_length
- *
- * Description:
- * How much data should be transferred for this SCSI command? Assume
- * all segments are to be transferred except for the last sg_last
- * segments. This will allow us to compute underflow easily. To
- * calculate the total length of the command, use sg_last = 0. To
- * calculate the length of all but the last 2 SG segments, use
- * sg_last = 2.
- *-F*************************************************************************/
-static unsigned
-aic7xxx_length(Scsi_Cmnd *cmd, int sg_last)
-{
- int i, segments;
- unsigned length;
- struct scatterlist *sg;
-
- segments = cmd->use_sg - sg_last;
- sg = (struct scatterlist *) cmd->request_buffer;
-
- if (cmd->use_sg)
- {
- for (i = length = 0; i < segments; i++)
- {
- length += sg[i].length;
- }
- }
- else
- {
- length = cmd->request_bufflen;
- }
-
- return (length);
-}
/*+F*************************************************************************
* Function:
@@ -1439,19 +1651,28 @@ aic7xxx_length(Scsi_Cmnd *cmd, int sg_last)
* Description:
* Look up the valid period to SCSIRATE conversion in our table
*-F*************************************************************************/
-static void
+static unsigned char
aic7xxx_scsirate(struct aic7xxx_host *p, unsigned char *scsirate,
- unsigned char *period, unsigned char *offset, int target, char channel)
+ unsigned char *period, unsigned char *offset, int target, int channel,
+ int set)
{
int i = num_aic7xxx_syncrates;
- unsigned long ultra_enb_addr;
- unsigned char ultra_enb, sxfrctl0;
+ unsigned char response_period;
+ unsigned char tindex;
+ unsigned short target_mask;
+ unsigned char lun;
+
+ tindex = target | (channel << 3);
+ target_mask = 0x01 << tindex;
+ lun = aic_inb(p, SCB_TCL) & 0x07;
+
+ response_period = *period;
/*
* If the offset is 0, then the device is requesting asynchronous
* transfers.
*/
- if ((*period <= aic7xxx_syncrates[i - 1].period) && *offset != 0)
+ if ((*period != 0) && (*offset != 0))
{
for (i = 0; i < num_aic7xxx_syncrates; i++)
{
@@ -1461,7 +1682,7 @@ aic7xxx_scsirate(struct aic7xxx_host *p, unsigned char *scsirate,
* Watch out for Ultra speeds when ultra is not enabled and
* vice-versa.
*/
- if (!(p->flags & ULTRA_ENABLED) &&
+ if (!(p->type & AHC_ULTRA) &&
(aic7xxx_syncrates[i].rate & ULTRA_SXFR))
{
/*
@@ -1474,11 +1695,31 @@ aic7xxx_scsirate(struct aic7xxx_host *p, unsigned char *scsirate,
*scsirate = (aic7xxx_syncrates[i].rate & 0xF0) | (*offset & 0x0F);
*period = aic7xxx_syncrates[i].period;
- if (aic7xxx_verbose)
+ /*
+ * When responding to a target that requests
+ * sync, that rate may fall between two rates
+ * that we can output, but still be a rate
+ * that we can receive. Because of this,
+ * we may want to respond to the target with
+ * the same rate that it sent to us even
+ * if the period we use to send data to it
+ * is lower. Only lower the response period
+ * if we must.
+ */
+ if ((i == 0) ||
+ ((aic7xxx_syncrates[i-1].rate & ULTRA_SXFR) != 0
+ && (p->type & AHC_ULTRA) == 0))
+ {
+ response_period = *period;
+ }
+
+ if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
+ (p->dev_flags[tindex] & DEVICE_PRINT_SDTR) )
{
- printk("scsi%d: Target %d, channel %c, now synchronous at %sMHz, "
- "offset %d.\n", p->host_no, target, channel,
+ printk(INFO_LEAD "Synchronous at %sMHz, "
+ "offset %d.\n", p->host_no, channel, target, lun,
aic7xxx_syncrates[i].english, *offset);
+ p->dev_flags[tindex] &= ~ DEVICE_PRINT_SDTR;
}
break;
}
@@ -1493,35 +1734,43 @@ aic7xxx_scsirate(struct aic7xxx_host *p, unsigned char *scsirate,
*scsirate = 0;
*period = 0;
*offset = 0;
- if (aic7xxx_verbose)
+ response_period = 0;
+ if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
+ (p->dev_flags[tindex] & DEVICE_PRINT_SDTR) )
{
- printk("scsi%d: Target %d, channel %c, using asynchronous transfers.\n",
- p->host_no, target, channel);
+ printk(INFO_LEAD "Using asynchronous transfers.\n",
+ p->host_no, channel, target, lun);
+ p->dev_flags[tindex] &= ~DEVICE_PRINT_SDTR;
}
}
/*
* Ensure Ultra mode is set properly for this target.
*/
- ultra_enb_addr = ULTRA_ENB;
- if ((channel == 'B') || (target > 7))
+ if ( (*scsirate != 0) &&
+ (aic7xxx_syncrates[i].rate & ULTRA_SXFR) )
{
- ultra_enb_addr++;
+ p->ultraenb |= target_mask;
}
- ultra_enb = inb(p->base + ultra_enb_addr);
- sxfrctl0 = inb(p->base + SXFRCTL0);
- if ((*scsirate != 0) && (aic7xxx_syncrates[i].rate & ULTRA_SXFR))
+ else
{
- ultra_enb |= 0x01 << (target & 0x07);
- sxfrctl0 |= FAST20;
+ p->ultraenb &= ~target_mask;
}
- else
+ if (set)
{
- ultra_enb &= ~(0x01 << (target & 0x07));
+ unsigned char sxfrctl0;
+
+ sxfrctl0 = aic_inb(p, SXFRCTL0);
sxfrctl0 &= ~FAST20;
+ if (p->ultraenb & target_mask)
+ {
+ sxfrctl0 |= FAST20;
+ }
+ aic_outb(p, p->ultraenb & 0xff, ULTRA_ENB);
+ aic_outb(p, (p->ultraenb >> 8) & 0xff, ULTRA_ENB + 1);
+ aic_outb(p, sxfrctl0, SXFRCTL0);
}
- outb(ultra_enb, p->base + ultra_enb_addr);
- outb(sxfrctl0, p->base + SXFRCTL0);
+ return(response_period);
}
/*+F*************************************************************************
@@ -1533,7 +1782,7 @@ aic7xxx_scsirate(struct aic7xxx_host *p, unsigned char *scsirate,
*
*-F*************************************************************************/
static inline void
-scbq_init(scb_queue_type *queue)
+scbq_init(volatile scb_queue_type *queue)
{
queue->head = NULL;
queue->tail = NULL;
@@ -1548,7 +1797,7 @@ scbq_init(scb_queue_type *queue)
*
*-F*************************************************************************/
static inline void
-scbq_insert_head(scb_queue_type *queue, struct aic7xxx_scb *scb)
+scbq_insert_head(volatile scb_queue_type *queue, struct aic7xxx_scb *scb)
{
scb->q_next = queue->head;
queue->head = scb;
@@ -1564,13 +1813,16 @@ scbq_insert_head(scb_queue_type *queue, struct aic7xxx_scb *scb)
* Remove an SCB from the head of the list.
*
*-F*************************************************************************/
-static inline void
-scbq_remove_head(scb_queue_type *queue)
+static __inline struct aic7xxx_scb *
+scbq_remove_head(volatile scb_queue_type *queue)
{
+ struct aic7xxx_scb * scbp;
+ scbp = queue->head;
if (queue->head != NULL)
queue->head = queue->head->q_next;
if (queue->head == NULL) /* If list is now empty, update tail. */
queue->tail = NULL;
+ return(scbp);
}
/*+F*************************************************************************
@@ -1582,7 +1834,7 @@ scbq_remove_head(scb_queue_type *queue)
*
*-F*************************************************************************/
static inline void
-scbq_remove(scb_queue_type *queue, struct aic7xxx_scb *scb)
+scbq_remove(volatile scb_queue_type *queue, struct aic7xxx_scb *scb)
{
if (queue->head == scb)
{
@@ -1623,12 +1875,11 @@ scbq_remove(scb_queue_type *queue, struct aic7xxx_scb *scb)
*
*-F*************************************************************************/
static inline void
-scbq_insert_tail(scb_queue_type *queue, struct aic7xxx_scb *scb)
+scbq_insert_tail(volatile scb_queue_type *queue, struct aic7xxx_scb *scb)
{
scb->q_next = NULL;
if (queue->tail != NULL) /* Add the scb at the end of the list. */
queue->tail->q_next = scb;
-
queue->tail = scb; /* Update the tail. */
if (queue->head == NULL) /* If list was empty, update head. */
queue->head = queue->tail;
@@ -1645,18 +1896,14 @@ scbq_insert_tail(scb_queue_type *queue, struct aic7xxx_scb *scb)
* to be reset and all devices on that channel must be aborted.
*-F*************************************************************************/
static int
-aic7xxx_match_scb(struct aic7xxx_scb *scb, int target, char channel,
- int lun, unsigned char tag)
+aic7xxx_match_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb,
+ int target, int channel, int lun, unsigned char tag)
{
int targ = (scb->hscb->target_channel_lun >> 4) & 0x0F;
- char chan = (scb->hscb->target_channel_lun & SELBUSB) ? 'B' : 'A';
+ int chan = (scb->hscb->target_channel_lun >> 3) & 0x01;
int slun = scb->hscb->target_channel_lun & 0x07;
int match;
-#ifdef AIC7XXX_DEBUG_ABORT
- printk("scsi%d: (targ %d/chan %c) matching scb to (targ %d/chan %c)\n",
- scb->cmd->device->host->host_no, target, channel, targ, chan);
-#endif
match = ((chan == channel) || (channel == ALL_CHANNELS));
if (match != 0)
match = ((targ == target) || (target == ALL_TARGETS));
@@ -1665,6 +1912,14 @@ aic7xxx_match_scb(struct aic7xxx_scb *scb, int target, char channel,
if (match != 0)
match = ((tag == scb->hscb->tag) || (tag == SCB_LIST_NULL));
+ if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
+ {
+ printk(KERN_INFO "(scsi%d:%d:%d:%d:tag%d) %s search criteria"
+ " (scsi%d:%d:%d:%d:tag%d)\n", p->host_no, CTL_OF_SCB(scb),
+ scb->hscb->tag, (match) ? "matches" : "doesn't match",
+ p->host_no, channel, target, lun, tag);
+ }
+
return (match);
}
@@ -1682,10 +1937,11 @@ aic7xxx_add_curscb_to_free_list(struct aic7xxx_host *p)
* Invalidate the tag so that aic7xxx_find_scb doesn't think
* it's active
*/
- outb(SCB_LIST_NULL, p->base + SCB_TAG);
+ aic_outb(p, SCB_LIST_NULL, SCB_TAG);
+ aic_outb(p, 0, SCB_CONTROL);
- outb(inb(p->base + FREE_SCBH), p->base + SCB_NEXT);
- outb(inb(p->base + SCBPTR), p->base + FREE_SCBH);
+ aic_outb(p, aic_inb(p, FREE_SCBH), SCB_NEXT);
+ aic_outb(p, aic_inb(p, SCBPTR), FREE_SCBH);
}
/*+F*************************************************************************
@@ -1702,28 +1958,25 @@ aic7xxx_rem_scb_from_disc_list(struct aic7xxx_host *p, unsigned char scbptr)
unsigned char next;
unsigned char prev;
- outb(scbptr, p->base + SCBPTR);
- next = inb(p->base + SCB_NEXT);
- prev = inb(p->base + SCB_PREV);
-
- outb(0, p->base + SCB_CONTROL);
-
+ aic_outb(p, scbptr, SCBPTR);
+ next = aic_inb(p, SCB_NEXT);
+ prev = aic_inb(p, SCB_PREV);
aic7xxx_add_curscb_to_free_list(p);
if (prev != SCB_LIST_NULL)
{
- outb(prev, p->base + SCBPTR);
- outb(next, p->base + SCB_NEXT);
+ aic_outb(p, prev, SCBPTR);
+ aic_outb(p, next, SCB_NEXT);
}
else
{
- outb(next, p->base + DISCONNECTED_SCBH);
+ aic_outb(p, next, DISCONNECTED_SCBH);
}
if (next != SCB_LIST_NULL)
{
- outb(next, p->base + SCBPTR);
- outb(prev, p->base + SCB_PREV);
+ aic_outb(p, next, SCBPTR);
+ aic_outb(p, prev, SCB_PREV);
}
return next;
}
@@ -1735,23 +1988,10 @@ aic7xxx_rem_scb_from_disc_list(struct aic7xxx_host *p, unsigned char scbptr)
* Description:
* Set the specified target busy.
*-F*************************************************************************/
-static void
-aic7xxx_busy_target(struct aic7xxx_host *p, unsigned char target,
- char channel, unsigned char scbid)
+static __inline void
+aic7xxx_busy_target(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
{
- unsigned char active_scb;
- unsigned char info_scb;
- unsigned int scb_offset;
-
- info_scb = target / 4;
- if (channel == 'B')
- info_scb = info_scb + 2;
-
- active_scb = inb(p->base + SCBPTR);
- outb(info_scb, p->base + SCBPTR);
- scb_offset = SCB_BUSYTARGETS + (target & 0x03);
- outb(scbid, p->base + scb_offset);
- outb(active_scb, p->base + SCBPTR);
+ p->untagged_scbs[scb->hscb->target_channel_lun] = scb->hscb->tag;
}
/*+F*************************************************************************
@@ -1762,28 +2002,17 @@ aic7xxx_busy_target(struct aic7xxx_host *p, unsigned char target,
* Returns the index of the busy target, and optionally sets the
* target inactive.
*-F*************************************************************************/
-static unsigned char
-aic7xxx_index_busy_target(struct aic7xxx_host *p, unsigned char target,
- char channel, int unbusy)
+static __inline unsigned char
+aic7xxx_index_busy_target(struct aic7xxx_host *p, unsigned char tcl,
+ int unbusy)
{
- unsigned char active_scb;
- unsigned char info_scb;
unsigned char busy_scbid;
- unsigned int scb_offset;
- info_scb = target / 4;
- if (channel == 'B')
- info_scb = info_scb + 2;
-
- active_scb = inb(p->base + SCBPTR);
- outb(info_scb, p->base + SCBPTR);
- scb_offset = SCB_BUSYTARGETS + (target & 0x03);
- busy_scbid = inb(p->base + scb_offset);
+ busy_scbid = p->untagged_scbs[tcl];
if (unbusy)
{
- outb(SCB_LIST_NULL, p->base + scb_offset);
+ p->untagged_scbs[tcl] = SCB_LIST_NULL;
}
- outb(active_scb, p->base + SCBPTR);
return (busy_scbid);
}
@@ -1803,17 +2032,17 @@ aic7xxx_find_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
unsigned char saved_scbptr;
unsigned char curindex;
- saved_scbptr = inb(p->base + SCBPTR);
+ saved_scbptr = aic_inb(p, SCBPTR);
curindex = 0;
for (curindex = 0; curindex < p->scb_data->maxhscbs; curindex++)
{
- outb(curindex, p->base + SCBPTR);
- if (inb(p->base + SCB_TAG) == scb->hscb->tag)
+ aic_outb(p, curindex, SCBPTR);
+ if (aic_inb(p, SCB_TAG) == scb->hscb->tag)
{
break;
}
}
- outb(saved_scbptr, p->base + SCBPTR);
+ aic_outb(p, saved_scbptr, SCBPTR);
if (curindex >= p->scb_data->maxhscbs)
{
curindex = SCB_LIST_NULL;
@@ -1830,58 +2059,83 @@ aic7xxx_find_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
* Get an SCB from the free list or by allocating a new one.
*-F*************************************************************************/
static struct aic7xxx_scb *
-aic7xxx_allocate_scb(struct aic7xxx_host *p)
+aic7xxx_allocate_scb(struct aic7xxx_host *p, int force_alloc)
{
struct aic7xxx_scb *scbp = NULL;
- struct aic7xxx_hwscb *hscbp = NULL;
-#ifdef AGRESSIVE
- long processor_flags;
+ int scb_size = sizeof(struct aic7xxx_scb) +
+ sizeof (struct hw_scatterlist) * AIC7XXX_MAX_SG;
+ int i;
+ unsigned long scb_count = 0;
+ struct hw_scatterlist *hsgp;
+ struct aic7xxx_scb *scb_ap;
- save_flags(processor_flags);
- cli();
-#endif
- scbp = p->scb_data->free_scbs.head;
- if (scbp != NULL)
+ if (force_alloc == FALSE)
{
- scbq_remove_head(&p->scb_data->free_scbs);
+ scbp = scbq_remove_head(&p->scb_data->free_scbs);
+ if (scbp != NULL)
+ return(scbp);
}
- else
+ /*
+ * Either there wasn't an SCB or this is a strictly allocation call
+ */
+
+ if (p->scb_data->numscbs < p->scb_data->maxscbs)
{
- if (p->scb_data->numscbs < p->scb_data->maxscbs)
- {
- int scb_index = p->scb_data->numscbs;
- int scb_size = sizeof(struct aic7xxx_scb) +
- sizeof (struct hw_scatterlist) * AIC7XXX_MAX_SG;
- scbp = kmalloc(scb_size, GFP_ATOMIC);
- if (scbp != NULL)
+ /*
+ * Optimize for 30 scbs at a time, but allow a final allocation of
+ * fewer than 30 scbs. Except on 64 bit platforms, we optimize for
+ * 29 SCBs at a time because a pointer is 4 bytes larger and we don't
+ * want to overrun this suppossedly 32K allocation to 64K and waste
+ * tons of space.
+ */
+ if( sizeof(void *) == sizeof(int) )
+ scb_count = MIN(30, p->scb_data->maxscbs - p->scb_data->numscbs);
+ else
+ scb_count = MIN(29, p->scb_data->maxscbs - p->scb_data->numscbs);
+
+ scb_ap = (struct aic7xxx_scb *)kmalloc(scb_size * scb_count, GFP_ATOMIC);
+ if (scb_ap != NULL)
+ {
+ if (aic7xxx_verbose & VERBOSE_QUEUE)
+ {
+ if (p->scb_data->numscbs == 0)
+ printk(INFO_LEAD "Allocating initial %ld SCB structures.\n",
+ p->host_no, -1, -1, -1, scb_count);
+ else
+ printk(INFO_LEAD "Allocating %ld additional SCB structures.\n",
+ p->host_no, -1, -1, -1, scb_count);
+ }
+ memset(scb_ap, 0, scb_count * scb_size);
+ hsgp = (struct hw_scatterlist *) &scb_ap[scb_count];
+ for (i=0; i < scb_count; i++)
{
- memset(scbp, 0, sizeof(struct aic7xxx_scb));
- hscbp = &p->scb_data->hscbs[scb_index];
- scbp->hscb = hscbp;
- scbp->sg_list = (struct hw_scatterlist *) &scbp[1];
- memset(hscbp, 0, sizeof(struct aic7xxx_hwscb));
- hscbp->tag = scb_index;
- p->scb_data->numscbs++;
+ scbp = &scb_ap[i];
+ scbp->hscb = &p->scb_data->hscbs[p->scb_data->numscbs];
+ scbp->sg_list = &hsgp[i * AIC7XXX_MAX_SG];
+ memset(scbp->hscb, 0, sizeof(struct aic7xxx_hwscb));
+ scbp->hscb->tag = p->scb_data->numscbs;
/*
* Place in the scb array; never is removed
*/
- p->scb_data->scb_array[scb_index] = scbp;
+ p->scb_data->scb_array[p->scb_data->numscbs++] = scbp;
+ scbq_insert_head(&p->scb_data->free_scbs, scbp);
}
}
+ else
+ {
+ return(NULL);
+ }
}
-#ifdef AIC7XXX_DEBUG
- if (scbp != NULL)
+ if (force_alloc == TRUE)
{
- p->activescbs++;
+ return((struct aic7xxx_scb *)scb_count);
+ }
+ else
+ {
+ return(scbq_remove_head(&p->scb_data->free_scbs));
}
-#endif
-
-#ifdef AGRESSIVE
- restore_flags(processor_flags);
-#endif
- return (scbp);
}
/*+F*************************************************************************
@@ -1896,11 +2150,8 @@ aic7xxx_allocate_scb(struct aic7xxx_host *p)
static inline void
aic7xxx_queue_cmd_complete(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
{
- if (p->completeq.tail == NULL)
- p->completeq.head = cmd;
- else
- p->completeq.tail->host_scribble = (char *) cmd;
- p->completeq.tail = cmd;
+ cmd->host_scribble = (char *)p->completeq.head;
+ p->completeq.head = cmd;
}
/*+F*************************************************************************
@@ -1914,16 +2165,21 @@ static inline void
aic7xxx_done_cmds_complete(struct aic7xxx_host *p)
{
Scsi_Cmnd *cmd;
-
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+ unsigned int cpu_flags = 0;
+#endif
+
+ DRIVER_LOCK
while (p->completeq.head != NULL)
{
cmd = p->completeq.head;
p->completeq.head = (Scsi_Cmnd *)cmd->host_scribble;
cmd->host_scribble = NULL;
- p->device_status[TARGET_INDEX(cmd)].active_cmds--;
+ DRIVER_UNLOCK
cmd->scsi_done(cmd);
+ DRIVER_LOCK
}
- p->completeq.tail = NULL;
+ DRIVER_UNLOCK
}
/*+F*************************************************************************
@@ -1936,24 +2192,17 @@ aic7xxx_done_cmds_complete(struct aic7xxx_host *p)
static void
aic7xxx_free_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
{
- struct aic7xxx_hwscb *hscb;
- long flags;
-
- hscb = scb->hscb;
- save_flags(flags);
- cli();
scb->flags = SCB_FREE;
scb->cmd = NULL;
- hscb->control = 0;
- hscb->target_status = 0;
+ scb->sg_count = 0;
+ scb->sg_length = 0;
+ scb->tag_action = 0;
+ scb->hscb->control = 0;
+ scb->hscb->target_status = 0;
+ scb->hscb->target_channel_lun = SCB_LIST_NULL;
scbq_insert_head(&p->scb_data->free_scbs, scb);
-#ifdef AIC7XXX_DEBUG
- p->activescbs--; /* For debugging purposes. */
-#endif
-
- restore_flags(flags);
}
/*+F*************************************************************************
@@ -1967,25 +2216,31 @@ static void
aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
{
Scsi_Cmnd *cmd = scb->cmd;
+ int tindex = TARGET_INDEX(cmd);
+ struct aic7xxx_scb *scbp;
+ unsigned char queue_depth;
if (scb->flags & SCB_RECOVERY_SCB)
{
- p->flags &= ~IN_TIMEOUT;
+ p->flags &= ~AHC_ABORT_PENDING;
}
- if (cmd->result == DID_OK)
+ if (scb->flags & SCB_RESET)
{
- if (scb->flags & SCB_ABORTED)
- {
- cmd->result = (DID_RESET << 16);
- }
+ cmd->result = (DID_RESET << 16) | (SUGGEST_RETRY << 24) |
+ (cmd->result & 0xffff);
+ }
+ else if (scb->flags & SCB_ABORT)
+ {
+ cmd->result = (DID_RESET << 16) | (SUGGEST_RETRY << 24) |
+ (cmd->result & 0xffff);
}
if ((scb->flags & (SCB_MSGOUT_WDTR | SCB_MSGOUT_SDTR)) != 0)
{
unsigned short mask;
int message_error = FALSE;
- mask = 0x01 << TARGET_INDEX(scb->cmd);
-
+ mask = 0x01 << tindex;
+
/*
* Check to see if we get an invalid message or a message error
* after failing to negotiate a wide or sync transfer message.
@@ -2002,6 +2257,17 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
p->wdtr_pending &= ~mask;
if (message_error)
{
+ if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
+ (p->dev_flags[tindex] & DEVICE_PRINT_WDTR) )
+ {
+ printk(INFO_LEAD "Device failed to complete Wide Negotiation "
+ "processing and\n", p->host_no, CTL_OF_SCB(scb));
+ printk(INFO_LEAD "returned a sense error code for invalid message, "
+ "disabling future\n", p->host_no, CTL_OF_SCB(scb));
+ printk(INFO_LEAD "Wide negotiation to this device.\n", p->host_no,
+ CTL_OF_SCB(scb));
+ p->dev_flags[tindex] &= ~DEVICE_PRINT_WDTR;
+ }
p->needwdtr &= ~mask;
p->needwdtr_copy &= ~mask;
}
@@ -2011,27 +2277,74 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
p->sdtr_pending &= ~mask;
if (message_error)
{
+ if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
+ (p->dev_flags[tindex] & DEVICE_PRINT_SDTR) )
+ {
+ printk(INFO_LEAD "Device failed to complete Sync Negotiation "
+ "processing and\n", p->host_no, CTL_OF_SCB(scb));
+ printk(INFO_LEAD "returned a sense error code for invalid message, "
+ "disabling future\n", p->host_no, CTL_OF_SCB(scb));
+ printk(INFO_LEAD "Sync negotiation to this device.\n", p->host_no,
+ CTL_OF_SCB(scb));
+ p->dev_flags[tindex] &= ~DEVICE_PRINT_SDTR;
+ }
p->needsdtr &= ~mask;
p->needsdtr_copy &= ~mask;
}
}
}
- aic7xxx_free_scb(p, scb);
- aic7xxx_queue_cmd_complete(p, cmd);
+ queue_depth = p->dev_temp_queue_depth[tindex];
+ if (queue_depth >= p->dev_active_cmds[tindex])
+ {
+ scbp = scbq_remove_head(&p->delayed_scbs[tindex]);
+ if (scbp)
+ scbq_insert_tail(&p->waiting_scbs, scbp);
+ if ( (queue_depth > p->dev_active_cmds[tindex]) && scbp)
+ {
+ scbp = scbq_remove_head(&p->delayed_scbs[tindex]);
+ if (scbp)
+ scbq_insert_tail(&p->waiting_scbs, scbp);
+ }
+ }
+ if ( (p->dev_timer[tindex].expires) &&
+ ((p->dev_active_cmds[tindex] == 1) ||
+ (p->dev_max_queue_depth[tindex] ==
+ p->dev_temp_queue_depth[tindex])) )
+ {
+ del_timer(&p->dev_timer[tindex]);
+ p->dev_timer[tindex].expires = 0;
+ p->dev_temp_queue_depth[tindex] =
+ p->dev_max_queue_depth[tindex];
+ }
+ p->dev_active_cmds[tindex]--;
+ p->activescbs--;
+
+ /*
+ * If this was an untagged I/O, unbusy the target so the sequencer won't
+ * mistake things later
+ */
+ if (aic7xxx_index_busy_target(p, scb->hscb->target_channel_lun, FALSE) ==
+ scb->hscb->tag)
+ {
+ aic7xxx_index_busy_target(p, scb->hscb->target_channel_lun, TRUE);
+ }
#ifdef AIC7XXX_PROC_STATS
- if ( (cmd->cmnd[0] != TEST_UNIT_READY) &&
- (cmd->cmnd[0] != INQUIRY) )
{
int actual;
/*
* XXX: we should actually know how much actually transferred
* XXX: for each command, but apparently that's too difficult.
+ *
+ * We set a lower limit of 512 bytes on the transfer length. We
+ * ignore anything less than this because we don't have a real
+ * reason to count it. Read/Writes to tapes are usually about 20K
+ * and disks are a minimum of 512 bytes unless you want to count
+ * non-read/write commands (such as TEST_UNIT_READY) which we don't
*/
- actual = aic7xxx_length(cmd, 0);
- if (!(scb->flags & (SCB_ABORTED | SCB_SENSE)) && (actual > 0)
- && (aic7xxx_error(cmd) == 0))
+ actual = scb->sg_length;
+ if ((actual >= 512) && (((cmd->result >> 16) & 0xf) == DID_OK))
{
struct aic7xxx_xferstats *sp;
long *ptr;
@@ -2040,7 +2353,14 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
sp = &p->stats[TARGET_INDEX(cmd)][cmd->lun & 0x7];
sp->xfers++;
- if (cmd->request.cmd == WRITE)
+ /*
+ * For block devices, cmd->request.cmd is always == either READ or
+ * WRITE. For character devices, this isn't always set properly, so
+ * we check data_cmnd[0]. This catches the conditions for st.c, but
+ * I'm still not sure if request.cmd is valid for sg devices.
+ */
+ if ( (cmd->request.cmd == WRITE) || (cmd->data_cmnd[0] == WRITE_6) ||
+ (cmd->data_cmnd[0] == WRITE_FILEMARKS) )
{
sp->w_total++;
sp->w_total512 += (actual >> 9);
@@ -2067,6 +2387,10 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
}
}
#endif /* AIC7XXX_PROC_STATS */
+
+ aic7xxx_free_scb(p, scb);
+ aic7xxx_queue_cmd_complete(p, cmd);
+
}
/*+F*************************************************************************
@@ -2082,20 +2406,25 @@ static void
aic7xxx_run_done_queue(struct aic7xxx_host *p, /*complete*/ int complete)
{
struct aic7xxx_scb *scb;
- int i;
+ int i, found = 0;
for (i = 0; i < p->scb_data->numscbs; i++)
{
scb = p->scb_data->scb_array[i];
if (scb->flags & SCB_QUEUED_FOR_DONE)
{
-#ifdef AIC7XXX_DEBUG_ABORT
- printk("(scsi%d:%d:%d) Aborting scb %d\n",
- p->host_no, TC_OF_SCB(scb), scb->hscb->tag);
-#endif
+ if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
+ printk(INFO_LEAD "Aborting scb %d\n",
+ p->host_no, CTL_OF_SCB(scb), scb->hscb->tag);
+ found++;
aic7xxx_done(p, scb);
}
}
+ if (aic7xxx_verbose & (VERBOSE_ABORT_RETURN | VERBOSE_RESET_RETURN))
+ {
+ printk(INFO_LEAD "%d commands found and queued for "
+ "completion.\n", p->host_no, -1, -1, -1, found);
+ }
if (complete)
{
aic7xxx_done_cmds_complete(p);
@@ -2119,14 +2448,9 @@ aic7xxx_abort_waiting_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb,
/*
* Select the SCB we want to abort and pull the next pointer out of it.
*/
- curscb = inb(p->base + SCBPTR);
- outb(scbpos, p->base + SCBPTR);
- next = inb(p->base + SCB_NEXT);
-
- /*
- * Clear the necessary fields
- */
- outb(0, p->base + SCB_CONTROL);
+ curscb = aic_inb(p, SCBPTR);
+ aic_outb(p, scbpos, SCBPTR);
+ next = aic_inb(p, SCB_NEXT);
aic7xxx_add_curscb_to_free_list(p);
@@ -2138,25 +2462,21 @@ aic7xxx_abort_waiting_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb,
/*
* First in the list
*/
- outb(next, p->base + WAITING_SCBH);
+ aic_outb(p, next, WAITING_SCBH);
}
else
{
/*
* Select the scb that pointed to us and update its next pointer.
*/
- outb(prev, p->base + SCBPTR);
- outb(next, p->base + SCB_NEXT);
+ aic_outb(p, prev, SCBPTR);
+ aic_outb(p, next, SCB_NEXT);
}
/*
* Point us back at the original scb position and inform the SCSI
* system that the command has been aborted.
*/
- outb(curscb, p->base + SCBPTR);
- scb->flags |= SCB_ABORTED | SCB_QUEUED_FOR_DONE;
- scb->flags &= ~SCB_ACTIVE;
- scb->cmd->result = (DID_RESET << 16);
-
+ aic_outb(p, curscb, SCBPTR);
return (next);
}
@@ -2169,219 +2489,381 @@ aic7xxx_abort_waiting_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb,
* requeue. Returns the number of matching SCBs.
*-F*************************************************************************/
static int
-aic7xxx_search_qinfifo(struct aic7xxx_host *p, int target, char channel,
- int lun, unsigned char tag, int flags, int requeue)
+aic7xxx_search_qinfifo(struct aic7xxx_host *p, int target, int channel,
+ int lun, unsigned char tag, int flags, int requeue,
+ volatile scb_queue_type *queue)
{
- unsigned char saved_queue[AIC7XXX_MAXSCB];
- int queued = inb(p->base + QINCNT) & p->qcntmask;
- int i;
int found;
+ unsigned char qinpos, qintail;
struct aic7xxx_scb *scbp;
- scb_queue_type removed_scbs;
found = 0;
- scbq_init (&removed_scbs);
- for (i = 0; i < (queued - found); i++)
+ qinpos = aic_inb(p, QINPOS);
+ qintail = p->qinfifonext;
+
+ p->qinfifonext = qinpos;
+
+ while (qinpos != qintail)
{
- saved_queue[i] = inb(p->base + QINFIFO);
- scbp = p->scb_data->scb_array[saved_queue[i]];
- if (aic7xxx_match_scb(scbp, target, channel, lun, tag))
+ scbp = p->scb_data->scb_array[p->qinfifo[qinpos++]];
+ if (aic7xxx_match_scb(p, scbp, target, channel, lun, tag))
{
/*
* We found an scb that needs to be removed.
*/
- if (requeue)
+ if (requeue && (queue != NULL))
{
- scbq_insert_head(&removed_scbs, scbp);
+ if ( !(scbp->flags & SCB_WAITINGQ) )
+ {
+ scbq_insert_tail(queue, scbp);
+ p->dev_active_cmds[TARGET_INDEX(scbp->cmd)]--;
+ p->activescbs--;
+ scbp->flags |= SCB_WAITINGQ;
+ }
+ if ( !(scbp->tag_action & TAG_ENB) )
+ {
+ aic7xxx_index_busy_target(p, scbp->hscb->target_channel_lun,
+ TRUE);
+ }
+ }
+ else if (requeue)
+ {
+ p->qinfifo[p->qinfifonext++] = scbp->hscb->tag;
}
else
{
- scbp->flags = flags;
- scbp->flags &= ~SCB_ACTIVE;
- /*
- * XXX - Don't know what error to use here.
- */
- aic7xxx_error(scbp->cmd) = DID_RESET;
+ /*
+ * Preserve any SCB_RECOVERY_SCB flags on this scb then set the
+ * flags we were called with, presumeably so aic7xxx_run_done_queue
+ * can find this scb
+ */
+ scbp->flags = flags | (scbp->flags & SCB_RECOVERY_SCB);
+ if (aic7xxx_index_busy_target(p, scbp->hscb->target_channel_lun,
+ FALSE) == scbp->hscb->tag)
+ {
+ aic7xxx_index_busy_target(p, scbp->hscb->target_channel_lun,
+ TRUE);
+ }
}
- i--;
found++;
}
- }
- /* Now put the saved scbs back. */
- for (queued = 0; queued < i; queued++)
- outb(saved_queue[queued], p->base + QINFIFO);
-
- if (requeue)
- {
- scbp = removed_scbs.head;
- while (scbp != NULL)
+ else
{
- scbq_remove_head(&removed_scbs);
- /*
- * XXX - Shouldn't we be adding this to the free list?
- */
- scbq_insert_head(&p->waiting_scbs, scbp);
- scbp->flags |= SCB_WAITINGQ;
- scbp = removed_scbs.head;
+ p->qinfifo[p->qinfifonext++] = scbp->hscb->tag;
}
}
+ /*
+ * Now that we've done the work, clear out any left over commands in the
+ * qinfifo and update the KERNEL_QINPOS down on the card.
+ *
+ * NOTE: This routine expect the sequencer to already be paused when
+ * it is run....make sure it's that way!
+ */
+ qinpos = p->qinfifonext;
+ while(qinpos != qintail)
+ {
+ p->qinfifo[qinpos++] = SCB_LIST_NULL;
+ }
+ aic_outb(p, p->qinfifonext, KERNEL_QINPOS);
return (found);
}
/*+F*************************************************************************
* Function:
+ * aic7xxx_scb_on_qoutfifo
+ *
+ * Description:
+ * Is the scb that was passed to us currently on the qoutfifo?
+ *-F*************************************************************************/
+static int
+aic7xxx_scb_on_qoutfifo(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
+{
+ int i=0;
+
+ while(p->qoutfifo[(p->qoutfifonext + i) & 0xff ] != SCB_LIST_NULL)
+ {
+ if(p->qoutfifo[(p->qoutfifonext + i) & 0xff ] == scb->hscb->tag)
+ return TRUE;
+ else
+ i++;
+ }
+ return FALSE;
+}
+
+
+/*+F*************************************************************************
+ * Function:
* aic7xxx_reset_device
*
* Description:
* The device at the given target/channel has been reset. Abort
- * all active and queued scbs for that target/channel.
+ * all active and queued scbs for that target/channel. This function
+ * need not worry about linked next pointers because if was a MSG_ABORT_TAG
+ * then we had a tagged command (no linked next), if it was MSG_ABORT or
+ * MSG_BUS_DEV_RESET then the device won't know about any commands any more
+ * and no busy commands will exist, and if it was a bus reset, then nothing
+ * knows about any linked next commands any more. In all cases, we don't
+ * need to worry about the linked next or busy scb, we just need to clear
+ * them.
*-F*************************************************************************/
-static int
-aic7xxx_reset_device(struct aic7xxx_host *p, int target, char channel,
+static void
+aic7xxx_reset_device(struct aic7xxx_host *p, int target, int channel,
int lun, unsigned char tag)
{
struct aic7xxx_scb *scbp;
- unsigned char active_scb;
- int i = 0;
- int found;
+ unsigned char active_scb, tcl;
+ int i = 0, j, init_lists = FALSE;
/*
* Restore this when we're done
*/
- active_scb = inb(p->base + SCBPTR);
-
-#ifdef AIC7XXX_DEBUG_ABORT
- printk("(scsi%d:%d:%d) Reset device, active_scb %d\n",
- p->host_no, target, CHAN_TO_INT(channel), active_scb);
-#endif
+ active_scb = aic_inb(p, SCBPTR);
+ if (aic7xxx_verbose & (VERBOSE_RESET_PROCESS | VERBOSE_ABORT_PROCESS))
+ printk(INFO_LEAD "Reset device, active_scb %d\n",
+ p->host_no, channel, target, lun, active_scb);
/*
* Deal with the busy target and linked next issues.
*/
{
int min_target, max_target;
- unsigned char busy_scbid;
+ struct aic7xxx_scb *scbp, *prev_scbp;
/* Make all targets 'relative' to bus A. */
if (target == ALL_TARGETS)
{
switch (channel)
{
- case 'A':
- min_target = 0;
- max_target = (p->bus_type == AIC_SINGLE) ? 7 : 15;
- break;
- case 'B':
- min_target = 8;
- max_target = 15;
- break;
+ case 0:
+ min_target = 0;
+ max_target = (p->type & AHC_WIDE) ? 15 : 7;
+ break;
+ case 1:
+ min_target = 8;
+ max_target = 15;
+ break;
case ALL_CHANNELS:
default:
- min_target = 0;
- max_target = (p->bus_type == AIC_SINGLE) ? 7 : 15;
- break;
+ min_target = 0;
+ max_target = (p->type & (AHC_TWIN|AHC_WIDE)) ? 15 : 7;
+ break;
}
}
else
{
- min_target = target + channel == 'B' ? 8 : 0;
+ min_target = target | (channel << 3);
max_target = min_target;
}
+
for (i = min_target; i <= max_target; i++)
{
- busy_scbid = aic7xxx_index_busy_target(p, i, 'A', /*unbusy*/FALSE);
- if (busy_scbid < p->scb_data->numscbs)
+ if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
+ printk(INFO_LEAD "Cleaning up status information "
+ "and delayed_scbs.\n", p->host_no, channel, i, lun);
+ if ( !(p->dev_flags[i] & DEVICE_TAGGED_SUCCESS) &&
+ (p->dev_active_cmds[i]) &&
+ (p->tagenable & (0x01 << i)) )
{
- struct aic7xxx_scb *busy_scb;
- struct aic7xxx_scb *next_scb;
- unsigned char next_scbid;
-
- busy_scb = p->scb_data->scb_array[busy_scbid];
-
- next_scbid = busy_scb->hscb->data_count >> 24;
-
- if (next_scbid == SCB_LIST_NULL)
+ printk(INFO_LEAD "Device appears to be choking on tagged commands.\n",
+ p->host_no, channel, i, lun);
+ printk(INFO_LEAD "Will use untagged I/O instead.\n", p->host_no,
+ channel, i, lun);
+ p->dev_max_queue_depth[i] = 1;
+ p->dev_temp_queue_depth[i] = 1;
+ p->tagenable &= ~(0x01 << i);
+ p->orderedtag &= ~(0x01 << i);
+ }
+ p->dev_flags[i] &= ~BUS_DEVICE_RESET_PENDING;
+ if ( tag == SCB_LIST_NULL )
+ {
+ p->dev_flags[i] |= DEVICE_PRINT_WDTR | DEVICE_PRINT_SDTR;
+ p->dev_last_reset[i] = jiffies;
+ p->dev_last_queue_full_count[i] = 0;
+ p->dev_last_queue_full[i] = 0;
+ p->dev_temp_queue_depth[i] =
+ p->dev_max_queue_depth[i];
+ /*
+ * In case this isn't a full bus reset, we want to add a 4 second timer in
+ * here so that we can delay all re-sent commands for this device for the
+ * 4 seconds and then have our timer routine pick them back up.
+ */
+ if( (p->dev_timer[i].prev != NULL) ||
+ (p->dev_timer[i].next != NULL) )
{
- busy_scbid = aic7xxx_find_scb(p, busy_scb);
-
- if (busy_scbid != SCB_LIST_NULL)
- {
- outb(busy_scbid, p->base + SCBPTR);
- next_scbid = inb(p->base + SCB_LINKED_NEXT);
- }
- }
-
- if (aic7xxx_match_scb(busy_scb, target, channel, lun, tag))
+ del_timer(&p->dev_timer[i]);
+ }
+ p->dev_timer[i].expires = jiffies + (3 * HZ);
+ add_timer(&p->dev_timer[i]);
+ }
+ for(j=0; j<MAX_LUNS; j++)
+ {
+ if (channel == 1)
+ tcl = ((i << 4) & 0x70) | (channel << 3) | j;
+ else
+ tcl = (i << 4) | (channel << 3) | j;
+ if ( (aic7xxx_index_busy_target(p, tcl, FALSE) == tag) ||
+ (tag == SCB_LIST_NULL) )
+ aic7xxx_index_busy_target(p, tcl, /* unbusy */ TRUE);
+ }
+ j = 0;
+ prev_scbp = NULL;
+ scbp = p->delayed_scbs[i].head;
+ while ( (scbp != NULL) && (j++ <= p->scb_data->numscbs) )
+ {
+ prev_scbp = scbp;
+ scbp = scbp->q_next;
+ if ( prev_scbp == scbp )
{
- aic7xxx_index_busy_target(p, i, 'A', /*unbusy*/TRUE);
- }
-
- if (next_scbid != SCB_LIST_NULL)
+ if (aic7xxx_verbose & (VERBOSE_ABORT | VERBOSE_RESET))
+ printk(WARN_LEAD "Yikes!! scb->q_next == scb "
+ "in the delayed_scbs queue!\n", p->host_no, channel, i, lun);
+ scbp = NULL;
+ prev_scbp->q_next = NULL;
+ p->delayed_scbs[i].tail = prev_scbp;
+ }
+ if (aic7xxx_match_scb(p, prev_scbp, target, channel, lun, tag))
{
- next_scb = p->scb_data->scb_array[next_scbid];
- if (aic7xxx_match_scb(next_scb, target, channel, lun, tag))
+ scbq_remove(&p->delayed_scbs[i], prev_scbp);
+ if ( !(prev_scbp->flags & SCB_QUEUED_ABORT) )
{
- continue;
+ p->dev_active_cmds[i]++;
+ p->activescbs++;
}
- /* Requeue for later processing */
- scbq_insert_head(&p->waiting_scbs, next_scb);
- next_scb->flags |= SCB_WAITINGQ;
- }
+ prev_scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ);
+ prev_scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
+ }
+ }
+ if ( j > p->scb_data->numscbs )
+ {
+ if (aic7xxx_verbose & (VERBOSE_ABORT | VERBOSE_RESET))
+ printk(WARN_LEAD "Yikes!! There's a loop in the "
+ "delayed_scbs queue!\n", p->host_no, channel, i, lun);
+ scbq_init(&p->delayed_scbs[i]);
+ }
+ if ( (p->delayed_scbs[i].head == NULL) &&
+ (p->dev_timer[i].expires) )
+ {
+ del_timer(&p->dev_timer[i]);
+ p->dev_timer[i].expires = 0;
+ }
+ }
+ }
+
+ if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
+ printk(INFO_LEAD "Cleaning QINFIFO.\n", p->host_no, channel, target, lun );
+ aic7xxx_search_qinfifo(p, target, channel, lun, tag,
+ SCB_RESET | SCB_QUEUED_FOR_DONE, /* requeue */ FALSE, NULL);
+
+/*
+ * Search the waiting_scbs queue for matches, this catches any SCB_QUEUED
+ * ABORT/RESET commands.
+ */
+ if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
+ printk(INFO_LEAD "Cleaning waiting_scbs.\n", p->host_no, channel,
+ target, lun );
+ {
+ struct aic7xxx_scb *scbp, *prev_scbp;
+
+ j = 0;
+ prev_scbp = NULL;
+ scbp = p->waiting_scbs.head;
+ while ( (scbp != NULL) && (j++ <= p->scb_data->numscbs) )
+ {
+ prev_scbp = scbp;
+ scbp = scbp->q_next;
+ if ( prev_scbp == scbp )
+ {
+ if (aic7xxx_verbose & (VERBOSE_ABORT | VERBOSE_RESET))
+ printk(WARN_LEAD "Yikes!! scb->q_next == scb "
+ "in the waiting_scbs queue!\n", p->host_no, CTL_OF_SCB(scbp));
+ scbp = NULL;
+ prev_scbp->q_next = NULL;
+ p->waiting_scbs.tail = prev_scbp;
}
+ if (aic7xxx_match_scb(p, prev_scbp, target, channel, lun, tag))
+ {
+ scbq_remove(&p->waiting_scbs, prev_scbp);
+ if ( !(prev_scbp->flags & SCB_QUEUED_ABORT) )
+ {
+ p->dev_active_cmds[TARGET_INDEX(prev_scbp->cmd)]++;
+ p->activescbs++;
+ }
+ prev_scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ);
+ prev_scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
+ }
+ }
+ if ( j > p->scb_data->numscbs )
+ {
+ if (aic7xxx_verbose & (VERBOSE_ABORT | VERBOSE_RESET))
+ printk(WARN_LEAD "Yikes!! There's a loop in the "
+ "waiting_scbs queue!\n", p->host_no, channel, target, lun);
+ scbq_init(&p->waiting_scbs);
}
}
- found = aic7xxx_search_qinfifo(p, target, channel, lun, tag,
- SCB_ABORTED | SCB_QUEUED_FOR_DONE, /* requeue */ FALSE);
/*
* Search waiting for selection list.
*/
+ if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
+ printk(INFO_LEAD "Cleaning waiting for selection "
+ "list.\n", p->host_no, channel, target, lun);
{
unsigned char next, prev, scb_index;
- next = inb(p->base + WAITING_SCBH); /* Start at head of list. */
+ next = aic_inb(p, WAITING_SCBH); /* Start at head of list. */
prev = SCB_LIST_NULL;
-
- while (next != SCB_LIST_NULL)
+ j = 0;
+ while ( (next != SCB_LIST_NULL) && (j++ <= p->scb_data->maxhscbs) )
{
- outb(next, p->base + SCBPTR);
- scb_index = inb(p->base + SCB_TAG);
+ aic_outb(p, next, SCBPTR);
+ scb_index = aic_inb(p, SCB_TAG);
if (scb_index >= p->scb_data->numscbs)
{
- panic("aic7xxx: Waiting List inconsistency; SCB index=%d, numscbs=%d\n",
- scb_index, p->scb_data->numscbs);
+ /*
+ * No aic7xxx_verbose check here.....we want to see this since it
+ * means either the kernel driver or the sequencer screwed things up
+ */
+ printk(WARN_LEAD "Waiting List inconsistency; SCB index=%d, "
+ "numscbs=%d\n", p->host_no, channel, target, lun, scb_index,
+ p->scb_data->numscbs);
+ next = aic_inb(p, SCB_NEXT);
+ aic7xxx_add_curscb_to_free_list(p);
}
- scbp = p->scb_data->scb_array[scb_index];
- if (aic7xxx_match_scb(scbp, target, channel, lun, tag))
+ else
{
- unsigned char linked_next;
-
- next = aic7xxx_abort_waiting_scb(p, scbp, next, prev);
- linked_next = inb(p->base + SCB_LINKED_NEXT);
- if (linked_next != SCB_LIST_NULL)
+ scbp = p->scb_data->scb_array[scb_index];
+ if (aic7xxx_match_scb(p, scbp, target, channel, lun, tag))
{
- struct aic7xxx_scb *next_scb;
- /*
- * Requeue the waiting SCB via the waiting list.
- */
- next_scb = p->scb_data->scb_array[linked_next];
- if (! aic7xxx_match_scb(next_scb, target, channel, lun, tag))
+ next = aic7xxx_abort_waiting_scb(p, scbp, next, prev);
+ scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ);
+ scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
+ if (prev == SCB_LIST_NULL)
{
- scbq_insert_head(&p->waiting_scbs, next_scb);
- next_scb->flags |= SCB_WAITINGQ;
+ /*
+ * This is either the first scb on the waiting list, or we
+ * have already yanked the first and haven't left any behind.
+ * Either way, we need to turn off the selection hardware if
+ * it isn't already off.
+ */
+ aic_outb(p, aic_inb(p, SCSISEQ) & ~ENSELO, SCSISEQ);
}
}
- found++;
- }
- else
- {
- prev = next;
- next = inb(p->base + SCB_NEXT);
+ else
+ {
+ prev = next;
+ next = aic_inb(p, SCB_NEXT);
+ }
}
}
+ if ( j > p->scb_data->maxhscbs )
+ {
+ printk(WARN_LEAD "Yikes!! There is a loop in the waiting for "
+ "selection list!\n", p->host_no, channel, target, lun);
+ init_lists = TRUE;
+ }
}
/*
@@ -2391,47 +2873,114 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, char channel,
{
unsigned char next, prev, scb_index;
- next = inb(p->base + DISCONNECTED_SCBH);
+ next = aic_inb(p, DISCONNECTED_SCBH);
prev = SCB_LIST_NULL;
-
- while (next != SCB_LIST_NULL)
+ j = 0;
+ while ( (next != SCB_LIST_NULL) && (j++ <= p->scb_data->maxhscbs) )
{
- outb(next, p->base + SCBPTR);
- scb_index = inb(p->base + SCB_TAG);
+ aic_outb(p, next, SCBPTR);
+ scb_index = aic_inb(p, SCB_TAG);
if (scb_index > p->scb_data->numscbs)
{
- panic("aic7xxx: Disconnected List inconsistency, SCB index = %d, "
- "num scbs = %d.\n", scb_index, p->scb_data->numscbs);
+ printk(WARN_LEAD "Waiting List inconsistency; SCB index=%d, "
+ "numscbs=%d\n", p->host_no, channel, target, lun, scb_index,
+ p->scb_data->numscbs);
+ next = aic7xxx_rem_scb_from_disc_list(p, next);
}
- scbp = p->scb_data->scb_array[scb_index];
- if (aic7xxx_match_scb(scbp, target, channel, lun, tag))
+ else
{
- next = aic7xxx_rem_scb_from_disc_list(p, next);
+ scbp = p->scb_data->scb_array[scb_index];
+ if (aic7xxx_match_scb(p, scbp, target, channel, lun, tag))
+ {
+ next = aic7xxx_rem_scb_from_disc_list(p, next);
+ scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ);
+ scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
+ scbp->hscb->control = 0;
+ }
+ else
+ {
+ prev = next;
+ next = aic_inb(p, SCB_NEXT);
+ }
+ }
+ }
+ if ( j > p->scb_data->maxhscbs )
+ {
+ printk(WARN_LEAD "Yikes!! There is a loop in the disconnected list!\n",
+ p->host_no, channel, target, lun);
+ init_lists = TRUE;
+ }
+ }
+
+ /*
+ * Walk the free list making sure no entries on the free list have
+ * a valid SCB_TAG value or SCB_CONTROL byte.
+ */
+ {
+ unsigned char next;
+
+ j = 0;
+ next = aic_inb(p, FREE_SCBH);
+ while ( (next != SCB_LIST_NULL) && (j++ < p->scb_data->maxhscbs) )
+ {
+ aic_outb(p, next, SCBPTR);
+ if ( aic_inb(p, SCB_TAG) < p->scb_data->numscbs )
+ {
+ printk(WARN_LEAD "Free list inconsistency!.\n", p->host_no, channel,
+ target, lun);
+ init_lists = TRUE;
+ next = SCB_LIST_NULL;
}
else
{
- prev = next;
- next = inb(p->base + SCB_NEXT);
+ aic_outb(p, SCB_LIST_NULL, SCB_TAG);
+ aic_outb(p, 0, SCB_CONTROL);
+ next = aic_inb(p, SCB_NEXT);
}
}
+ if ( j > p->scb_data->maxhscbs )
+ {
+ printk(WARN_LEAD "Yikes!! There is a loop in the free list!\n",
+ p->host_no, channel, target, lun);
+ init_lists = TRUE;
+ }
}
/*
* Go through the hardware SCB array looking for commands that
* were active but not on any list.
*/
- for (i = 0; i < p->scb_data->maxhscbs; i++)
+ if (init_lists)
+ {
+ aic_outb(p, SCB_LIST_NULL, FREE_SCBH);
+ aic_outb(p, SCB_LIST_NULL, WAITING_SCBH);
+ aic_outb(p, SCB_LIST_NULL, DISCONNECTED_SCBH);
+ }
+ for (i = p->scb_data->maxhscbs; i >= 0; --i)
{
unsigned char scbid;
- outb(i, p->base + SCBPTR);
- scbid = inb(p->base + SCB_TAG);
- if (scbid < p->scb_data->numscbs)
+ aic_outb(p, i, SCBPTR);
+ if (init_lists)
+ {
+ aic_outb(p, SCB_LIST_NULL, SCB_TAG);
+ aic_outb(p, SCB_LIST_NULL, SCB_NEXT);
+ aic_outb(p, SCB_LIST_NULL, SCB_PREV);
+ aic_outb(p, 0, SCB_CONTROL);
+ aic7xxx_add_curscb_to_free_list(p);
+ }
+ else
{
- scbp = p->scb_data->scb_array[scbid];
- if (aic7xxx_match_scb(scbp, target, channel, lun, tag))
+ scbid = aic_inb(p, SCB_TAG);
+ if (scbid < p->scb_data->numscbs)
{
- aic7xxx_add_curscb_to_free_list(p);
+ scbp = p->scb_data->scb_array[scbid];
+ if (aic7xxx_match_scb(p, scbp, target, channel, lun, tag))
+ {
+ aic_outb(p, 0, SCB_CONTROL);
+ aic_outb(p, SCB_LIST_NULL, SCB_TAG);
+ aic7xxx_add_curscb_to_free_list(p);
+ }
}
}
}
@@ -2440,31 +2989,28 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, char channel,
* Go through the entire SCB array now and look for commands for
* for this target that are stillactive. These are other (most likely
* tagged) commands that were disconnected when the reset occurred.
+ * Any commands we find here we know this about, it wasn't on any queue,
+ * it wasn't in the qinfifo, it wasn't in the disconnected or waiting
+ * lists, so it really must have been a paged out SCB. In that case,
+ * we shouldn't need to bother with updating any counters, just mark
+ * the correct flags and go on.
*/
for (i = 0; i < p->scb_data->numscbs; i++)
{
scbp = p->scb_data->scb_array[i];
- if (((scbp->flags & SCB_ACTIVE) != 0) &&
- aic7xxx_match_scb(scbp, target, channel, lun, tag))
+ if ((scbp->flags & SCB_ACTIVE) &&
+ aic7xxx_match_scb(p, scbp, target, channel, lun, tag) &&
+ !aic7xxx_scb_on_qoutfifo(p, scbp))
{
- scbp->flags |= SCB_ABORTED | SCB_QUEUED_FOR_DONE;
- scbp->flags &= ~SCB_ACTIVE;
- aic7xxx_error(scbp->cmd) = DID_RESET;
-
- found++;
-
- if ((scbp->flags & SCB_WAITINGQ) != 0)
- {
- scbq_remove(&p->waiting_scbs, scbp);
- scbp->flags &= ~SCB_WAITINGQ;
- }
+ scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
+ scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ);
}
}
- outb(active_scb, p->base + SCBPTR);
- return (found);
+ aic_outb(p, active_scb, SCBPTR);
}
+
/*+F*************************************************************************
* Function:
* aic7xxx_clear_intstat
@@ -2476,10 +3022,10 @@ static void
aic7xxx_clear_intstat(struct aic7xxx_host *p)
{
/* Clear any interrupt conditions this may have caused. */
- outb(CLRSELDO | CLRSELDI | CLRSELINGO, p->base + CLRSINT0);
- outb(CLRSELTIMEO | CLRATNO | CLRSCSIRSTI | CLRBUSFREE | CLRSCSIPERR |
- CLRPHASECHG | CLRREQINIT, p->base + CLRSINT1);
- outb(CLRSCSIINT, p->base + CLRINT);
+ aic_outb(p, CLRSELDO | CLRSELDI | CLRSELINGO, CLRSINT0);
+ aic_outb(p, CLRSELTIMEO | CLRATNO | CLRSCSIRSTI | CLRBUSFREE | CLRSCSIPERR |
+ CLRPHASECHG | CLRREQINIT, CLRSINT1);
+ aic_outb(p, CLRSCSIINT | CLRSEQINT | CLRBRKADRINT, CLRINT);
}
/*+F*************************************************************************
@@ -2495,21 +3041,21 @@ aic7xxx_reset_current_bus(struct aic7xxx_host *p)
unsigned char scsiseq;
/* Disable reset interrupts. */
- outb(inb(p->base + SIMODE1) & ~ENSCSIRST, p->base + SIMODE1);
+ aic_outb(p, aic_inb(p, SIMODE1) & ~ENSCSIRST, SIMODE1);
/* Turn on the bus reset. */
- scsiseq = inb(p->base + SCSISEQ);
- outb(scsiseq | SCSIRSTO, p->base + SCSISEQ);
+ scsiseq = aic_inb(p, SCSISEQ);
+ aic_outb(p, scsiseq | SCSIRSTO, SCSISEQ);
udelay(1000);
/* Turn off the bus reset. */
- outb(scsiseq & ~SCSIRSTO, p->base + SCSISEQ);
+ aic_outb(p, scsiseq & ~SCSIRSTO, SCSISEQ);
aic7xxx_clear_intstat(p);
/* Re-enable reset interrupts. */
- outb(inb(p->base + SIMODE1) | ENSCSIRST, p->base + SIMODE1);
+ aic_outb(p, aic_inb(p, SIMODE1) | ENSCSIRST, SIMODE1);
udelay(1000);
}
@@ -2521,22 +3067,19 @@ aic7xxx_reset_current_bus(struct aic7xxx_host *p)
* Description:
* Reset the channel.
*-F*************************************************************************/
-static int
-aic7xxx_reset_channel(struct aic7xxx_host *p, char channel, int initiate_reset)
+static void
+aic7xxx_reset_channel(struct aic7xxx_host *p, int channel, int initiate_reset)
{
unsigned long offset, offset_max;
- int found;
unsigned char sblkctl;
- char cur_channel;
+ int cur_channel;
+
+ if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+ printk(INFO_LEAD "Reset channel called, %s initiate reset.\n",
+ p->host_no, channel, -1, -1, (initiate_reset==TRUE) ? "will" : "won't" );
- pause_sequencer(p);
- /*
- * Clean up all the state information for the pending transactions
- * on this bus.
- */
- found = aic7xxx_reset_device(p, ALL_TARGETS, channel, ALL_LUNS, SCB_LIST_NULL);
- if (channel == 'B')
+ if (channel == 1)
{
p->needsdtr |= (p->needsdtr_copy & 0xFF00);
p->sdtr_pending &= 0x00FF;
@@ -2545,7 +3088,7 @@ aic7xxx_reset_channel(struct aic7xxx_host *p, char channel, int initiate_reset)
}
else
{
- if (p->bus_type == AIC_WIDE)
+ if (p->type & AHC_WIDE)
{
p->needsdtr = p->needsdtr_copy;
p->needwdtr = p->needwdtr_copy;
@@ -2571,80 +3114,77 @@ aic7xxx_reset_channel(struct aic7xxx_host *p, char channel, int initiate_reset)
*/
u_char targ_scratch;
- targ_scratch = inb(p->base + offset);
+ targ_scratch = aic_inb(p, offset);
targ_scratch &= SXFR;
- outb(targ_scratch, p->base + offset);
- offset++;
+ aic_outb(p, targ_scratch, offset++);
}
/*
* Reset the bus and unpause/restart the controller
*/
- sblkctl = inb(p->base + SBLKCTL);
- cur_channel = (sblkctl & SELBUSB) ? 'B' : 'A';
+ sblkctl = aic_inb(p, SBLKCTL);
+ cur_channel = (sblkctl & SELBUSB) >> 3;
if (cur_channel != channel)
{
/*
* Case 1: Command for another bus is active
*/
-#ifdef AIC7XXX_DEBUG_ABORT
- printk("scsi%d: Stealthily resetting channel %c\n",
- p->host_no, channel);
-#endif
+ if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+ printk(INFO_LEAD "Stealthily resetting idle channel.\n", p->host_no,
+ channel, -1, -1);
/*
* Stealthily reset the other bus without upsetting the current bus.
*/
- outb(sblkctl ^ SELBUSB, p->base + SBLKCTL);
- outb(inb(p->base + SIMODE1) & ~ENBUSFREE, p->base + SIMODE1);
+ aic_outb(p, sblkctl ^ SELBUSB, SBLKCTL);
+ aic_outb(p, aic_inb(p, SIMODE1) & ~ENBUSFREE, SIMODE1);
if (initiate_reset)
{
aic7xxx_reset_current_bus(p);
- /*
- * Cause the mid-level SCSI code to delay any further
- * queueing by the bus settle time for us.
- */
- p->host->last_reset = (jiffies + (AIC7XXX_RESET_DELAY * HZ));
}
- outb(0, p->base + SCSISEQ);
+ aic_outb(p, 0, SCSISEQ);
aic7xxx_clear_intstat(p);
- outb(sblkctl, p->base + SBLKCTL);
- unpause_sequencer(p, /* unpause_always */ FALSE);
+ aic_outb(p, sblkctl, SBLKCTL);
}
else
{
/*
* Case 2: A command from this bus is active or we're idle.
*/
-#ifdef AIC7XXX_DEBUG_ABORT
- printk("scsi%d: Resetting current channel %c\n",
- p->host_no, channel);
-#endif
- outb(inb(p->base + SIMODE1) & ~ENBUSFREE, p->base + SIMODE1);
+ if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+ printk(INFO_LEAD "Resetting currently active channel.\n", p->host_no,
+ channel, -1, -1);
+ aic_outb(p, aic_inb(p, SIMODE1) & ~(ENBUSFREE|ENREQINIT),
+ SIMODE1);
+ p->flags &= ~AHC_HANDLING_REQINITS;
+ p->msg_type = MSG_TYPE_NONE;
+ p->msg_len = 0;
if (initiate_reset)
{
aic7xxx_reset_current_bus(p);
- /*
- * Cause the mid-level SCSI code to delay any further
- * queueing by the bus settle time for us.
- */
-#if 0
- p->host->last_reset = (jiffies + (AIC7XXX_RESET_DELAY * HZ));
-#endif
}
- outb(0, p->base + SCSISEQ);
+ aic_outb(p, 0, SCSISEQ);
aic7xxx_clear_intstat(p);
+ }
+ if (aic7xxx_verbose & VERBOSE_RESET_RETURN)
+ printk(INFO_LEAD "Channel reset\n", p->host_no, channel, -1, -1);
+ /*
+ * Clean up all the state information for the pending transactions
+ * on this bus.
+ */
+ aic7xxx_reset_device(p, ALL_TARGETS, channel, ALL_LUNS, SCB_LIST_NULL);
+
+ if ( !(p->type & AHC_TWIN) )
+ {
restart_sequencer(p);
-#ifdef AIC7XXX_DEBUG_ABORT
- printk("scsi%d: Channel reset, sequencer restarted\n", p->host_no);
-#endif
}
/*
* Now loop through all the SCBs that have been marked for abortion,
* and call the scsi_done routines.
*/
- aic7xxx_run_done_queue(p, /*complete*/ TRUE);
- return (found);
+ if(!(p->flags & AHC_IN_ISR))
+ aic7xxx_run_done_queue(p, /*complete*/ TRUE);
+ return;
}
/*+F*************************************************************************
@@ -2659,47 +3199,108 @@ static inline void
aic7xxx_run_waiting_queues(struct aic7xxx_host *p)
{
struct aic7xxx_scb *scb;
+ int tindex;
+ int sent;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+ unsigned long cpu_flags = 0;
+#endif
+
if (p->waiting_scbs.head == NULL)
return;
- pause_sequencer(p);
+ sent = 0;
+
/*
* First handle SCBs that are waiting but have been assigned a slot.
*/
- scb = p->waiting_scbs.head;
- while (scb != NULL)
+ DRIVER_LOCK
+ while ((scb = scbq_remove_head(&p->waiting_scbs)) != NULL)
{
- if (p->curqincnt >= p->qfullcount)
+ tindex = TARGET_INDEX(scb->cmd);
+ if ( (p->dev_active_cmds[tindex] >=
+ p->dev_temp_queue_depth[tindex]) ||
+ (p->dev_last_reset[tindex] >= (jiffies + (3 * HZ))) )
{
- p->curqincnt = inb(p->base + QINCNT) & p->qcntmask;
- if (p->curqincnt >= p->qfullcount)
- {
- break;
- }
+ scbq_insert_tail(&p->delayed_scbs[tindex], scb);
+ }
+ else
+ {
+ scb->flags &= ~SCB_WAITINGQ;
+ if ( !(scb->flags & SCB_QUEUED_ABORT) )
+ {
+ p->dev_active_cmds[tindex]++;
+ p->activescbs++;
+ }
+ if ( !(scb->tag_action) )
+ {
+ aic7xxx_busy_target(p, scb);
+ }
+ p->qinfifo[p->qinfifonext++] = scb->hscb->tag;
+ sent++;
+ }
+ }
+ if (sent)
+ {
+ if(p->type & AHC_AIC78x0)
+ aic_outb(p, p->qinfifonext, KERNEL_QINPOS);
+ else
+ {
+ pause_sequencer(p);
+ aic_outb(p, p->qinfifonext, KERNEL_QINPOS);
+ unpause_sequencer(p, FALSE);
}
+ if (p->activescbs > p->max_activescbs)
+ p->max_activescbs = p->activescbs;
+ }
+ DRIVER_UNLOCK
+}
- /*
- * We have some space.
- */
- scbq_remove_head(&(p->waiting_scbs));
- scb->flags &= ~SCB_WAITINGQ;
- outb(scb->hscb->tag, p->base + QINFIFO);
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_timer
+ *
+ * Description:
+ * Take expired extries off of delayed queues and place on waiting queue
+ * then run waiting queue to start commands.
+ ***************************************************************************/
+static void
+aic7xxx_timer(struct aic7xxx_host *p)
+{
+ int i;
+ unsigned long cpu_flags = 0;
+ struct aic7xxx_scb *scb;
- if ((p->flags & PAGE_ENABLED) != 0)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+ DRIVER_LOCK
+#else
+ spin_lock_irqsave(&io_request_lock, cpu_flags);
+#endif
+ for(i=0; i<MAX_TARGETS; i++)
+ {
+ if ( (p->dev_timer[i].expires) &&
+ (p->dev_timer[i].expires <= jiffies) )
{
- /*
- * We only care about this statistic when paging
- * since it's impossible to overflow the qinfifo
- * in the non-paging case.
- */
- p->curqincnt++;
+ p->dev_timer[i].expires = 0;
+ if ( (p->dev_timer[i].prev != NULL) ||
+ (p->dev_timer[i].next != NULL) )
+ {
+ del_timer(&p->dev_timer[i]);
+ }
+ p->dev_temp_queue_depth[i] = p->dev_max_queue_depth[i];
+ while ( (scb = scbq_remove_head(&p->delayed_scbs[i])) != NULL )
+ {
+ scbq_insert_tail(&p->waiting_scbs, scb);
+ }
}
- scb = p->waiting_scbs.head;
}
-
- unpause_sequencer(p, FALSE);
+ aic7xxx_run_waiting_queues(p);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+ DRIVER_UNLOCK
+#else
+ spin_unlock_irqrestore(&io_request_lock, cpu_flags);
+#endif
}
/*+F*************************************************************************
@@ -2711,15 +3312,15 @@ aic7xxx_run_waiting_queues(struct aic7xxx_host *p)
* buffer on the sequencer.
*-F*************************************************************************/
static void
-aic7xxx_construct_sdtr(struct aic7xxx_host *p, int start_byte,
- unsigned char period, unsigned char offset)
+aic7xxx_construct_sdtr(struct aic7xxx_host *p, unsigned char period,
+ unsigned char offset)
{
- outb(MSG_EXTENDED, p->base + MSG_OUT + start_byte);
- outb(MSG_EXT_SDTR_LEN, p->base + MSG_OUT + 1 + start_byte);
- outb(MSG_EXT_SDTR, p->base + MSG_OUT + 2 + start_byte);
- outb(period, p->base + MSG_OUT + 3 + start_byte);
- outb(offset, p->base + MSG_OUT + 4 + start_byte);
- outb(start_byte + 5, p->base + MSG_LEN);
+ p->msg_buf[p->msg_index++] = MSG_EXTENDED;
+ p->msg_buf[p->msg_index++] = MSG_EXT_SDTR_LEN;
+ p->msg_buf[p->msg_index++] = MSG_EXT_SDTR;
+ p->msg_buf[p->msg_index++] = period;
+ p->msg_buf[p->msg_index++] = offset;
+ p->msg_len += 5;
}
/*+F*************************************************************************
@@ -2731,14 +3332,13 @@ aic7xxx_construct_sdtr(struct aic7xxx_host *p, int start_byte,
* on the sequencer.
*-F*************************************************************************/
static void
-aic7xxx_construct_wdtr(struct aic7xxx_host *p, int start_byte,
- unsigned char bus_width)
+aic7xxx_construct_wdtr(struct aic7xxx_host *p, unsigned char bus_width)
{
- outb(MSG_EXTENDED, p->base + MSG_OUT + start_byte);
- outb(MSG_EXT_WDTR_LEN, p->base + MSG_OUT + 1 + start_byte);
- outb(MSG_EXT_WDTR, p->base + MSG_OUT + 2 + start_byte);
- outb(bus_width, p->base + MSG_OUT + 3 + start_byte);
- outb(start_byte + 4, p->base + MSG_LEN);
+ p->msg_buf[p->msg_index++] = MSG_EXTENDED;
+ p->msg_buf[p->msg_index++] = MSG_EXT_WDTR_LEN;
+ p->msg_buf[p->msg_index++] = MSG_EXT_WDTR;
+ p->msg_buf[p->msg_index++] = bus_width;
+ p->msg_len += 4;
}
/*+F*************************************************************************
@@ -2753,7 +3353,7 @@ aic7xxx_calculate_residual (struct aic7xxx_host *p, struct aic7xxx_scb *scb)
{
struct aic7xxx_hwscb *hscb;
Scsi_Cmnd *cmd;
- int actual;
+ int actual, i;
cmd = scb->cmd;
hscb = scb->hscb;
@@ -2771,18 +3371,22 @@ aic7xxx_calculate_residual (struct aic7xxx_host *p, struct aic7xxx_scb *scb)
* and cmd->underflow seems to be set rather half-
* heartedly in the higher-level SCSI code.
*/
- actual = aic7xxx_length(cmd, hscb->residual_SG_segment_count);
-
+ actual = scb->sg_length;
+ for (i=1; i < hscb->residual_SG_segment_count; i++)
+ {
+ actual -= scb->sg_list[scb->sg_count - i].length;
+ }
actual -= (hscb->residual_data_count[2] << 16) |
(hscb->residual_data_count[1] << 8) |
hscb->residual_data_count[0];
if (actual < cmd->underflow)
{
- printk(KERN_WARNING "(scsi%d:%d:%d) Underflow - "
- "Wanted at least %u, got %u, residual SG count %d.\n",
- p->host_no, TC_OF_SCB(scb), cmd->underflow, actual,
- hscb->residual_SG_segment_count);
+ if (aic7xxx_verbose & VERBOSE_MINOR_ERROR)
+ printk(INFO_LEAD "Underflow - Wanted %u, %s %u, residual SG "
+ "count %d.\n", p->host_no, CTL_OF_SCB(scb), cmd->underflow,
+ (cmd->request.cmd == WRITE) ? "wrote" : "read", actual,
+ hscb->residual_SG_segment_count);
aic7xxx_error(cmd) = DID_RETRY_COMMAND;
aic7xxx_status(cmd) = hscb->target_status;
}
@@ -2806,31 +3410,29 @@ aic7xxx_calculate_residual (struct aic7xxx_host *p, struct aic7xxx_scb *scb)
* Interrupt handler for sequencer interrupts (SEQINT).
*-F*************************************************************************/
static void
-aic7xxx_handle_device_reset(struct aic7xxx_host *p, int target, char channel)
+aic7xxx_handle_device_reset(struct aic7xxx_host *p, int target, int channel)
{
unsigned short targ_mask;
unsigned char targ_scratch;
int scratch_offset = target;
- int found;
- if (channel == 'B')
- {
- scratch_offset += 8;
- }
+ scratch_offset += channel << 3;
+
targ_mask = (0x01 << scratch_offset);
/*
* Go back to async/narrow transfers and renegotiate.
*/
- p->needsdtr |= p->needsdtr_copy & targ_mask;
- p->needwdtr |= p->needwdtr_copy & targ_mask;
+ p->needsdtr |= (p->needsdtr_copy & targ_mask);
+ p->needwdtr |= (p->needwdtr_copy & targ_mask);
p->sdtr_pending &= ~targ_mask;
p->wdtr_pending &= ~targ_mask;
- targ_scratch = inb(p->base + TARG_SCRATCH + scratch_offset);
+ targ_scratch = aic_inb(p, TARG_SCRATCH + scratch_offset);
targ_scratch &= SXFR;
- outb(targ_scratch, p->base + TARG_SCRATCH + scratch_offset);
- found = aic7xxx_reset_device(p, target, channel, ALL_LUNS, SCB_LIST_NULL);
- printk(KERN_WARNING "(scsi%d:%d:%d) Bus Device Reset delivered, "
- "%d SCBs aborted.\n", p->host_no, target, CHAN_TO_INT(channel), found);
+ aic_outb(p, targ_scratch, TARG_SCRATCH + scratch_offset);
+ aic7xxx_reset_device(p, target, channel, ALL_LUNS, SCB_LIST_NULL);
+ if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+ printk(INFO_LEAD "Bus Device Reset delivered.\n", p->host_no, channel,
+ target, -1);
aic7xxx_run_done_queue(p, /*complete*/ TRUE);
}
@@ -2846,107 +3448,35 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
{
struct aic7xxx_scb *scb;
unsigned short target_mask;
- unsigned char target, scratch_offset;
+ unsigned char target, scratch_offset, lun;
+ unsigned char queue_flag = FALSE;
char channel;
- if ((inb(p->base + SEQ_FLAGS) & RESELECTED) != 0)
- {
- target = (inb(p->base + SELID) >> 4) & 0x0F;
- }
- else
- {
- target = (inb(p->base + SCSIID) >> 4) & 0x0F;
- }
- scratch_offset = target;
- channel = 'A';
- if (inb(p->base + SBLKCTL) & SELBUSB)
- {
- channel = 'B';
- scratch_offset += 8;
- }
+ target = ((aic_inb(p, SAVED_TCL) >> 4) & 0x0f);
+ channel = (aic_inb(p, SBLKCTL) >> 3) & 0x01;
+ scratch_offset = target + (channel << 3);
+ lun = aic_inb(p, SAVED_TCL) & 0x07;
target_mask = (0x01 << scratch_offset);
switch (intstat & SEQINT_MASK)
{
case NO_MATCH:
{
- /*
- * This could be for a normal abort request. Figure out
- * which SCB we were trying to find and only give an error
- * if we didn't ask for this to happen.
- */
- unsigned char scb_index;
- unsigned char busy_scbid;
- unsigned char arg1;
-
- busy_scbid = aic7xxx_index_busy_target(p, target, channel,
- /*unbusy*/ FALSE);
- arg1 = inb(p->base + ARG_1);
-
- if (arg1 == SCB_LIST_NULL)
- {
- /* untagged request */
- scb_index = busy_scbid;
- }
- else
- {
- scb_index = arg1;
- }
-
- if (scb_index < p->scb_data->numscbs)
- {
- scb = p->scb_data->scb_array[scb_index];
- if (scb->hscb->control & ABORT_SCB)
- {
- /*
- * We expected this. Let the busfree handler take care
- * of this when we the abort is finially sent. Set
- * IDENTIFY_SEEN so that the busfree handler knows that
- * there is an SCB to cleanup.
- */
- outb(inb(p->base + SEQ_FLAGS) | IDENTIFY_SEEN, p->base + SEQ_FLAGS);
- printk(KERN_INFO "(scsi%d:%d:%d) reconnect SCB abort successful\n",
- p->host_no, TC_OF_SCB(scb));
- break;
- }
- }
- printk(KERN_WARNING "(scsi%d:%d:%d) No active SCB for reconnecting "
- "target - Issuing BUS DEVICE RESET.\n",
- p->host_no, target, CHAN_TO_INT(channel));
-
- printk(KERN_WARNING " SAVED_TCL=0x%x, ARG_1=0x%x, SEQADDR=0x%x\n",
- inb(p->base + SAVED_TCL), arg1,
- (inb(p->base + SEQADDR1) << 8) | inb(p->base + SEQADDR0));
- aic7xxx_handle_device_reset(p, target, channel);
- }
- break;
-
- case NO_MATCH_BUSY:
- {
- /*
- * XXX - Leave this as a panic for the time being since it
- * indicates a bug in the timeout code for this to happen.
- */
- unsigned char scb_index;
-
- scb_index = inb(p->base + CUR_SCBID);
- scb = p->scb_data->scb_array[scb_index];
-
- panic("scsi%d: Target %d, channel %c, Target busy link failure, "
- "but busy SCB exists!\n",
- p->host_no, target, channel);
+ printk(WARN_LEAD "No active SCB for reconnecting target - Issuing "
+ "BUS DEVICE RESET.\n", p->host_no, channel, target, lun);
+ printk(WARN_LEAD " SAVED_TCL=0x%x, ARG_1=0x%x, SEQADDR=0x%x\n",
+ p->host_no, channel, target, lun,
+ aic_inb(p, SAVED_TCL), aic_inb(p, ARG_1),
+ (aic_inb(p, SEQADDR1) << 8) | aic_inb(p, SEQADDR0));
}
break;
case SEND_REJECT:
{
- unsigned char rej_byte;
-
- rej_byte = inb(p->base + REJBYTE);
- printk(KERN_WARNING "(scsi%d:%d:%d) Rejecting unknown message (0x%x) "
- "received from target, SEQ_FLAGS=0x%x\n",
- p->host_no, target, CHAN_TO_INT(channel), rej_byte,
- inb(p->base + SEQ_FLAGS));
+ if (aic7xxx_verbose & VERBOSE_MINOR_ERROR)
+ printk(INFO_LEAD "Rejecting unknown message (0x%x) received from "
+ "target, SEQ_FLAGS=0x%x\n", p->host_no, channel, target, lun,
+ aic_inb(p, ACCUM), aic_inb(p, SEQ_FLAGS));
}
break;
@@ -2954,560 +3484,652 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
{
/*
* The reconnecting target either did not send an identify
- * message, or did, but we didn't find and SCB to match and
+ * message, or did, but we didn't find an SCB to match and
* before it could respond to our ATN/abort, it hit a dataphase.
* The only safe thing to do is to blow it away with a bus
* reset.
*/
- int found;
+ if (aic7xxx_verbose & (VERBOSE_SEQINT | VERBOSE_RESET_MID))
+ printk(INFO_LEAD "Target did not send an IDENTIFY message; "
+ "LASTPHASE 0x%x, SAVED_TCL 0x%x\n", p->host_no, channel, target,
+ lun, aic_inb(p, LASTPHASE), aic_inb(p, SAVED_TCL));
- printk(KERN_WARNING "(scsi%d:%d:%d): Target did not send an IDENTIFY "
- "message; LASTPHASE 0x%x, SAVED_TCL 0x%x\n",
- p->host_no, target, CHAN_TO_INT(channel),
- inb(p->base + LASTPHASE), inb(p->base + SAVED_TCL));
+ aic7xxx_reset_channel(p, channel, /*initiate reset*/ TRUE);
- found = aic7xxx_reset_channel(p, channel, /*initiate reset*/ TRUE);
-
- printk(KERN_WARNING "scsi%d: Issued channel %c bus reset; "
- "%d SCBs aborted\n", p->host_no, channel, found);
}
break;
case BAD_PHASE:
- if (inb(p->base + LASTPHASE) == P_BUSFREE)
+ if (aic_inb(p, LASTPHASE) == P_BUSFREE)
{
- printk(KERN_WARNING "(scsi%d:%d:%d): Missed busfree.\n",
- p->host_no, CHAN_TO_INT(channel), target);
+ if (aic7xxx_verbose & VERBOSE_SEQINT)
+ printk(INFO_LEAD "Missed busfree.\n", p->host_no, channel,
+ target, lun);
restart_sequencer(p);
}
else
{
- printk(KERN_WARNING "(scsi%d:%d:%d): Unknown scsi bus phase, attempting "
- "to continue\n", p->host_no, CHAN_TO_INT(channel), target);
+ if (aic7xxx_verbose & VERBOSE_SEQINT)
+ printk(INFO_LEAD "Unknown scsi bus phase, continuing\n", p->host_no,
+ channel, target, lun);
}
break;
case EXTENDED_MSG:
{
- unsigned char message_length;
- unsigned char message_code;
- unsigned char scb_index;
+ p->msg_type = MSG_TYPE_INITIATOR_MSGIN;
+ p->msg_len = 0;
+ p->msg_index = 0;
- message_length = inb(p->base + MSGIN_EXT_LEN);
- message_code = inb(p->base + MSGIN_EXT_OPCODE);
- scb_index = inb(p->base + SCB_TAG);
- scb = p->scb_data->scb_array[scb_index];
+ /*
+ * We have to clear the SEQINT *BEFORE* we set the REQINIT handler
+ * active or else VLB and edge triggered EISA cards could loose the
+ * first REQINIT and cause a bus hang/reset cycle.
+ */
+ aic_outb(p, CLRSEQINT, CLRINT);
- switch (message_code)
- {
- case MSG_EXT_SDTR:
- {
- unsigned char period;
- unsigned char offset;
- unsigned char saved_offset;
- unsigned char targ_scratch;
- unsigned char max_offset;
- unsigned char rate;
-
- if (message_length != MSG_EXT_SDTR_LEN)
- {
- outb(SEND_REJ, p->base + RETURN_1);
- break;
- }
+ /*
+ * To actually receive the message, simply turn on
+ * REQINIT interrupts and let our interrupt handler
+ * do the rest (REQINIT should already be true).
+ */
+ p->flags |= AHC_HANDLING_REQINITS;
+ aic_outb(p, aic_inb(p, SIMODE1) | ENREQINIT, SIMODE1);
- period = inb(p->base + MSGIN_EXT_BYTES);
- saved_offset = inb(p->base + MSGIN_EXT_BYTES + 1);
- targ_scratch = inb(p->base + TARG_SCRATCH + scratch_offset);
+ /*
+ * We don't want the sequencer unpaused yet so we return early
+ */
+ return;
+ }
- if (targ_scratch & WIDEXFER)
- max_offset = MAX_OFFSET_16BIT;
- else
- max_offset = MAX_OFFSET_8BIT;
- offset = MIN(saved_offset, max_offset);
+ case REJECT_MSG:
+ {
+ /*
+ * What we care about here is if we had an outstanding SDTR
+ * or WDTR message for this target. If we did, this is a
+ * signal that the target is refusing negotiation.
+ */
+ unsigned char targ_scratch;
+ unsigned char scb_index;
+ unsigned char last_msg;
- aic7xxx_scsirate(p, &rate, &period, &offset, target, channel);
+ scb_index = aic_inb(p, SCB_TAG);
+ scb = p->scb_data->scb_array[scb_index];
+ targ_scratch = aic_inb(p, TARG_SCRATCH + scratch_offset);
+ last_msg = aic_inb(p, LAST_MSG);
+ if ( (last_msg == MSG_IDENTIFYFLAG) &&
+ (scb->tag_action != 0 ) &&
+ !(p->flags & AHC_HANDLING_REQINITS) )
+ {
+ if ((scb->tag_action == MSG_ORDERED_Q_TAG) &&
+ (p->dev_flags[scratch_offset] & DEVICE_TAGGED_SUCCESS))
+ {
/*
- * Preserve the WideXfer flag.
+ * OK...the device seems able to accept tagged commands, but
+ * not ordered tag commands, only simple tag commands. So, we
+ * disable ordered tag commands and go on with life just like
+ * normal.
*/
- targ_scratch = rate | (targ_scratch & WIDEXFER);
-
+ p->orderedtag &= ~target_mask;
+ scb->tag_action = MSG_SIMPLE_Q_TAG;
+ scb->hscb->control &= ~SCB_TAG_TYPE;
+ scb->hscb->control |= MSG_SIMPLE_Q_TAG;
+ aic_outb(p, scb->hscb->control, SCB_CONTROL);
/*
- * Update both the target scratch area and current SCSIRATE.
+ * OK..we set the tag type to simple tag command, now we re-assert
+ * ATNO and hope this will take us into the identify phase again
+ * so we can resend the tag type and info to the device.
*/
- outb(targ_scratch, p->base + TARG_SCRATCH + scratch_offset);
- outb(targ_scratch, p->base + SCSIRATE);
-
+ }
+ else
+ {
+ unsigned char i, reset = 0;
+ struct aic7xxx_scb *scbp;
+ int old_verbose;
/*
- * See if we initiated Sync Negotiation and didn't have
- * have to fall down to async transfers.
+ * Hmmmm....the device is flaking out on tagged commands. The
+ * bad thing is that we already have tagged commands enabled in
+ * the device struct in the mid level code. We also have a queue
+ * set according to the tagged queue depth. Gonna have to live
+ * with it by controlling our queue depth internally and making
+ * sure we don't set the tagged command flag any more.
*/
- if ((scb->flags & SCB_MSGOUT_SDTR) != 0)
- {
- /* We started it. */
- if (saved_offset == offset)
- {
- /*
- * Don't send an SDTR back to the target.
- */
- outb(0, p->base + RETURN_1);
- }
- else
- {
- /* We went too low - force async. */
- outb(SEND_REJ, p->base + RETURN_1);
- }
- }
- else
- {
- /*
- * Send our own SDTR in reply.
- *
- * We want to see this message as we don't expect a target
- * to send us a SDTR request first.
- */
- printk(KERN_WARNING "scsi%d: Sending SDTR!!\n", p->host_no);
- aic7xxx_construct_sdtr(p, /* start byte */ 0, period, offset);
- outb(SEND_MSG, p->base + RETURN_1);
- }
+ p->tagenable &= ~target_mask;
+ p->orderedtag &= ~target_mask;
+ p->dev_max_queue_depth[scratch_offset] =
+ p->dev_temp_queue_depth[scratch_offset] = 1;
/*
- * Clear the flags.
+ * We set this command up as a bus device reset. However, we have
+ * to clear the tag type as it's causing us problems. We shouldnt
+ * have to worry about any other commands being active, since if
+ * the device is refusing tagged commands, this should be the
+ * first tagged command sent to the device, however, we do have
+ * to worry about any other tagged commands that may already be
+ * in the qinfifo. The easiest way to do this, is to issue a BDR,
+ * send all the commands back to the mid level code, then let them
+ * come back and get rebuilt as untagged commands.
*/
- p->needsdtr &= ~target_mask;
- break;
- }
-
- case MSG_EXT_WDTR:
- {
- unsigned char scratch, bus_width;
-
- if (message_length != MSG_EXT_WDTR_LEN)
+ scb->tag_action = 0;
+ scb->hscb->control &= ~(TAG_ENB | SCB_TAG_TYPE);
+ scb->hscb->control |= MK_MESSAGE;
+ aic_outb(p, scb->hscb->control, SCB_CONTROL);
+
+ old_verbose = aic7xxx_verbose;
+ aic7xxx_verbose &= ~(VERBOSE_RESET|VERBOSE_ABORT);
+ for (i=0; i!=p->scb_data->numscbs; i++)
{
- outb(SEND_REJ, p->base + RETURN_1);
- break;
- }
-
- bus_width = inb(p->base + MSGIN_EXT_BYTES);
- scratch = inb(p->base + TARG_SCRATCH + scratch_offset);
-
- if ((scb->flags & SCB_MSGOUT_WDTR) != 0)
- {
- /*
- * Don't send an WDTR back to the target, since we asked first.
- */
- outb(0, p->base + RETURN_1);
- switch (bus_width)
+ scbp = p->scb_data->scb_array[i];
+ if ((scbp->flags & SCB_ACTIVE) && (scbp != scb))
{
- case BUS_8_BIT:
- scratch &= 0x7F;
- break;
-
- case BUS_16_BIT:
- if (aic7xxx_verbose)
- {
- printk(KERN_INFO "scsi%d: Target %d, channel %c, using 16 "
- "bit transfers.\n", p->host_no, target, channel);
- }
- scratch |= WIDEXFER;
- break;
-
- case BUS_32_BIT:
- outb(SEND_REJ, p->base + RETURN_1);
- /* No verbose here! We want to see this condition. */
- printk(KERN_WARNING "scsi%d: Target %d, channel %c, "
- "requesting 32 bit transfers, rejecting...\n",
- p->host_no, target, channel);
- break;
-
- default:
- break;
+ if (aic7xxx_match_scb(p, scbp, target, channel, lun, i))
+ {
+ aic7xxx_reset_device(p, target, channel, lun, i);
+ reset++;
+ }
}
}
- else
- {
- int send_reject = FALSE;
-
- /*
- * Send our own WDTR in reply.
- */
- switch (bus_width)
- {
- case BUS_8_BIT:
- scratch &= 0x7F;
- break;
-
- case BUS_32_BIT:
- case BUS_16_BIT:
- if (p->bus_type == AIC_WIDE)
- {
- printk(KERN_INFO "scsi%d: Target %d, channel %c, using 16 "
- "bit transfers.\n", p->host_no, target, channel);
- bus_width = BUS_16_BIT;
- scratch |= WIDEXFER;
- }
- else
- {
- bus_width = BUS_8_BIT;
- scratch &= 0x7F; /* XXX - FreeBSD doesn't do this. */
- send_reject = TRUE;
- }
- break;
-
- default:
- break;
- }
- if (send_reject)
- {
- outb(SEND_REJ, p->base + RETURN_1);
- printk(KERN_WARNING "scsi%d: Target %d, channel %c, initiating "
- "wide negotiation on a narrow bus - rejecting!",
- p->host_no, target, channel);
- }
- else
- {
- aic7xxx_construct_wdtr(p, /* start byte */ 0, bus_width);
- outb(SEND_MSG, p->base + RETURN_1);
- }
- }
- p->needwdtr &= ~target_mask;
- outb(scratch, p->base + TARG_SCRATCH + scratch_offset);
- outb(scratch, p->base + SCSIRATE);
- break;
- } /* case MSG_EXT_WDTR */
-
- default:
+ aic7xxx_verbose = old_verbose;
/*
- * Unknown extended message - reject it.
+ * Wait until after the for loop to set the busy index since
+ * aic7xxx_reset_device will clear the busy index during its
+ * operation.
*/
- outb(SEND_REJ, p->base + RETURN_1);
- break;
- } /* switch (message_code) */
- } /* case EXTENDED_MSG */
- break;
-
- case REJECT_MSG:
- {
- /*
- * What we care about here is if we had an outstanding SDTR
- * or WDTR message for this target. If we did, this is a
- * signal that the target is refusing negotiation.
- */
- unsigned char targ_scratch;
- unsigned char scb_index;
-
- scb_index = inb(p->base + SCB_TAG);
- scb = p->scb_data->scb_array[scb_index];
- targ_scratch = inb(p->base + TARG_SCRATCH + scratch_offset);
-
- if ((scb->flags & SCB_MSGOUT_WDTR) != 0)
- {
+ aic7xxx_busy_target(p, scb);
+ printk(INFO_LEAD "Device is refusing tagged commands, using "
+ "untagged I/O.\n", p->host_no, channel, target, lun);
+ }
+ aic_outb(p, MSG_IDENTIFYFLAG, MSG_OUT);
+ aic_outb(p, aic_inb(p, SCSISIGI) | ATNO, SCSISIGO);
+ }
+ else if ( (last_msg == MSG_IDENTIFYFLAG) &&
+ (scb->flags & SCB_MSGOUT_WDTR) )
+ {
/*
* note 8bit xfers and clear flag
*/
targ_scratch &= 0x7F;
p->needwdtr &= ~target_mask;
- printk(KERN_WARNING "scsi%d: Target %d, channel %c, refusing WIDE "
- "negotiation; using 8 bit transfers.\n",
- p->host_no, target, channel);
- }
- else
- {
- if ((scb->flags & SCB_MSGOUT_SDTR) != 0)
+ p->needwdtr_copy &= ~target_mask;
+ p->wdtr_pending &= ~target_mask;
+ if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
+ (p->dev_flags[scratch_offset] & DEVICE_PRINT_WDTR) )
{
- /*
- * note asynch xfers and clear flag
- */
- targ_scratch &= 0xF0;
- p->needsdtr &= ~target_mask;
- printk(KERN_WARNING "scsi%d: Target %d, channel %c, refusing "
- "synchronous negotiation; using asynchronous transfers.\n",
- p->host_no, target, channel);
+ printk(INFO_LEAD "Refusing WIDE negotiation; using 8 bit "
+ "transfers.\n", p->host_no, CTL_OF_SCB(scb));
+ p->dev_flags[scratch_offset] &= ~DEVICE_PRINT_WDTR;
+ }
+ scb->flags &= ~SCB_MSGOUT_WDTR_16BIT;
+ p->syncinfo[scratch_offset].offset = MAX_OFFSET_8BIT;
+ if (p->needsdtr & target_mask)
+ {
+ p->sdtr_pending |= target_mask;
+ scb->flags |= SCB_MSGOUT_SDTR;
+ aic_outb(p, HOST_MSG, MSG_OUT);
+ aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
+ }
+ }
+ else if (scb->flags & SCB_MSGOUT_SDTR)
+ {
+ /*
+ * note asynch xfers and clear flag
+ */
+ targ_scratch &= 0xF0;
+ p->needsdtr &= ~target_mask;
+ p->needsdtr_copy &= ~target_mask;
+ p->sdtr_pending &= ~target_mask;
+ p->syncinfo[scratch_offset].period = 0;
+ p->syncinfo[scratch_offset].offset = 0;
+ if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
+ (p->dev_flags[scratch_offset] & DEVICE_PRINT_SDTR) )
+ {
+ printk(INFO_LEAD "Refusing synchronous negotiation; using "
+ "asynchronous transfers.\n", p->host_no, CTL_OF_SCB(scb));
+ p->dev_flags[scratch_offset] &= ~DEVICE_PRINT_SDTR;
}
+ }
+ else if (aic7xxx_verbose & VERBOSE_SEQINT)
+ {
/*
* Otherwise, we ignore it.
*/
- }
- outb(targ_scratch, p->base + TARG_SCRATCH + scratch_offset);
- outb(targ_scratch, p->base + SCSIRATE);
+ printk(INFO_LEAD "Received MESSAGE_REJECT for unknown cause. "
+ "Ignoring.\n", p->host_no, channel, target, lun);
+ }
+ aic_outb(p, targ_scratch, TARG_SCRATCH + scratch_offset);
+ aic_outb(p, targ_scratch, SCSIRATE);
}
break;
case BAD_STATUS:
{
- unsigned char scb_index;
- struct aic7xxx_hwscb *hscb;
- Scsi_Cmnd *cmd;
-
- /* The sequencer will notify us when a command has an error that
- * would be of interest to the kernel. This allows us to leave
- * the sequencer running in the common case of command completes
- * without error. The sequencer will have DMA'd the SCB back
- * up to us, so we can reference the drivers SCB array.
- */
- scb_index = inb(p->base + SCB_TAG);
- scb = p->scb_data->scb_array[scb_index];
- hscb = scb->hscb;
-
- /*
- * Set the default return value to 0 indicating not to send
- * sense. The sense code will change this if needed and this
- * reduces code duplication.
- */
- outb(0, p->base + RETURN_1);
- if (!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL))
- {
- printk(KERN_WARNING "scsi%d: Referenced SCB not valid during "
- "SEQINT 0x%x, scb %d, flags 0x%x, cmd 0x%x.\n", p->host_no,
- intstat, scb_index, scb->flags, (unsigned int) scb->cmd);
- }
- else
- {
+ unsigned char scb_index;
+ struct aic7xxx_hwscb *hscb;
+ Scsi_Cmnd *cmd;
+
+ /* The sequencer will notify us when a command has an error that
+ * would be of interest to the kernel. This allows us to leave
+ * the sequencer running in the common case of command completes
+ * without error. The sequencer will have DMA'd the SCB back
+ * up to us, so we can reference the drivers SCB array.
+ */
+ scb_index = aic_inb(p, SCB_TAG);
+ if (scb_index > p->scb_data->numscbs)
+ {
+ aic_outb(p, 0, RETURN_1);
+ printk(WARN_LEAD "Invalid SCB during SEQINT 0x%02x, SCB_TAG %d.\n",
+ p->host_no, channel, target, lun, intstat, scb_index);
+ break;
+ }
+ scb = p->scb_data->scb_array[scb_index];
+ hscb = scb->hscb;
+
+ /*
+ * Set the default return value to 0 indicating not to send
+ * sense. The sense code will change this if needed and this
+ * reduces code duplication.
+ */
+ aic_outb(p, 0, RETURN_1);
+ if (!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL))
+ {
+ printk(WARN_LEAD "Invalid SCB during SEQINT 0x%x, scb %d, flags 0x%x,"
+ " cmd 0x%lx.\n", p->host_no, channel, target, lun, intstat,
+ scb_index, scb->flags, (unsigned long) scb->cmd);
+ }
+ else
+ {
cmd = scb->cmd;
- hscb->target_status = inb(p->base + SCB_TARGET_STATUS);
+ hscb->target_status = aic_inb(p, SCB_TARGET_STATUS);
aic7xxx_status(cmd) = hscb->target_status;
- cmd->result |= hscb->target_status;
+ cmd->result = hscb->target_status;
switch (status_byte(hscb->target_status))
{
case GOOD:
- printk(KERN_WARNING "(scsi%d:%d:%d) Interrupted for status of "
- "GOOD???\n", p->host_no, TC_OF_SCB(scb));
+ if (aic7xxx_verbose & VERBOSE_SEQINT)
+ printk(INFO_LEAD "Interrupted for status of GOOD???\n",
+ p->host_no, CTL_OF_SCB(scb));
break;
+ case COMMAND_TERMINATED:
case CHECK_CONDITION:
- if ((aic7xxx_error(cmd) == 0) && !(scb->flags & SCB_SENSE))
+ if ( !(scb->flags & SCB_SENSE) )
{
- unsigned int addr; /* must be 32 bits */
- /*
- * XXX - How do we save the residual (if there is one).
- */
- aic7xxx_calculate_residual(p, scb);
-
- /*
- * Send a sense command to the requesting target.
- * XXX - revisit this and get rid of the memcopys.
- */
- memcpy((void *) scb->sense_cmd, (void *) generic_sense,
- sizeof(generic_sense));
-
- scb->sense_cmd[1] = (cmd->lun << 5);
- scb->sense_cmd[4] = sizeof(cmd->sense_buffer);
-
- scb->sg_list[0].address = VIRT_TO_BUS(&cmd->sense_buffer);
- scb->sg_list[0].length = sizeof(cmd->sense_buffer);
- cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]);
+ /*
+ * XXX - How do we save the residual (if there is one).
+ */
+ if ( hscb->residual_SG_segment_count != 0 )
+ aic7xxx_calculate_residual(p, scb);
+
+ /*
+ * Send a sense command to the requesting target.
+ * XXX - revisit this and get rid of the memcopys.
+ */
+ memcpy((void *) scb->sense_cmd, (void *) generic_sense,
+ sizeof(generic_sense));
+
+ scb->sense_cmd[1] = (cmd->lun << 5);
+ scb->sense_cmd[4] = sizeof(cmd->sense_buffer);
+
+ scb->sg_list[0].address =
+ cpu_to_le32(VIRT_TO_BUS(&cmd->sense_buffer[0]));
+ scb->sg_list[0].length =
+ cpu_to_le32(sizeof(cmd->sense_buffer));
/*
* XXX - We should allow disconnection, but can't as it
* might allow overlapped tagged commands.
*/
- /* hscb->control &= DISCENB; */
+ /* hscb->control &= DISCENB; */
hscb->control = 0;
- hscb->target_status = 0;
- hscb->SG_segment_count = 1;
-
- addr = VIRT_TO_BUS(&scb->sg_list[0]);
- memcpy(&hscb->SG_list_pointer, &addr,
- sizeof(hscb->SG_list_pointer));
-
- memcpy(&hscb->data_pointer, &(scb->sg_list[0].address),
- sizeof(hscb->data_pointer));
- /* Maintain SCB_LINKED_NEXT */
- hscb->data_count &= 0xFF000000;
- hscb->data_count |= scb->sg_list[0].length;
-
- addr = VIRT_TO_BUS(scb->sense_cmd);
- memcpy(&hscb->SCSI_cmd_pointer, &addr,
- sizeof(hscb->SCSI_cmd_pointer));
- hscb->SCSI_cmd_length = COMMAND_SIZE(scb->sense_cmd[0]);
-
- scb->sg_count = hscb->SG_segment_count;
- scb->flags |= SCB_SENSE;
+ hscb->target_status = 0;
+ hscb->SG_list_pointer =
+ cpu_to_le32(VIRT_TO_BUS(&scb->sg_list[0]));
+ hscb->data_pointer = scb->sg_list[0].address;
+ hscb->data_count = scb->sg_list[0].length;
+ hscb->SCSI_cmd_pointer =
+ cpu_to_le32(VIRT_TO_BUS(&scb->sense_cmd[0]));
+ hscb->SCSI_cmd_length = COMMAND_SIZE(scb->sense_cmd[0]);
+ hscb->residual_SG_segment_count = 0;
+ hscb->residual_data_count[0] = 0;
+ hscb->residual_data_count[1] = 0;
+ hscb->residual_data_count[2] = 0;
+
+ scb->sg_count = hscb->SG_segment_count = 1;
+ scb->sg_length = sizeof(cmd->sense_buffer);
+ scb->flags &= ~SCB_MSGOUT_BITS;
+ scb->tag_action = 0;
+ /*
+ * This problem could be caused if the target has lost power
+ * or found some other way to loose the negotiation settings,
+ * so if needed, we'll re-negotiate while doing the sense cmd.
+ * However, if this SCB already was attempting to negotiate,
+ * then we assume this isn't the problem and skip this part.
+ */
+ if ( !(scb->flags & SCB_MSGOUT_BITS) )
+ {
+ if ( p->needwdtr_copy & target_mask )
+ {
+ p->needwdtr |= target_mask;
+ p->wdtr_pending |= target_mask;
+ hscb->control |= MK_MESSAGE;
+ scb->flags |= SCB_MSGOUT_WDTR_16BIT;
+ }
+ if ( p->needsdtr_copy & target_mask )
+ {
+ p->needsdtr |= target_mask;
+ if ((hscb->control & MK_MESSAGE) == 0)
+ {
+ p->sdtr_pending |= target_mask;
+ hscb->control |= MK_MESSAGE;
+ scb->flags |= SCB_MSGOUT_SDTR;
+ }
+ }
+ }
+
+ scb->flags |= SCB_SENSE;
/*
* Ensure the target is busy since this will be an
* an untagged request.
*/
- aic7xxx_busy_target(p, target, channel, hscb->tag);
- outb(SEND_SENSE, p->base + RETURN_1);
+ aic7xxx_busy_target(p, scb);
+ aic_outb(p, SEND_SENSE, RETURN_1);
+ aic7xxx_error(cmd) = DID_OK;
+ break;
} /* first time sense, no errors */
- else
- {
- if (aic7xxx_error(cmd) == 0)
- {
- aic7xxx_error(cmd) = DID_RETRY_COMMAND;
- }
- }
+ aic7xxx_error(cmd) = DID_OK;
+ scb->flags &= ~SCB_SENSE;
break;
case QUEUE_FULL:
-#ifdef NOT_YET
- if (scb->hscb->control & TAG_ENB)
+ queue_flag = TRUE; /* Mark that this is a QUEUE_FULL and */
+ case BUSY: /* drop through to here */
+ {
+ struct aic7xxx_scb *next_scbp, *prev_scbp;
+ unsigned char active_hscb, next_hscb, prev_hscb, scb_index;
+ /*
+ * We have to look three places for queued commands:
+ * 1: QINFIFO
+ * 2: p->waiting_scbs queue
+ * 3: WAITING_SCBS list on card (for commands that are started
+ * but haven't yet made it to the device)
+ */
+ aic7xxx_search_qinfifo(p, target, channel, lun,
+ SCB_LIST_NULL, 0, TRUE,
+ &p->delayed_scbs[scratch_offset]);
+ next_scbp = p->waiting_scbs.head;
+ while ( next_scbp != NULL )
{
- if (cmd->device->queue_depth > 2)
- {
- cmd->device->queue_depth--; /* Not correct */
- printk(KERN_WARNING "(scsi%d:%d:%d) Tagged queue depth "
- "reduced to %d\n", p->host_no,
- TC_OF_SCB(scb), cmd->device->queue_depth);
- }
- /*
- * XXX - Requeue this unconditionally?
- */
-
- /*
- * We'd like to be able to give the SCB some more time
- * (untimeout, then timeout).
- */
- break;
+ prev_scbp = next_scbp;
+ next_scbp = next_scbp->q_next;
+ if ( aic7xxx_match_scb(p, prev_scbp, target, channel, lun,
+ SCB_LIST_NULL) )
+ {
+ scbq_remove(&p->waiting_scbs, prev_scbp);
+ scbq_insert_tail(&p->delayed_scbs[scratch_offset],
+ prev_scbp);
+ }
}
-#endif
- printk(KERN_WARNING "(scsi%d:%d:%d) Queue full received; "
- "queue depth %d, active %d\n", p->host_no,
- TC_OF_SCB(scb), cmd->device->queue_depth,
- p->device_status[TARGET_INDEX(cmd)].active_cmds);
-
- /* Else treat this as if it was a BUSY condition. */
- scb->hscb->target_status = (BUSY << 1) |
- (scb->hscb->target_status & 0x01);
- /* Fall through to the BUSY case. */
-
- case BUSY:
- printk(KERN_WARNING "(scsi%d:%d:%d) Target busy\n",
- p->host_no, TC_OF_SCB(scb));
- if (!aic7xxx_error(cmd))
+ next_scbp = NULL;
+ active_hscb = aic_inb(p, SCBPTR);
+ prev_hscb = next_hscb = scb_index = SCB_LIST_NULL;
+ next_hscb = aic_inb(p, WAITING_SCBH);
+ while (next_hscb != SCB_LIST_NULL)
{
- /*
- * The mid-level SCSI code should be fixed to
- * retry the command at a later time instead of
- * trying right away.
- */
- aic7xxx_error(cmd) = DID_BUS_BUSY | (SUGGEST_RETRY << 8);
+ aic_outb(p, next_hscb, SCBPTR);
+ scb_index = aic_inb(p, SCB_TAG);
+ next_scbp = p->scb_data->scb_array[scb_index];
+ if (aic7xxx_match_scb(p, next_scbp, target, channel, lun,
+ SCB_LIST_NULL) )
+ {
+ scbq_insert_head(&p->delayed_scbs[scratch_offset],
+ next_scbp);
+ next_scbp->flags |= SCB_WAITINGQ;
+ p->dev_active_cmds[scratch_offset]--;
+ p->activescbs--;
+ next_hscb = aic_inb(p, SCB_NEXT);
+ aic_outb(p, 0, SCB_CONTROL);
+ aic_outb(p, SCB_LIST_NULL, SCB_TAG);
+ aic7xxx_add_curscb_to_free_list(p);
+ if (prev_hscb == SCB_LIST_NULL)
+ {
+ aic_outb(p, 0, SCSISEQ); /* We were first on the list,
+ * so we kill the selection
+ * hardware. Let the sequencer
+ * re-init the hardware itself
+ */
+ aic_outb(p, next_hscb, WAITING_SCBH);
+ }
+ else
+ {
+ aic_outb(p, prev_hscb, SCBPTR);
+ aic_outb(p, next_hscb, SCB_NEXT);
+ }
+ }
+ else
+ {
+ prev_hscb = next_hscb;
+ next_hscb = aic_inb(p, SCB_NEXT);
+ }
}
- udelay(1000); /* A small pause (1ms) to help the drive */
- break;
+ aic_outb(p, active_hscb, SCBPTR);
+ scbq_insert_head(&p->delayed_scbs[scratch_offset], scb);
+ p->dev_active_cmds[scratch_offset]--;
+ p->activescbs--;
+ scb->flags |= SCB_WAITINGQ | SCB_WAS_BUSY;
+
+ if (p->dev_timer[scratch_offset].expires == 0)
+ {
+ if ( p->dev_active_cmds[scratch_offset] )
+ {
+ p->dev_timer[scratch_offset].expires = jiffies + (HZ * 2);
+ add_timer(&p->dev_timer[scratch_offset]);
+ }
+ else
+ {
+ p->dev_timer[scratch_offset].expires = jiffies + (HZ / 2);
+ add_timer(&p->dev_timer[scratch_offset]);
+ }
+ }
+ if (aic7xxx_verbose & VERBOSE_QUEUE_FULL)
+ {
+ if (queue_flag)
+ printk(INFO_LEAD "Queue full received; queue depth %d, "
+ "active %d\n", p->host_no, CTL_OF_SCB(scb),
+ p->dev_max_queue_depth[scratch_offset],
+ p->dev_active_cmds[scratch_offset]);
+ else
+ printk(INFO_LEAD "Target busy\n", p->host_no, CTL_OF_SCB(scb));
+ }
+ if (queue_flag)
+ {
+ p->dev_temp_queue_depth[scratch_offset] =
+ p->dev_active_cmds[scratch_offset];
+ if ( p->dev_last_queue_full[scratch_offset] !=
+ p->dev_active_cmds[scratch_offset] )
+ {
+ p->dev_last_queue_full[scratch_offset] =
+ p->dev_active_cmds[scratch_offset];
+ p->dev_last_queue_full_count[scratch_offset] = 0;
+ }
+ else
+ {
+ p->dev_last_queue_full_count[scratch_offset]++;
+ }
+ if ( (p->dev_last_queue_full_count[scratch_offset] > 14) &&
+ (p->dev_active_cmds[scratch_offset] > 4) )
+ {
+ if (aic7xxx_verbose & VERBOSE_NEGOTIATION)
+ printk(INFO_LEAD "Queue depth reduced to %d\n", p->host_no,
+ CTL_OF_SCB(scb), p->dev_active_cmds[scratch_offset]);
+ p->dev_max_queue_depth[scratch_offset] =
+ p->dev_active_cmds[scratch_offset];
+ p->dev_last_queue_full[scratch_offset] = 0;
+ p->dev_last_queue_full_count[scratch_offset] = 0;
+ }
+ }
+ break;
+ }
+
default:
- printk(KERN_WARNING "(scsi%d:%d:%d) Unexpected target "
- "status 0x%x.\n", p->host_no,
- TC_OF_SCB(scb), scb->hscb->target_status);
+ if (aic7xxx_verbose & VERBOSE_SEQINT)
+ printk(INFO_LEAD "Unexpected target status 0x%x.\n", p->host_no,
+ CTL_OF_SCB(scb), scb->hscb->target_status);
if (!aic7xxx_error(cmd))
{
- aic7xxx_error(cmd) = DID_RETRY_COMMAND;
+ aic7xxx_error(cmd) = DID_RETRY_COMMAND;
}
break;
} /* end switch */
- } /* end else of */
+ } /* end else of */
}
break;
case AWAITING_MSG:
{
- unsigned char scb_index;
- unsigned char message_offset;
-
- scb_index = inb(p->base + SCB_TAG);
- scb = p->scb_data->scb_array[scb_index];
-
- /*
- * This SCB had a MK_MESSAGE set in its control byte informing
- * the sequencer that we wanted to send a special message to
- * this target.
- */
- message_offset = inb(p->base + MSG_LEN);
- if (scb->flags & SCB_DEVICE_RESET)
- {
- outb(MSG_BUS_DEV_RESET, p->base + MSG_OUT);
- outb(1, p->base + MSG_LEN);
- printk(KERN_INFO "(scsi%d:%d:%d) Bus device reset sent\n",
- p->host_no, TC_OF_SCB(scb));
- }
+ unsigned char scb_index;
+
+ scb_index = aic_inb(p, SCB_TAG);
+ scb = p->scb_data->scb_array[scb_index];
+ p->msg_index = p->msg_len = 0;
+ /*
+ * This SCB had a MK_MESSAGE set in its control byte informing
+ * the sequencer that we wanted to send a special message to
+ * this target.
+ */
+
+ if (scb->flags & SCB_DEVICE_RESET)
+ {
+ p->msg_buf[p->msg_index++] = MSG_BUS_DEV_RESET;
+ p->msg_len++;
+ if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+ printk(INFO_LEAD "Bus device reset mailed.\n",
+ p->host_no, CTL_OF_SCB(scb));
+ }
else if (scb->flags & SCB_ABORT)
{
- if ((scb->hscb->control & TAG_ENB) != 0)
+ if (scb->hscb->control & TAG_ENB)
{
- outb(MSG_ABORT_TAG, p->base + MSG_OUT + message_offset);
+ if (aic_inb(p, MSG_OUT) == MSG_IDENTIFYFLAG)
+ {
+ p->msg_buf[p->msg_index++] = scb->tag_action;
+ p->msg_buf[p->msg_index++] = scb->hscb->tag;
+ p->msg_len += 2;
+ }
+ p->msg_buf[p->msg_index++] = MSG_ABORT_TAG;
}
else
{
- outb(MSG_ABORT, p->base + MSG_OUT + message_offset);
+ p->msg_buf[p->msg_index++] = MSG_ABORT;
}
- outb(message_offset + 1, p->base + MSG_LEN);
- printk(KERN_WARNING "(scsi%d:%d:%d): Abort message sent.\n",
- p->host_no, TC_OF_SCB(scb));
+ p->msg_len++;
+ if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
+ printk(INFO_LEAD "Abort message mailed.\n", p->host_no,
+ CTL_OF_SCB(scb));
}
- else if (scb->flags & SCB_MSGOUT_WDTR)
- {
- aic7xxx_construct_wdtr(p, message_offset, BUS_16_BIT);
+ else if (scb->flags & SCB_MSGOUT_WDTR)
+ {
+ aic7xxx_construct_wdtr(p, (scb->flags & SCB_WDTR_16BIT));
}
else if (scb->flags & SCB_MSGOUT_SDTR)
{
- unsigned char target_scratch;
- unsigned short ultra_enable;
- int i, sxfr;
+ unsigned char period, offset;
/*
* Pull the user defined setting from scratch RAM.
*/
- target_scratch = inb(p->base + TARG_SCRATCH + scratch_offset);
- sxfr = target_scratch & SXFR;
- ultra_enable = inb(p->base + ULTRA_ENB) |
- (inb(p->base + ULTRA_ENB + 1) << 8);
- if (ultra_enable & target_mask)
- {
- sxfr |= 0x100;
- }
- for (i = 0; i < num_aic7xxx_syncrates; i++)
+ period = p->syncinfo[scratch_offset].period;
+ offset = p->syncinfo[scratch_offset].offset;
+ if ( (p->needsdtr_copy & target_mask) == 0)
{
- if (sxfr == aic7xxx_syncrates[i].rate)
- break;
+ period = 0;
+ offset = 0;
}
- aic7xxx_construct_sdtr(p, message_offset,
- aic7xxx_syncrates[i].period,
- target_scratch & WIDEXFER ?
- MAX_OFFSET_16BIT : MAX_OFFSET_8BIT);
+ aic7xxx_construct_sdtr(p, period, offset);
}
else
{
panic("aic7xxx: AWAITING_MSG for an SCB that does "
- "not have a waiting message.");
- }
+ "not have a waiting message.\n");
+ }
+ /*
+ * We've set everything up to send our message, now to actually do
+ * so we need to enable reqinit interrupts and let the interrupt
+ * handler do the rest. We don't want to unpause the sequencer yet
+ * though so we'll return early. We also have to make sure that
+ * we clear the SEQINT *BEFORE* we set the REQINIT handler active
+ * or else it's possible on VLB cards to loose the first REQINIT
+ * interrupt. Edge triggered EISA cards could also loose this
+ * interrupt, although PCI and level triggered cards should not
+ * have this problem since they continually interrupt the kernel
+ * until we take care of the situation.
+ */
+ aic_outb(p, CLRSEQINT, CLRINT);
+ p->msg_index = 0;
+ p->msg_type = MSG_TYPE_INITIATOR_MSGOUT;
+ p->flags |= AHC_HANDLING_REQINITS;
+ aic_outb(p, aic_inb(p, SIMODE1) | ENREQINIT, SIMODE1);
+ return;
}
break;
case DATA_OVERRUN:
{
- unsigned char scb_index = inb(p->base + SCB_TAG);
- unsigned char lastphase = inb(p->base + LASTPHASE);
- unsigned int i, overrun;
-
- scb = (p->scb_data->scb_array[scb_index]);
- overrun = inb(p->base + STCNT) | (inb(p->base + STCNT + 1) << 8) |
- (inb(p->base + STCNT + 2) << 16);
- overrun = 0x00FFFFFF - overrun;
- printk(KERN_WARNING "(scsi%d:%d:%d) Data overrun of %d bytes detected "
- "in %s phase, tag %d; forcing a retry.\n",
- p->host_no, TC_OF_SCB(scb), overrun,
- lastphase == P_DATAIN ? "Data-In" : "Data-Out",
- scb->hscb->tag);
- printk(KERN_WARNING "%s seen Data Phase. Length = %d, NumSGs = %d.\n",
- inb(p->base + SEQ_FLAGS) & DPHASE ? "Have" : "Haven't",
- aic7xxx_length(scb->cmd, 0), scb->sg_count);
- for (i = 0; i < scb->sg_count; i++)
+ unsigned char scb_index = aic_inb(p, SCB_TAG);
+ unsigned char lastphase = aic_inb(p, LASTPHASE);
+ unsigned int i;
+
+ scb = (p->scb_data->scb_array[scb_index]);
+ /*
+ * XXX - What do we really want to do on an overrun? The
+ * mid-level SCSI code should handle this, but for now,
+ * we'll just indicate that the command should retried.
+ * If we retrieved sense info on this target, then the
+ * base SENSE info should have been saved prior to the
+ * overrun error. In that case, we return DID_OK and let
+ * the mid level code pick up on the sense info. Otherwise
+ * we return DID_ERROR so the command will get retried.
+ */
+ if ( !(scb->flags & SCB_SENSE) )
{
- printk(KERN_INFO " sg[%d] - Addr 0x%x : Length %d\n",
- i, scb->sg_list[i].address, scb->sg_list[i].length);
+ printk(WARN_LEAD "Data overrun detected in %s phase, tag %d;\n",
+ p->host_no, CTL_OF_SCB(scb),
+ (lastphase == P_DATAIN) ? "Data-In" : "Data-Out", scb->hscb->tag);
+ printk(KERN_WARNING " %s seen Data Phase. Length=%d, NumSGs=%d.\n",
+ (aic_inb(p, SEQ_FLAGS) & DPHASE) ? "Have" : "Haven't",
+ scb->sg_length, scb->sg_count);
+ for (i = 0; i < scb->sg_count; i++)
+ {
+ printk(KERN_WARNING " sg[%d] - Addr 0x%x : Length %d\n",
+ i,
+ le32_to_cpu(scb->sg_list[i].address),
+ le32_to_cpu(scb->sg_list[i].length) );
+ }
+ aic7xxx_error(scb->cmd) = DID_ERROR;
}
- /*
- * XXX - What do we really want to do on an overrun? The
- * mid-level SCSI code should handle this, but for now,
- * we'll just indicate that the command should retried.
- */
- aic7xxx_error(scb->cmd) = DID_RETRY_COMMAND;
+ else
+ printk(INFO_LEAD "Data Overrun during SEND_SENSE operation.\n",
+ p->host_no, CTL_OF_SCB(scb));
+ }
+ break;
+
+ case TRACEPOINT:
+ {
+ printk(INFO_LEAD "Tracepoint #1 reached.\n", p->host_no, channel,
+ target, lun);
+ }
+ break;
+
+ case TRACEPOINT2:
+ {
+ printk(INFO_LEAD "Tracepoint #2 reached.\n", p->host_no, channel,
+ target, lun);
}
break;
-/* #if AIC7XXX_NOT_YET */
+#if AIC7XXX_NOT_YET
/* XXX Fill these in later */
case MSG_BUFFER_BUSY:
printk("aic7xxx: Message buffer busy.\n");
@@ -3515,33 +4137,376 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
case MSGIN_PHASEMIS:
printk("aic7xxx: Message-in phasemis.\n");
break;
-/*#endif */
-
- case ABORT_CMDCMPLT:
- /* This interrupt serves to pause the sequencer until we can clean
- * up the QOUTFIFO allowing us to handle any abort SCBs that may
- * completed yet still have an SCB in the QINFIFO or waiting for
- * selection queue. By the time we get here, we should have
- * already cleaned up the queues, so all we need to do is unpause
- * the sequencer.
- */
- break;
+#endif
- default: /* unknown */
- printk(KERN_WARNING "scsi%d: SEQINT, INTSTAT 0x%x, SCSISIGI 0x%x.\n",
- p->host_no, intstat, inb(p->base + SCSISIGI));
+ default: /* unknown */
+ printk(WARN_LEAD "Unknown SEQINT, INTSTAT 0x%x, SCSISIGI 0x%x.\n",
+ p->host_no, channel, target, lun, intstat,
+ aic_inb(p, SCSISIGI));
break;
}
/*
* Clear the sequencer interrupt and unpause the sequencer.
*/
- outb(CLRSEQINT, p->base + CLRINT);
+ aic_outb(p, CLRSEQINT, CLRINT);
unpause_sequencer(p, /* unpause always */ TRUE);
}
/*+F*************************************************************************
* Function:
+ * aic7xxx_parse_msg
+ *
+ * Description:
+ * Parses incoming messages into actions on behalf of
+ * aic7xxx_handle_reqinit
+ *_F*************************************************************************/
+static int
+aic7xxx_parse_msg(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
+{
+ int reject, done;
+ unsigned char target_scratch, scratch_offset;
+ unsigned short target_mask;
+
+ reject = done = FALSE;
+ scratch_offset = TARGET_INDEX(scb->cmd);
+ target_scratch = aic_inb(p, TARG_SCRATCH + scratch_offset);
+ target_mask = (0x01 << scratch_offset);
+
+ /*
+ * Parse as much of the message as is availible,
+ * rejecting it if we don't support it. When
+ * the entire message is availible and has been
+ * handled, return TRUE indicating that we have
+ * parsed an entire message.
+ */
+
+ if (p->msg_buf[0] != MSG_EXTENDED)
+ {
+ reject = TRUE;
+ }
+
+ /*
+ * Just accept the length byte outright and perform
+ * more checking once we know the message type.
+ */
+
+ if ( !reject && (p->msg_len > 2) )
+ {
+ switch(p->msg_buf[2])
+ {
+ case MSG_EXT_SDTR:
+ {
+ unsigned char period, response_period, offset;
+ unsigned char max_offset, saved_offset, rate;
+
+ if (p->msg_buf[1] != MSG_EXT_SDTR_LEN)
+ {
+ reject = TRUE;
+ break;
+ }
+
+ if (p->msg_len < (MSG_EXT_SDTR_LEN + 2))
+ {
+ break;
+ }
+
+ period = p->msg_buf[3];
+ saved_offset = p->msg_buf[4];
+
+ if (target_scratch & WIDEXFER)
+ {
+ max_offset = MAX_OFFSET_16BIT;
+ }
+ else
+ {
+ max_offset = MAX_OFFSET_8BIT;
+ }
+ offset = MIN(saved_offset, max_offset);
+ response_period = aic7xxx_scsirate(p, &rate, &period,
+ &offset, scb->cmd->target, scb->cmd->channel, /* set */ TRUE);
+ /* Preserve the WideXfer flag */
+ target_scratch = rate | (target_scratch & WIDEXFER);
+
+ /*
+ * Update the TARGET_SCRATCH, the SCSIRATE, and our syncinfo
+ * areas.
+ */
+ aic_outb(p, target_scratch, TARG_SCRATCH + scratch_offset);
+ aic_outb(p, target_scratch, SCSIRATE);
+ p->syncinfo[scratch_offset].period = response_period;
+ p->syncinfo[scratch_offset].offset = offset;
+
+ /*
+ * Did we start this, if not, or if we went to low and had to
+ * go async, then send an SDTR back to the target
+ */
+ p->needsdtr &= ~target_mask;
+ if (scb->flags & SCB_MSGOUT_SDTR)
+ {
+ if (saved_offset != offset)
+ {
+ p->needsdtr_copy &= ~target_mask;
+ reject = TRUE;
+ }
+ scb->flags &= ~SCB_MSGOUT_SDTR;
+ p->sdtr_pending &= ~target_mask;
+ }
+ else
+ {
+ scb->flags &= ~SCB_MSGOUT_BITS;
+ scb->flags |= SCB_MSGOUT_SDTR;
+ p->sdtr_pending |= target_mask;
+ aic_outb(p, HOST_MSG, MSG_OUT);
+ aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
+ }
+ done = TRUE;
+ break;
+ }
+ case MSG_EXT_WDTR:
+ {
+ unsigned char bus_width;
+
+ if (p->msg_buf[1] != MSG_EXT_WDTR_LEN)
+ {
+ reject = TRUE;
+ break;
+ }
+
+ if (p->msg_len < (MSG_EXT_WDTR_LEN + 2))
+ {
+ break;
+ }
+
+ bus_width = p->msg_buf[3];
+ p->needwdtr &= ~target_mask;
+ if (scb->flags & SCB_MSGOUT_WDTR)
+ {
+ switch(bus_width)
+ {
+ default:
+ {
+ reject = TRUE;
+ if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
+ (p->dev_flags[scratch_offset] & DEVICE_PRINT_WDTR) )
+ {
+ printk(INFO_LEAD "Requesting %d bit transfers, rejecting.\n",
+ p->host_no, CTL_OF_SCB(scb), 8 * (0x01 << bus_width));
+ p->dev_flags[scratch_offset] &= ~DEVICE_PRINT_WDTR;
+ }
+ } /* We fall through on purpose */
+ case MSG_EXT_WDTR_BUS_8_BIT:
+ {
+ bus_width = MSG_EXT_WDTR_BUS_8_BIT;
+ p->needwdtr_copy &= ~target_mask;
+ target_scratch &= 0x7f;
+ if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
+ (p->dev_flags[scratch_offset] & DEVICE_PRINT_WDTR) )
+ {
+ printk(INFO_LEAD "Using narrow (8 bit) transfers.\n",
+ p->host_no, CTL_OF_SCB(scb));
+ p->dev_flags[scratch_offset] &= ~DEVICE_PRINT_WDTR;
+ }
+ break;
+ }
+ case MSG_EXT_WDTR_BUS_16_BIT:
+ {
+ if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
+ (p->dev_flags[scratch_offset] & DEVICE_PRINT_WDTR) )
+ {
+ printk(INFO_LEAD "Using wide (16 bit) transfers.\n",
+ p->host_no, CTL_OF_SCB(scb));
+ p->dev_flags[scratch_offset] &= ~DEVICE_PRINT_WDTR;
+ }
+ target_scratch |= WIDEXFER;
+ break;
+ }
+ }
+ scb->flags &= ~SCB_MSGOUT_WDTR_16BIT;
+ p->wdtr_pending &= ~target_mask;
+ }
+ else
+ {
+ scb->flags &= ~SCB_MSGOUT_BITS;
+ switch(bus_width)
+ {
+ default:
+ {
+ if (p->type & AHC_WIDE)
+ {
+ bus_width = MSG_EXT_WDTR_BUS_16_BIT;
+ p->needwdtr_copy |= target_mask;
+ scb->flags |= SCB_MSGOUT_WDTR_16BIT;
+ target_scratch |= WIDEXFER;
+ if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
+ (p->dev_flags[scratch_offset] & DEVICE_PRINT_WDTR) )
+ {
+ printk(INFO_LEAD "Using wide (16 bit) transfers.\n",
+ p->host_no, CTL_OF_SCB(scb));
+ p->dev_flags[scratch_offset] &= ~DEVICE_PRINT_WDTR;
+ }
+ break;
+ }
+ } /* Fall through if we aren't a wide card */
+ case MSG_EXT_WDTR_BUS_8_BIT:
+ {
+ bus_width = MSG_EXT_WDTR_BUS_8_BIT;
+ p->needwdtr_copy &= ~target_mask;
+ scb->flags |= SCB_MSGOUT_WDTR_8BIT;
+ target_scratch &= 0x7f;
+ if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
+ (p->dev_flags[scratch_offset] & DEVICE_PRINT_WDTR) )
+ {
+ printk(INFO_LEAD "Using narrow (8 bit) transfers.\n",
+ p->host_no, CTL_OF_SCB(scb));
+ p->dev_flags[scratch_offset] &= ~DEVICE_PRINT_WDTR;
+ }
+ break;
+ }
+ }
+ aic_outb(p, HOST_MSG, MSG_OUT);
+ aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
+ p->wdtr_pending |= target_mask;
+ }
+ aic_outb(p, target_scratch, SCSIRATE);
+ aic_outb(p, target_scratch, TARG_SCRATCH + scratch_offset);
+ p->syncinfo[scratch_offset].offset =
+ (bus_width == MSG_EXT_WDTR_BUS_8_BIT) ?
+ MAX_OFFSET_8BIT : MAX_OFFSET_16BIT;
+ if ( !(p->wdtr_pending & target_mask) && !reject)
+ {
+ /*
+ * We've successfully completed the wide negotiation, so let's start
+ * up the sync negotiation now.
+ */
+ scb->flags &= ~SCB_MSGOUT_WDTR_16BIT;
+ if ((p->needsdtr & target_mask) && !(p->sdtr_pending & target_mask))
+ {
+ p->sdtr_pending |= target_mask;
+ scb->flags |= SCB_MSGOUT_SDTR;
+ aic_outb(p, HOST_MSG, MSG_OUT);
+ aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
+ }
+ }
+ done = TRUE;
+ break;
+ }
+ default:
+ {
+ reject = TRUE;
+ break;
+ }
+ } /* end of switch(p->msg_type) */
+ } /* end of if (!reject && (p->msg_len > 2)) */
+
+ if (reject)
+ {
+ aic_outb(p, MSG_MESSAGE_REJECT, MSG_OUT);
+ aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
+ }
+ return(done);
+}
+
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_handle_reqinit
+ *
+ * Description:
+ * Interrupt handler for REQINIT interrupts (used to transfer messages to
+ * and from devices).
+ *_F*************************************************************************/
+static void
+aic7xxx_handle_reqinit(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
+{
+ unsigned char lastbyte;
+ unsigned char phasemis;
+ int done;
+
+ switch(p->msg_type)
+ {
+ case MSG_TYPE_INITIATOR_MSGOUT:
+ {
+ if (p->msg_len == 0)
+ panic("aic7xxx: REQINIT with no active message!\n");
+
+ lastbyte = (p->msg_index == (p->msg_len - 1));
+ phasemis = ( aic_inb(p, SCSISIGI) & PHASE_MASK) != P_MESGOUT;
+
+ if (lastbyte || phasemis)
+ {
+ /* Time to end the message */
+ p->msg_len = 0;
+ p->msg_type = MSG_TYPE_NONE;
+ /*
+ * NOTE-TO-MYSELF: If you clear the REQINIT after you
+ * disable REQINITs, then cases of REJECT_MSG stop working
+ * and hang the bus
+ */
+ aic_outb(p, aic_inb(p, SIMODE1) & ~ENREQINIT, SIMODE1);
+ aic_outb(p, CLRSCSIINT, CLRINT);
+ p->flags &= ~AHC_HANDLING_REQINITS;
+
+ if (phasemis == 0)
+ {
+ aic_outb(p, p->msg_buf[p->msg_index], SINDEX);
+ aic_outb(p, 0, RETURN_1);
+ }
+ else
+ {
+ aic_outb(p, MSGOUT_PHASEMIS, RETURN_1);
+ }
+ unpause_sequencer(p, TRUE);
+ }
+ else
+ {
+ /*
+ * Present the byte on the bus (clearing REQINIT) but don't
+ * unpause the sequencer.
+ */
+ aic_outb(p, CLRREQINIT, CLRSINT1);
+ aic_outb(p, CLRSCSIINT, CLRINT);
+ aic_outb(p, p->msg_buf[p->msg_index++], SCSIDATL);
+ }
+ break;
+ }
+ case MSG_TYPE_INITIATOR_MSGIN:
+ {
+ phasemis = ( aic_inb(p, SCSISIGI) & PHASE_MASK ) != P_MESGIN;
+
+ if (phasemis == 0)
+ {
+ p->msg_len++;
+ /* Pull the byte in without acking it */
+ p->msg_buf[p->msg_index] = aic_inb(p, SCSIBUSL);
+ done = aic7xxx_parse_msg(p, scb);
+ /* Ack the byte */
+ aic_outb(p, CLRREQINIT, CLRSINT1);
+ aic_outb(p, CLRSCSIINT, CLRINT);
+ aic_inb(p, SCSIDATL);
+ p->msg_index++;
+ }
+ if (phasemis || done)
+ {
+ /* Time to end our message session */
+ p->msg_len = 0;
+ p->msg_type = MSG_TYPE_NONE;
+ p->flags &= ~AHC_HANDLING_REQINITS;
+ aic_outb(p, aic_inb(p, SIMODE1) & ~ENREQINIT, SIMODE1);
+ aic_outb(p, CLRSCSIINT, CLRINT);
+ unpause_sequencer(p, TRUE);
+ }
+ break;
+ }
+ default:
+ {
+ panic("aic7xxx: Unknown REQINIT message type.\n");
+ break;
+ }
+ } /* End of switch(p->msg_type) */
+}
+
+/*+F*************************************************************************
+ * Function:
* aic7xxx_handle_scsiint
*
* Description:
@@ -3554,8 +4519,8 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
unsigned char status;
struct aic7xxx_scb *scb;
- scb_index = inb(p->base + SCB_TAG);
- status = inb(p->base + SSTAT1);
+ scb_index = aic_inb(p, SCB_TAG);
+ status = aic_inb(p, SSTAT1);
if (scb_index < p->scb_data->numscbs)
{
@@ -3570,14 +4535,35 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
scb = NULL;
}
+
+ if ( (p->flags & AHC_HANDLING_REQINITS) && (status & REQINIT) )
+ {
+ if (scb)
+ {
+ aic7xxx_handle_reqinit(p, scb);
+ }
+ else
+ {
+ p->flags &= ~AHC_HANDLING_REQINITS;
+ aic_outb(p, aic_inb(p, SIMODE1) & ~ENREQINIT, SIMODE1);
+ aic_outb(p, CLRREQINIT, CLRSINT1);
+ aic_outb(p, CLRSCSIINT, CLRINT);
+ p->msg_type = MSG_TYPE_NONE;
+ p->msg_index = 0;
+ p->msg_len = 0;
+ }
+ return;
+ }
+
if ((status & SCSIRSTI) != 0)
{
- char channel;
+ int channel;
- channel = (inb(p->base + SBLKCTL) & SELBUSB) ? 'B' : 'A';
+ channel = (aic_inb(p, SBLKCTL) & SELBUSB) >> 3;
- printk(KERN_WARNING "scsi%d: SCSIINT - Someone reset channel %c.\n",
- p->host_no, channel);
+ if (aic7xxx_verbose & VERBOSE_RESET)
+ printk(WARN_LEAD "Someone else reset the channel!!\n",
+ p->host_no, channel, -1, -1);
/*
* Go through and abort all commands for the channel, but do not
* reset the channel again.
@@ -3592,35 +4578,27 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
* chances are pretty good that the bus free was in response to
* one of our abort requests.
*/
- unsigned char lastphase = inb(p->base + LASTPHASE);
- unsigned char target = (inb(p->base + SAVED_TCL) >> 4) & 0x0F;
- char channel = (inb(p->base + SBLKCTL) & SELBUSB) ? 'B' : 'A';
+ unsigned char lastphase = aic_inb(p, LASTPHASE);
+ unsigned char saved_tcl = aic_inb(p, SAVED_TCL);
+ unsigned char target = (saved_tcl >> 4) & 0x0F;
+ int channel = (aic_inb(p, SBLKCTL) & SELBUSB) >> 3;
int printerror = TRUE;
- outb(0, p->base + SCSISEQ);
+ aic_outb(p, 0, SCSISEQ);
if (lastphase == P_MESGOUT)
{
- unsigned char sindex;
unsigned char message;
- sindex = inb(p->base + SINDEX);
- message = inb(p->base + sindex - 1);
+ message = aic_inb(p, SINDEX);
- if (message == MSG_ABORT)
- {
- printk(KERN_WARNING "(scsi%d:%d:%d) SCB %d abort completed.\n",
- p->host_no, TC_OF_SCB(scb), scb->hscb->tag);
- aic7xxx_reset_device(p, target, channel, SCB_LUN(scb), SCB_LIST_NULL);
- aic7xxx_run_done_queue(p, /* complete */ TRUE);
- scb = NULL;
- printerror = 0;
- }
- else if (message == MSG_ABORT_TAG)
+ if ((message == MSG_ABORT) || (message == MSG_ABORT_TAG))
{
- printk(KERN_WARNING "(scsi%d:%d:%d) SCB %d abort Tag completed.\n",
- p->host_no, TC_OF_SCB(scb), scb->hscb->tag);
- aic7xxx_reset_device(p, target, channel, SCB_LUN(scb), scb->hscb->tag);
- aic7xxx_run_done_queue(p, /* complete */ TRUE);
+ if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
+ printk(INFO_LEAD "SCB %d abort delivered.\n", p->host_no,
+ CTL_OF_SCB(scb), scb->hscb->tag);
+ aic7xxx_reset_device(p, target, channel, ALL_LUNS,
+ (message == MSG_ABORT) ? SCB_LIST_NULL : scb->hscb->tag );
+ aic7xxx_run_done_queue(p, FALSE);
scb = NULL;
printerror = 0;
}
@@ -3645,20 +4623,26 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
{
tag = SCB_LIST_NULL;
}
- aic7xxx_reset_device(p, target, channel, SCB_LUN(scb), tag);
+ aic7xxx_reset_device(p, target, channel, ALL_LUNS, tag);
+ aic7xxx_run_done_queue(p, FALSE);
}
else
- {
- aic7xxx_reset_device(p, target, channel, ALL_LUNS, SCB_LIST_NULL);
+ { /* Since we don't really know what happened here, we'll wait */
+ /* for the commands to timeout and get aborted if need be */
+ aic7xxx_add_curscb_to_free_list(p);
}
- printk(KERN_WARNING "scsi%d: Unexpected busfree, LASTPHASE = 0x%x, "
- "SEQADDR = 0x%x\n", p->host_no, lastphase,
- (inb(p->base + SEQADDR1) << 8) | inb(p->base + SEQADDR0));
+ printk(INFO_LEAD "Unexpected busfree, LASTPHASE = 0x%x, "
+ "SEQADDR = 0x%x\n", p->host_no, channel, target, -1, lastphase,
+ (aic_inb(p, SEQADDR1) << 8) | aic_inb(p, SEQADDR0));
+ scb = NULL;
}
- outb(inb(p->base + SIMODE1) & ~ENBUSFREE, p->base + SIMODE1);
- outb(CLRBUSFREE, p->base + CLRSINT1);
- outb(CLRSCSIINT, p->base + CLRINT);
+ aic_outb(p, aic_inb(p, SIMODE1) & ~(ENBUSFREE|ENREQINIT),
+ SIMODE1);
+ p->flags &= ~AHC_HANDLING_REQINITS;
+ aic_outb(p, CLRBUSFREE | CLRREQINIT, CLRSINT1);
+ aic_outb(p, CLRSCSIINT, CLRINT);
restart_sequencer(p);
+ unpause_sequencer(p, TRUE);
}
else if ((status & SELTO) != 0)
{
@@ -3666,9 +4650,18 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
unsigned char nextscb;
Scsi_Cmnd *cmd;
- scbptr = inb(p->base + WAITING_SCBH);
- outb(scbptr, p->base + SCBPTR);
- scb_index = inb(p->base + SCB_TAG);
+ scbptr = aic_inb(p, WAITING_SCBH);
+ if (scbptr >= p->scb_data->maxhscbs)
+ {
+ scb_index = SCB_LIST_NULL;
+ printk(WARN_LEAD "Bad scbptr %d during SELTO.\n",
+ p->host_no, -1, -1, -1, scbptr);
+ }
+ else
+ {
+ aic_outb(p, scbptr, SCBPTR);
+ scb_index = aic_inb(p, SCB_TAG);
+ }
scb = NULL;
if (scb_index < p->scb_data->numscbs)
@@ -3681,63 +4674,80 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
}
if (scb == NULL)
{
- printk(KERN_WARNING "scsi%d: Referenced SCB %d not valid during SELTO.\n",
- p->host_no, scb_index);
+ printk(WARN_LEAD "Referenced SCB %d not valid during SELTO.\n",
+ p->host_no, -1, -1, -1, scb_index);
printk(KERN_WARNING " SCSISEQ = 0x%x SEQADDR = 0x%x SSTAT0 = 0x%x "
- "SSTAT1 = 0x%x\n", inb(p->base + SCSISEQ),
- inb(p->base + SEQADDR0) | (inb(p->base + SEQADDR1) << 8),
- inb(p->base + SSTAT0), inb(p->base + SSTAT1));
+ "SSTAT1 = 0x%x\n", aic_inb(p, SCSISEQ),
+ aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8),
+ aic_inb(p, SSTAT0), aic_inb(p, SSTAT1));
}
else
{
- /*
- * XXX - If we queued an abort tag, go clean up the disconnected list.
- */
cmd = scb->cmd;
cmd->result = (DID_TIME_OUT << 16);
/*
- * Clear an pending messages for the timed out
- * target and mark the target as free.
+ * Clear out this hardware SCB
+ */
+ aic_outb(p, 0, SCB_CONTROL);
+
+ /*
+ * Clear out a few values in the card that are in an undetermined
+ * state.
*/
- outb(0, p->base + MSG_LEN);
- aic7xxx_index_busy_target(p, cmd->target,
- cmd->channel ? 'B': 'A', /*unbusy*/ TRUE);
- outb(0, p->base + SCB_CONTROL);
+ aic_outb(p, MSG_NOOP, MSG_OUT);
/*
* Shift the waiting for selection queue forward
*/
- nextscb = inb(p->base + SCB_NEXT);
- outb(nextscb, p->base + WAITING_SCBH);
+ nextscb = aic_inb(p, SCB_NEXT);
+ aic_outb(p, nextscb, WAITING_SCBH);
/*
* Put this SCB back on the free list.
*/
aic7xxx_add_curscb_to_free_list(p);
+ /*
+ * XXX - If we queued an abort tag, go clean up the disconnected list.
+ * We know that this particular SCB had to be the queued abort since
+ * the disconnected SCB would have gotten a reconnect instead.
+ * However, if this is an abort command, then DID_TIMEOUT isn't
+ * appropriate, neither is returning the command for that matter.
+ * What we need to do then is to let the command timeout again so
+ * we get a reset since this abort just failed.
+ */
+ if (p->flags & SCB_QUEUED_ABORT)
+ {
+ cmd->result = 0;
+ scb->flags &= ~SCB_QUEUED_ABORT;
+ scb = NULL;
+ }
}
/*
* Stop the selection.
*/
- outb(0, p->base + SCSISEQ);
- outb(CLRSELTIMEO | CLRBUSFREE, p->base + CLRSINT1);
- outb(CLRSCSIINT, p->base + CLRINT);
+ aic_outb(p, 0, SCSISEQ);
+ aic_outb(p, aic_inb(p, SIMODE1) & ~ENREQINIT, SIMODE1);
+ p->flags &= ~AHC_HANDLING_REQINITS;
+ aic_outb(p, CLRSELTIMEO | CLRBUSFREE | CLRREQINIT, CLRSINT1);
+ aic_outb(p, CLRSCSIINT, CLRINT);
restart_sequencer(p);
+ unpause_sequencer(p, TRUE);
}
else if (scb == NULL)
{
- printk(KERN_WARNING "scsi%d: aic7xxx_isr - referenced scb not valid "
+ printk(WARN_LEAD "aic7xxx_isr - referenced scb not valid "
"during scsiint 0x%x scb(%d)\n"
" SIMODE0 0x%x, SIMODE1 0x%x, SSTAT0 0x%x, SEQADDR 0x%x\n",
- p->host_no, status, scb_index, inb(p->base + SIMODE0),
- inb(p->base + SIMODE1), inb(p->base + SSTAT0),
- (inb(p->base + SEQADDR1) << 8) | inb(p->base + SEQADDR0));
+ p->host_no, -1, -1, -1, status, scb_index, aic_inb(p, SIMODE0),
+ aic_inb(p, SIMODE1), aic_inb(p, SSTAT0),
+ (aic_inb(p, SEQADDR1) << 8) | aic_inb(p, SEQADDR0));
/*
* Turn off the interrupt and set status to zero, so that it
* falls through the rest of the SCSIINT code.
*/
- outb(status, p->base + CLRSINT1);
- outb(CLRSCSIINT, p->base + CLRINT);
+ aic_outb(p, status, CLRSINT1);
+ aic_outb(p, CLRSCSIINT, CLRINT);
unpause_sequencer(p, /* unpause always */ TRUE);
scb = NULL;
}
@@ -3749,7 +4759,7 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
char *phase;
Scsi_Cmnd *cmd;
unsigned char mesg_out = MSG_NOOP;
- unsigned char lastphase = inb(p->base + LASTPHASE);
+ unsigned char lastphase = aic_inb(p, LASTPHASE);
cmd = scb->cmd;
switch (lastphase)
@@ -3784,8 +4794,8 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
* A parity error has occurred during a data
* transfer phase. Flag it and continue.
*/
- printk(KERN_WARNING "(scsi%d:%d:%d) Parity error during phase %s.\n",
- p->host_no, TC_OF_SCB(scb), phase);
+ printk(WARN_LEAD "Parity error during phase %s.\n",
+ p->host_no, CTL_OF_SCB(scb), phase);
/*
* We've set the hardware to assert ATN if we get a parity
@@ -3795,19 +4805,11 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
*/
if (mesg_out != MSG_NOOP)
{
- outb(mesg_out, p->base + MSG_OUT);
- outb(1, p->base + MSG_LEN);
+ aic_outb(p, mesg_out, MSG_OUT);
scb = NULL;
}
- else
- {
- /*
- * Should we allow the target to make this decision for us?
- */
- cmd->result = DID_RETRY_COMMAND << 16;
- }
- outb(CLRSCSIPERR, p->base + CLRSINT1);
- outb(CLRSCSIINT, p->base + CLRINT);
+ aic_outb(p, CLRSCSIPERR, CLRSINT1);
+ aic_outb(p, CLRSCSIINT, CLRINT);
unpause_sequencer(p, /* unpause_always */ TRUE);
}
else
@@ -3816,214 +4818,229 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
* We don't know what's going on. Turn off the
* interrupt source and try to continue.
*/
- printk(KERN_WARNING "aic7xxx: SSTAT1(0x%x).\n", status);
- outb(status, p->base + CLRSINT1);
- outb(CLRSCSIINT, p->base + CLRINT);
+ if (aic7xxx_verbose & VERBOSE_SCSIINT)
+ printk(INFO_LEAD "Unknown SCSIINT status, SSTAT1(0x%x).\n",
+ p->host_no, -1, -1, -1, status);
+ aic_outb(p, status, CLRSINT1);
+ aic_outb(p, CLRSCSIINT, CLRINT);
unpause_sequencer(p, /* unpause always */ TRUE);
scb = NULL;
}
if (scb != NULL)
{
aic7xxx_done(p, scb);
- aic7xxx_done_cmds_complete(p);
}
}
+#ifdef CONFIG_PCI
+
+#define DPE 0x80
+#define SSE 0x40
+#define RMA 0x20
+#define RTA 0x10
+#define STA 0x08
+#define DPR 0x01
+
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_pci_intr
+ *
+ * Description:
+ * Check the scsi card for PCI errors and clear the interrupt
+ *
+ * NOTE: If you don't have this function and a 2940 card encounters
+ * a PCI error condition, the machine will end up locked as the
+ * interrupt handler gets slammed with non-stop PCI error interrupts
+ *-F*************************************************************************/
+static void
+aic7xxx_pci_intr(struct aic7xxx_host *p)
+{
+ unsigned char status1;
+ int error;
+
+ error = 0;
+ error = pcibios_read_config_byte(p->pci_bus, p->pci_device_fn,
+ PCI_STATUS, &status1);
+
+ if (error == 0)
+ {
+ if (status1 & DPE)
+ printk(WARN_LEAD "Data Parity Error during PCI address or PCI write"
+ "phase.\n", p->host_no, -1, -1, -1);
+ if (status1 & SSE)
+ printk(WARN_LEAD "Signal System Error Detected\n", p->host_no,
+ -1, -1, -1);
+ if (status1 & RMA)
+ printk(WARN_LEAD "Received a PCI Master Abort\n", p->host_no,
+ -1, -1, -1);
+ if (status1 & RTA)
+ printk(WARN_LEAD "Received a PCI Target Abort\n", p->host_no,
+ -1, -1, -1);
+ if (status1 & STA)
+ printk(WARN_LEAD "Signaled a PCI Target Abort\n", p->host_no,
+ -1, -1, -1);
+ if (status1 & DPR)
+ printk(WARN_LEAD "Data Parity Error has been reported via PCI pin "
+ "PERR#\n", p->host_no, -1, -1, -1);
+ }
+ else
+ {
+ printk(WARN_LEAD "Error reading PCI config register during PCI ERROR"
+ "interrupt.\n", p->host_no, -1, -1, -1);
+ aic_outb(p, CLRPARERR, CLRINT);
+ return;
+ }
+
+ pcibios_write_config_byte(p->pci_bus, p->pci_device_fn,
+ PCI_STATUS, status1);
+ if (status1 & (DPR|RMA|RTA))
+ aic_outb(p, CLRPARERR, CLRINT);
+
+}
+#endif
+
/*+F*************************************************************************
* Function:
* aic7xxx_isr
*
* Description:
* SCSI controller interrupt handler.
- *
- * NOTE: Since we declared this using SA_INTERRUPT, interrupts should
- * be disabled all through this function unless we say otherwise.
*-F*************************************************************************/
static void
aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
{
struct aic7xxx_host *p;
unsigned char intstat;
- unsigned long flags;
- p = (struct aic7xxx_host *) aic7xxx_boards[irq]->hostdata;
+ p = (struct aic7xxx_host *)dev_id;
/*
- * Search for the host with a pending interrupt. If we can't find
- * one, then we've encountered a spurious interrupt.
+ * Just a few sanity checks. Make sure p != NULL, that we have an
+ * interrupt pending, and that we aren't already in our int handler.
+ * Also, if PCI, then we are going to check for a PCI bus error status
+ * should we get too many spurious interrupts.
*/
- while ((p != NULL) && !(inb(p->base + INTSTAT) & INT_PEND))
+ if (p == NULL)
+ {
+ printk(KERN_WARNING "aic7xxx: ISR routine called with NULL dev_id\n");
+ return;
+ }
+ else if (!(aic_inb(p, INTSTAT) & INT_PEND))
{
- if (p->next == NULL)
+#ifdef CONFIG_PCI
+ if ((p->type & AHC_AIC78x0) && (p->spurious_int > 500))
{
- p = NULL;
+ if ( aic_inb(p, ERROR) & PCIERRSTAT )
+ {
+ aic7xxx_pci_intr(p);
+ }
+ p->spurious_int = 0;
}
else
{
- p = (struct aic7xxx_host *) p->next->hostdata;
+ p->spurious_int++;
}
+#endif
+ return;
}
-
- if (p == NULL)
+ else if (p->flags & AHC_IN_ISR)
+ {
return;
+ }
/*
* Handle all the interrupt sources - especially for SCSI
* interrupts, we won't get a second chance at them.
*/
- intstat = inb(p->base + INTSTAT);
+ intstat = aic_inb(p, INTSTAT);
+ p->spurious_int = 0;
/*
* Keep track of interrupts for /proc/scsi
*/
p->isr_count++;
-
- if (!(p->flags & A_SCANNED) && (p->isr_count == 1))
- {
- /*
- * We must only have one card at this IRQ and it must have been
- * added to the board data before the spurious interrupt occurred.
- * It is sufficient that we check isr_count and not the spurious
- * interrupt count.
- */
- printk("scsi%d: Encountered spurious interrupt.\n", p->host_no);
- if (intstat)
- {
- /* Try clearing all interrupts. */
- outb(CLRBRKADRINT | CLRSCSIINT | CLRCMDINT | CLRSEQINT, p->base + CLRINT);
- }
- return;
- }
-
- if (p->flags & IN_ISR)
- {
- printk(KERN_WARNING "scsi%d: Warning!! Interrupt routine called reentrantly!\n",
- p->host_no);
- return;
- }
+ p->flags |= AHC_IN_ISR;
/*
* Indicate that we're in the interrupt handler.
*/
- save_flags(flags);
- cli();
- p->flags |= IN_ISR;
-
if (intstat & CMDCMPLT)
{
struct aic7xxx_scb *scb = NULL;
Scsi_Cmnd *cmd;
- unsigned char qoutcnt;
unsigned char scb_index;
- int i, interrupts_cleared = 0;
/*
+ * Clear interrupt status before running the completion loop.
+ * This eliminates a race condition whereby a command could
+ * complete between the last check of qoutfifo and the
+ * CLRCMDINT statement. This would result in us thinking the
+ * qoutfifo was empty when it wasn't, and in actuality be a lost
+ * completion interrupt. With multiple devices or tagged queueing
+ * this could be very bad if we caught all but the last completion
+ * and no more are imediately sent.
+ */
+ aic_outb(p, CLRCMDINT, CLRINT);
+ /*
* The sequencer will continue running when it
* issues this interrupt. There may be >1 commands
* finished, so loop until we've processed them all.
*/
- qoutcnt = inb(p->base + QOUTCNT) & p->qcntmask;
-#if 1
- if (qoutcnt >= p->qfullcount - 1)
- printk(KERN_WARNING "aic7xxx: Command complete near Qfull count, "
- "qoutcnt = %d.\n", qoutcnt);
-#endif
- while (qoutcnt > 0)
+ while (p->qoutfifo[p->qoutfifonext] != SCB_LIST_NULL)
{
- if ((p->flags & PAGE_ENABLED) != 0)
+ scb_index = p->qoutfifo[p->qoutfifonext];
+ p->qoutfifo[p->qoutfifonext++] = SCB_LIST_NULL;
+ if ( scb_index >= p->scb_data->numscbs )
+ scb = NULL;
+ else
+ scb = p->scb_data->scb_array[scb_index];
+ if (scb == NULL)
{
- p->cmdoutcnt += qoutcnt;
- if (p->cmdoutcnt >= p->qfullcount)
- {
- /*
- * Since paging only occurs on aic78x0 chips, we can use
- * Auto Access Pause to clear the command count.
- */
- outb(0, p->base + CMDOUTCNT);
- p->cmdoutcnt = 0;
- }
+ printk(WARN_LEAD "CMDCMPLT with invalid SCB index %d\n", p->host_no,
+ -1, -1, -1, scb_index);
+ continue;
}
- for (i = 0; i < qoutcnt; i++)
+ else if (!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL))
{
- scb_index = inb(p->base + QOUTFIFO);
- scb = p->scb_data->scb_array[scb_index];
- if (scb == NULL)
- {
- printk(KERN_WARNING "scsi%d: CMDCMPLT with invalid SCB index %d, "
- "QOUTCNT %d, QINCNT %d\n", p->host_no, scb_index,
- inb(p->base + QOUTCNT), inb(p->base + QINCNT));
- continue;
- }
- else if (!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL))
- {
- printk(KERN_WARNING "scsi%d: CMDCMPLT without command for SCB %d, "
- "QOUTCNT %d, QINCNT %d, SCB flags 0x%x, cmd 0x%lx\n",
- p->host_no, scb_index, inb(p->base + QOUTCNT),
- inb(p->base + QINCNT), scb->flags, (unsigned long) scb->cmd);
- continue;
- }
- cmd = scb->cmd;
- if (scb->hscb->residual_SG_segment_count != 0)
- {
- aic7xxx_calculate_residual(p, scb);
- }
- if ((scb->flags & SCB_QUEUED_ABORT) != 0)
- {
- /*
- * Have to clean up any possible entries in the
- * waiting queue and the QINFIFO.
- */
- int target;
- char channel;
- int lun;
- unsigned char tag;
-
- tag = SCB_LIST_NULL;
- target = cmd->target;
- lun = cmd->lun;
- channel = (scb->hscb->target_channel_lun & SELBUSB) ? 'B' : 'A';
- if (scb->hscb->control & TAG_ENB)
+ printk(WARN_LEAD "CMDCMPLT without command for SCB %d, SCB flags "
+ "0x%x, cmd 0x%lx\n", p->host_no, -1, -1, -1, scb_index, scb->flags,
+ (unsigned long) scb->cmd);
+ continue;
+ }
+ switch (status_byte(scb->hscb->target_status))
+ {
+ case QUEUE_FULL:
+ case BUSY:
+ scb->hscb->target_status = 0;
+ scb->cmd->result = 0;
+ aic7xxx_error(scb->cmd) = DID_OK;
+ break;
+ default:
+ cmd = scb->cmd;
+ if (scb->hscb->residual_SG_segment_count != 0)
{
- tag = scb->hscb->tag;
+ aic7xxx_calculate_residual(p, scb);
}
- aic7xxx_reset_device(p, target, channel, lun, tag);
- /*
- * Run the done queue, but don't complete the commands; we
- * do this once at the end of the loop.
- */
- aic7xxx_run_done_queue(p, /*complete*/ FALSE);
- }
- cmd->result |= (aic7xxx_error(cmd) << 16);
- p->device_status[TARGET_INDEX(cmd)].flags |= DEVICE_SUCCESS;
- aic7xxx_done(p, scb);
- }
- /*
- * Clear interrupt status before checking the output queue again.
- * This eliminates a race condition whereby a command could
- * complete between the queue poll and the interrupt clearing,
- * so notification of the command being complete never made it
- * back up to the kernel.
- */
- outb(CLRCMDINT, p->base + CLRINT);
- interrupts_cleared++;
- qoutcnt = inb(p->base + QOUTCNT) & p->qcntmask;
- }
-
- if (interrupts_cleared == 0)
- {
- outb(CLRCMDINT, p->base + CLRINT);
+ cmd->result |= (aic7xxx_error(cmd) << 16);
+ if (scb->tag_action)
+ p->dev_flags[TARGET_INDEX(cmd)] |=
+ DEVICE_TAGGED_SUCCESS | DEVICE_SUCCESS | DEVICE_PRESENT;
+ else
+ p->dev_flags[TARGET_INDEX(cmd)] |=
+ DEVICE_SUCCESS | DEVICE_PRESENT;
+ aic7xxx_done(p, scb);
+ break;
+ }
}
-
- aic7xxx_done_cmds_complete(p);
}
if (intstat & BRKADRINT)
{
int i;
- unsigned char errno = inb(p->base + ERROR);
+ unsigned char errno = aic_inb(p, ERROR);
- printk(KERN_ERR "scsi%d: BRKADRINT error(0x%x):\n", p->host_no, errno);
+ printk(KERN_ERR "(scsi%d) BRKADRINT error(0x%x):\n", p->host_no, errno);
for (i = 0; i < NUMBER(hard_error); i++)
{
if (errno & hard_error[i].errno)
@@ -4031,11 +5048,15 @@ aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
printk(KERN_ERR " %s\n", hard_error[i].errmesg);
}
}
- printk("scsi%d: BRKADRINT, error 0x%x, seqaddr 0x%x.\n", p->host_no,
- inb(p->base + ERROR),
- (inb(p->base + SEQADDR1) << 8) | inb(p->base + SEQADDR0));
- aic7xxx_reset_device(p, ALL_TARGETS, ALL_CHANNELS, ALL_LUNS, SCB_LIST_NULL);
- aic7xxx_run_done_queue(p, /*complete*/ TRUE);
+ printk(KERN_ERR "(scsi%d) LINE=%d\n", p->host_no,
+ (((aic_inb(p, SEQADDR1) << 8) & 0x100) | aic_inb(p, SEQADDR0)));
+ aic7xxx_reset_channel(p, 0, TRUE);
+ if ( p->type & AHC_TWIN )
+ {
+ aic7xxx_reset_channel(p, 1, TRUE);
+ restart_sequencer(p);
+ }
+ aic_outb(p, CLRBRKADRINT, CLRINT);
}
if (intstat & SEQINT)
@@ -4047,14 +5068,37 @@ aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
{
aic7xxx_handle_scsiint(p, intstat);
}
-
- if (p->waiting_scbs.head != NULL)
+ if(!(p->flags & (AHC_IN_ABORT | AHC_IN_RESET)))
{
+ aic7xxx_done_cmds_complete(p);
aic7xxx_run_waiting_queues(p);
}
+ p->flags &= ~AHC_IN_ISR;
+}
- p->flags &= ~IN_ISR;
- restore_flags(flags);
+/*+F*************************************************************************
+ * Function:
+ * do_aic7xxx_isr
+ *
+ * Description:
+ * This is a gross hack to solve a problem in linux kernels 2.1.85 and
+ * above. Please, children, do not try this at home, and if you ever see
+ * anything like it, please inform the Gross Hack Police immediately
+ *-F*************************************************************************/
+static void
+do_aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
+{
+ unsigned long cpu_flags;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,95)
+
+ spin_lock_irqsave(&io_request_lock, cpu_flags);
+ aic7xxx_isr(irq, dev_id, regs);
+ spin_unlock_irqrestore(&io_request_lock, cpu_flags);
+#else
+ DRIVER_LOCK
+ aic7xxx_isr(irq, dev_id, regs);
+ DRIVER_UNLOCK
+#endif
}
/*+F*************************************************************************
@@ -4077,54 +5121,58 @@ aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
static void
aic7xxx_device_queue_depth(struct aic7xxx_host *p, Scsi_Device *device)
{
- int default_depth = 2;
+ int default_depth = 3;
+ unsigned char tindex;
+ unsigned short target_mask;
+
+ tindex = device->id | (device->channel << 3);
+ target_mask = (1 << tindex);
device->queue_depth = default_depth;
-#ifdef AIC7XXX_TAGGED_QUEUEING
+ p->dev_mid_level_queue_depth[tindex] = 3;
+ p->dev_temp_queue_depth[tindex] = 1;
+ p->dev_max_queue_depth[tindex] = 1;
+ p->tagenable &= ~target_mask;
+
if (device->tagged_supported)
{
- unsigned short target_mask;
int tag_enabled = TRUE;
- target_mask = (1 << (device->id | (device->channel << 3)));
-
#ifdef AIC7XXX_CMDS_PER_LUN
default_depth = AIC7XXX_CMDS_PER_LUN;
#else
- if (p->scb_data->maxhscbs <= 4)
- {
- default_depth = 4; /* Not many SCBs to work with. */
- }
- else
- {
- default_depth = 8;
- }
+ default_depth = 8; /* Not many SCBs to work with. */
#endif
if (!(p->discenable & target_mask))
{
- printk(KERN_INFO "(scsi%d:%d:%d) Disconnection disabled, unable to "
+ if (aic7xxx_verbose & VERBOSE_QUEUE)
+ printk(INFO_LEAD "Disconnection disabled, unable to "
"enable tagged queueing.\n",
- p->host_no, device->id, device->channel);
+ p->host_no, device->channel, device->id, device->lun);
}
else
{
-#ifndef AIC7XXX_TAGGED_QUEUEING_BY_DEVICE
- device->queue_depth = default_depth;
-#else
if (p->instance >= NUMBER(aic7xxx_tag_info))
{
+ static int print_warning = TRUE;
+ if(print_warning)
+ {
+ printk(KERN_INFO "aic7xxx: WARNING, insufficient tag_info instances for"
+ " installed controllers.\n");
+ printk(KERN_INFO "aic7xxx: Please update the aic7xxx_tag_info array in"
+ " the aic7xxx.c source file.\n");
+ print_warning = FALSE;
+ }
device->queue_depth = default_depth;
}
else
{
- unsigned char tindex;
- tindex = device->id | (device->channel << 3);
- if (aic7xxx_tag_info[p->instance].tag_commands[tindex] < 0)
+ if (aic7xxx_tag_info[p->instance].tag_commands[tindex] == 255)
{
tag_enabled = FALSE;
- device->queue_depth = 2; /* Tagged queueing is disabled. */
+ device->queue_depth = 3; /* Tagged queueing is disabled. */
}
else if (aic7xxx_tag_info[p->instance].tag_commands[tindex] == 0)
{
@@ -4136,21 +5184,24 @@ aic7xxx_device_queue_depth(struct aic7xxx_host *p, Scsi_Device *device)
aic7xxx_tag_info[p->instance].tag_commands[tindex];
}
}
-#endif
if ((device->tagged_queue == 0) && tag_enabled)
{
- if (aic7xxx_verbose)
+ if (aic7xxx_verbose & VERBOSE_QUEUE)
{
- printk(KERN_INFO "(scsi%d:%d:%d) Enabled tagged queuing, "
- "queue depth %d.\n", p->host_no,
- device->id, device->channel, device->queue_depth);
+ printk(INFO_LEAD "Enabled tagged queuing, queue depth %d.\n",
+ p->host_no, device->channel, device->id,
+ device->lun, device->queue_depth);
}
+ p->dev_max_queue_depth[tindex] = device->queue_depth;
+ p->dev_temp_queue_depth[tindex] = device->queue_depth;
+ p->dev_mid_level_queue_depth[tindex] = device->queue_depth;
+ p->tagenable |= target_mask;
+ p->orderedtag |= target_mask;
device->tagged_queue = 1;
device->current_tag = SCB_LIST_NULL;
}
}
}
-#endif
}
/*+F*************************************************************************
@@ -4171,14 +5222,27 @@ aic7xxx_select_queue_depth(struct Scsi_Host *host,
{
Scsi_Device *device;
struct aic7xxx_host *p = (struct aic7xxx_host *) host->hostdata;
+ int scbnum;
+ scbnum = 0;
for (device = scsi_devs; device != NULL; device = device->next)
{
if (device->host == host)
{
aic7xxx_device_queue_depth(p, device);
+ scbnum += device->queue_depth;
}
}
+ while (scbnum > p->scb_data->numscbs)
+ {
+ /*
+ * Pre-allocate the needed SCBs to get around the possibility of having
+ * to allocate some when memory is more or less exhausted and we need
+ * the SCB in order to perform a swap operation (possible deadlock)
+ */
+ if ( aic7xxx_allocate_scb(p, TRUE) == NULL )
+ return;
+ }
}
/*+F*************************************************************************
@@ -4203,8 +5267,8 @@ aic7xxx_select_queue_depth(struct Scsi_Host *host,
* The fourth byte's lowest bit seems to be an enabled/disabled
* flag (rest of the bits are reserved?).
*-F*************************************************************************/
-static aha_chip_type
-aic7xxx_probe(int slot, int base, aha_status_type *bios)
+static ahc_type
+aic7xxx_probe(int slot, int base, ahc_flag_type *flags)
{
int i;
unsigned char buf[4];
@@ -4212,13 +5276,13 @@ aic7xxx_probe(int slot, int base, aha_status_type *bios)
static struct {
int n;
unsigned char signature[sizeof(buf)];
- aha_chip_type type;
+ ahc_type type;
int bios_disabled;
} AIC7xxx[] = {
- { 4, { 0x04, 0x90, 0x77, 0x71 }, AIC_7771, FALSE }, /* host adapter 274x */
- { 4, { 0x04, 0x90, 0x77, 0x70 }, AIC_7770, FALSE }, /* motherboard 7770 */
- { 4, { 0x04, 0x90, 0x77, 0x56 }, AIC_284x, FALSE }, /* 284x BIOS enabled */
- { 4, { 0x04, 0x90, 0x77, 0x57 }, AIC_284x, TRUE } /* 284x BIOS disabled */
+ { 4, { 0x04, 0x90, 0x77, 0x71 }, AHC_274, FALSE }, /* host adapter 274x */
+ { 4, { 0x04, 0x90, 0x77, 0x70 }, AHC_AIC7770, FALSE }, /* mb 7770 */
+ { 4, { 0x04, 0x90, 0x77, 0x56 }, AHC_284, FALSE }, /* 284x BIOS enabled */
+ { 4, { 0x04, 0x90, 0x77, 0x57 }, AHC_284, TRUE } /* 284x BIOS disabled */
};
/*
@@ -4242,13 +5306,13 @@ aic7xxx_probe(int slot, int base, aha_status_type *bios)
{
if (AIC7xxx[i].bios_disabled)
{
- *bios = AIC_DISABLED;
+ *flags |= AHC_USEDEFAULTS;
}
else
{
- *bios = AIC_ENABLED;
+ *flags |= AHC_BIOS_ENABLED;
}
- return (AIC7xxx[i].type);
+ return (AIC7xxx[i].type);
}
printk("aic7xxx: <Adaptec 7770 SCSI Host Adapter> "
@@ -4256,7 +5320,7 @@ aic7xxx_probe(int slot, int base, aha_status_type *bios)
}
}
- return (AIC_NONE);
+ return (AHC_NONE);
}
/*+F*************************************************************************
@@ -4294,11 +5358,11 @@ read_284x_seeprom(struct aic7xxx_host *p, struct seeprom_config *sc)
struct seeprom_cmd seeprom_read = {3, {1, 1, 0}};
#define CLOCK_PULSE(p) \
- while ((inb(p->base + STATUS_2840) & EEPROM_TF) == 0) \
- { \
- ; /* Do nothing */ \
- } \
- (void) inb(p->base + SEECTL_2840);
+ while ((aic_inb(p, STATUS_2840) & EEPROM_TF) == 0) \
+ { \
+ ; /* Do nothing */ \
+ } \
+ (void) aic_inb(p, SEECTL_2840);
/*
* Read the first 32 registers of the seeprom. For the 2840,
@@ -4311,7 +5375,7 @@ read_284x_seeprom(struct aic7xxx_host *p, struct seeprom_config *sc)
/*
* Send chip select for one clock cycle.
*/
- outb(CK_2840 | CS_2840, p->base + SEECTL_2840);
+ aic_outb(p, CK_2840 | CS_2840, SEECTL_2840);
CLOCK_PULSE(p);
/*
@@ -4321,10 +5385,10 @@ read_284x_seeprom(struct aic7xxx_host *p, struct seeprom_config *sc)
for (i = 0; i < seeprom_read.len; i++)
{
temp = CS_2840 | seeprom_read.bits[i];
- outb(temp, p->base + SEECTL_2840);
+ aic_outb(p, temp, SEECTL_2840);
CLOCK_PULSE(p);
temp = temp ^ CK_2840;
- outb(temp, p->base + SEECTL_2840);
+ aic_outb(p, temp, SEECTL_2840);
CLOCK_PULSE(p);
}
/*
@@ -4335,10 +5399,10 @@ read_284x_seeprom(struct aic7xxx_host *p, struct seeprom_config *sc)
temp = k;
temp = (temp >> i) & 1; /* Mask out all but lower bit. */
temp = CS_2840 | temp;
- outb(temp, p->base + SEECTL_2840);
+ aic_outb(p, temp, SEECTL_2840);
CLOCK_PULSE(p);
temp = temp ^ CK_2840;
- outb(temp, p->base + SEECTL_2840);
+ aic_outb(p, temp, SEECTL_2840);
CLOCK_PULSE(p);
}
@@ -4351,11 +5415,11 @@ read_284x_seeprom(struct aic7xxx_host *p, struct seeprom_config *sc)
for (i = 0; i <= 16; i++)
{
temp = CS_2840;
- outb(temp, p->base + SEECTL_2840);
+ aic_outb(p, temp, SEECTL_2840);
CLOCK_PULSE(p);
temp = temp ^ CK_2840;
- seeprom[k] = (seeprom[k] << 1) | (inb(p->base + STATUS_2840) & DI_2840);
- outb(temp, p->base + SEECTL_2840);
+ seeprom[k] = (seeprom[k] << 1) | (aic_inb(p, STATUS_2840) & DI_2840);
+ aic_outb(p, temp, SEECTL_2840);
CLOCK_PULSE(p);
}
/*
@@ -4372,11 +5436,11 @@ read_284x_seeprom(struct aic7xxx_host *p, struct seeprom_config *sc)
/*
* Reset the chip select for the next command cycle.
*/
- outb(0, p->base + SEECTL_2840);
+ aic_outb(p, 0, SEECTL_2840);
CLOCK_PULSE(p);
- outb(CK_2840, p->base + SEECTL_2840);
+ aic_outb(p, CK_2840, SEECTL_2840);
CLOCK_PULSE(p);
- outb(0, p->base + SEECTL_2840);
+ aic_outb(p, 0, SEECTL_2840);
CLOCK_PULSE(p);
}
@@ -4423,16 +5487,16 @@ acquire_seeprom(struct aic7xxx_host *p)
* is needed. Reason: after the 7870 chip reset, there
* should be no contention.
*/
- outb(SEEMS, p->base + SEECTL);
+ aic_outb(p, SEEMS, SEECTL);
wait = 1000; /* 1000 msec = 1 second */
- while ((wait > 0) && ((inb(p->base + SEECTL) & SEERDY) == 0))
+ while ((wait > 0) && ((aic_inb(p, SEECTL) & SEERDY) == 0))
{
wait--;
udelay(1000); /* 1 msec */
}
- if ((inb(p->base + SEECTL) & SEERDY) == 0)
+ if ((aic_inb(p, SEECTL) & SEERDY) == 0)
{
- outb(0, p->base + SEECTL);
+ aic_outb(p, 0, SEECTL);
return (0);
}
return (1);
@@ -4448,7 +5512,7 @@ acquire_seeprom(struct aic7xxx_host *p)
static inline void
release_seeprom(struct aic7xxx_host *p)
{
- outb(0, p->base + SEECTL);
+ aic_outb(p, 0, SEECTL);
}
/*+F*************************************************************************
@@ -4502,8 +5566,8 @@ release_seeprom(struct aic7xxx_host *p)
* this case, has no implied timing.
*-F*************************************************************************/
static int
-read_seeprom(struct aic7xxx_host *p, int offset, unsigned short *scarray,
- unsigned int len, seeprom_chip_type chip)
+read_seeprom(struct aic7xxx_host *p, int offset,
+ unsigned short *scarray, unsigned int len, seeprom_chip_type chip)
{
int i = 0, k;
unsigned char temp;
@@ -4515,9 +5579,9 @@ read_seeprom(struct aic7xxx_host *p, int offset, unsigned short *scarray,
struct seeprom_cmd seeprom_read = {3, {1, 1, 0}};
#define CLOCK_PULSE(p) \
- while ((inb(p->base + SEECTL) & SEERDY) == 0) \
- { \
- ; /* Do nothing */ \
+ while ((aic_inb(p, SEECTL) & SEERDY) == 0) \
+ { \
+ ; /* Do nothing */ \
}
/*
@@ -4540,7 +5604,7 @@ read_seeprom(struct aic7xxx_host *p, int offset, unsigned short *scarray,
/*
* Send chip select for one clock cycle.
*/
- outb(SEEMS | SEECK | SEECS, p->base + SEECTL);
+ aic_outb(p, SEEMS | SEECK | SEECS, SEECTL);
CLOCK_PULSE(p);
/*
@@ -4550,10 +5614,10 @@ read_seeprom(struct aic7xxx_host *p, int offset, unsigned short *scarray,
for (i = 0; i < seeprom_read.len; i++)
{
temp = SEEMS | SEECS | (seeprom_read.bits[i] << 1);
- outb(temp, p->base + SEECTL);
+ aic_outb(p, temp, SEECTL);
CLOCK_PULSE(p);
temp = temp ^ SEECK;
- outb(temp, p->base + SEECTL);
+ aic_outb(p, temp, SEECTL);
CLOCK_PULSE(p);
}
/*
@@ -4564,10 +5628,10 @@ read_seeprom(struct aic7xxx_host *p, int offset, unsigned short *scarray,
temp = k + offset;
temp = (temp >> i) & 1; /* Mask out all but lower bit. */
temp = SEEMS | SEECS | (temp << 1);
- outb(temp, p->base + SEECTL);
+ aic_outb(p, temp, SEECTL);
CLOCK_PULSE(p);
temp = temp ^ SEECK;
- outb(temp, p->base + SEECTL);
+ aic_outb(p, temp, SEECTL);
CLOCK_PULSE(p);
}
@@ -4580,11 +5644,11 @@ read_seeprom(struct aic7xxx_host *p, int offset, unsigned short *scarray,
for (i = 0; i <= 16; i++)
{
temp = SEEMS | SEECS;
- outb(temp, p->base + SEECTL);
+ aic_outb(p, temp, SEECTL);
CLOCK_PULSE(p);
temp = temp ^ SEECK;
- scarray[k] = (scarray[k] << 1) | (inb(p->base + SEECTL) & SEEDI);
- outb(temp, p->base + SEECTL);
+ scarray[k] = (scarray[k] << 1) | (aic_inb(p, SEECTL) & SEEDI);
+ aic_outb(p, temp, SEECTL);
CLOCK_PULSE(p);
}
@@ -4602,11 +5666,11 @@ read_seeprom(struct aic7xxx_host *p, int offset, unsigned short *scarray,
/*
* Reset the chip select for the next command cycle.
*/
- outb(SEEMS, p->base + SEECTL);
+ aic_outb(p, SEEMS, SEECTL);
CLOCK_PULSE(p);
- outb(SEEMS | SEECK, p->base + SEECTL);
+ aic_outb(p, SEEMS | SEECK, SEECTL);
CLOCK_PULSE(p);
- outb(SEEMS, p->base + SEECTL);
+ aic_outb(p, SEEMS, SEECTL);
CLOCK_PULSE(p);
}
@@ -4629,7 +5693,6 @@ read_seeprom(struct aic7xxx_host *p, int offset, unsigned short *scarray,
}
printk("\n");
#endif
-
if (checksum != scarray[len - 1])
{
return (0);
@@ -4652,13 +5715,13 @@ write_brdctl(struct aic7xxx_host *p, unsigned char value)
unsigned char brdctl;
brdctl = BRDCS | BRDSTB;
- outb(brdctl, p->base + BRDCTL);
+ aic_outb(p, brdctl, BRDCTL);
brdctl |= value;
- outb(brdctl, p->base + BRDCTL);
+ aic_outb(p, brdctl, BRDCTL);
brdctl &= ~BRDSTB;
- outb(brdctl, p->base + BRDCTL);
+ aic_outb(p, brdctl, BRDCTL);
brdctl &= ~BRDCS;
- outb(brdctl, p->base + BRDCTL);
+ aic_outb(p, brdctl, BRDCTL);
}
/*+F*************************************************************************
@@ -4671,8 +5734,77 @@ write_brdctl(struct aic7xxx_host *p, unsigned char value)
static inline unsigned char
read_brdctl(struct aic7xxx_host *p)
{
- outb(BRDRW | BRDCS, p->base + BRDCTL);
- return (inb(p->base + BRDCTL));
+ aic_outb(p, BRDRW | BRDCS, BRDCTL);
+ return (aic_inb(p, BRDCTL));
+}
+
+/*+F*************************************************************************
+ * Function:
+ * aic785x_cable_detect
+ *
+ * Description:
+ * Detect the cables that are present on aic785x class controller chips
+ *-F*************************************************************************/
+static void
+aic785x_cable_detect(struct aic7xxx_host *p, int *int_50,
+ int *ext_present, int *eeprom)
+{
+ unsigned char brdctl;
+
+ aic_outb(p, BRDRW | BRDCS, BRDCTL);
+ aic_outb(p, 0, BRDCTL);
+ brdctl = aic_inb(p, BRDCTL);
+ *int_50 = !(brdctl & BRDDAT5);
+ *ext_present = !(brdctl & BRDDAT6);
+ *eeprom = ( aic_inb(p, SPIOCAP) & EEPROM ) != 0;
+}
+
+/*+F*************************************************************************
+ * Function:
+ * aic787x_cable_detect
+ *
+ * Description:
+ * Detect the cables that are present on aic787x class controller chips
+ *
+ * NOTE: This functions assumes the SEEPROM will have already been aquired
+ * prior to invocation of this function.
+ *-F*************************************************************************/
+static void
+aic787x_cable_detect(struct aic7xxx_host *p, int *int_50, int *int_68,
+ int *ext_present, int *eeprom)
+{
+ unsigned char brdctl;
+
+ /*
+ * First read the status of our cables. Set the rom bank to
+ * 0 since the bank setting serves as a multiplexor for the
+ * cable detection logic. BRDDAT5 controls the bank switch.
+ */
+ write_brdctl(p, 0);
+
+ /*
+ * Now we read the state of the two internal connectors. BRDDAT6
+ * is internal 50, BRDDAT7 is internal 68. For each, the cable is
+ * present if the bit is 0
+ */
+ brdctl = read_brdctl(p);
+ *int_50 = !(brdctl & BRDDAT6);
+ *int_68 = !(brdctl & BRDDAT7);
+
+ /*
+ * Set the bank bit in brdctl and then read the external cable state
+ * and the EEPROM status
+ */
+ write_brdctl(p, BRDDAT5);
+ brdctl = read_brdctl(p);
+
+ *ext_present = !(brdctl & BRDDAT6);
+ *eeprom = (brdctl & BRDDAT7);
+
+ /*
+ * We're done, the calling function will release the SEEPROM for us
+ */
+
}
/*+F*************************************************************************
@@ -4687,82 +5819,72 @@ static void
configure_termination(struct aic7xxx_host *p, unsigned char *sxfrctl1,
unsigned short adapter_control, unsigned char max_targ)
{
- unsigned char brdctl_int, brdctl_ext;
int internal50_present;
int internal68_present = 0;
int external_present = 0;
int eprom_present;
int high_on;
int low_on;
- int old_verbose;
if (acquire_seeprom(p))
{
if (adapter_control & CFAUTOTERM)
{
- old_verbose = aic7xxx_verbose;
- printk(KERN_INFO "aic7xxx: Warning - detected auto-termination. Please "
- "verify driver\n");
- printk(KERN_INFO " detected settings and use manual termination "
- "if necessary.\n");
-
+ printk(KERN_INFO "aic7xxx: Warning - detected auto-termination on "
+ "controller:\n");
+ printk(KERN_INFO "aic7xxx: <%s> at ", board_names[p->board_name_index]);
+ switch(p->type & 0x1ff1)
+ {
+ case AHC_AIC7770:
+ case AHC_274:
+ printk("EISA slot %d\n", p->pci_device_fn);
+ break;
+ case AHC_284:
+ printk("VLB slot %d\n", p->pci_device_fn);
+ break;
+ default:
+ printk("PCI %d/%d\n", PCI_SLOT(p->pci_device_fn),
+ PCI_FUNC(p->pci_device_fn));
+ break;
+ }
+ printk(KERN_INFO "aic7xxx: Please verify driver detected settings are "
+ "correct.\n");
+ printk(KERN_INFO "aic7xxx: If not, then please properly set the device "
+ "termination\n");
+ printk(KERN_INFO "aic7xxx: in the Adaptec SCSI BIOS by hitting CTRL-A "
+ "when prompted\n");
+ printk(KERN_INFO "aic7xxx: during machine bootup.\n");
/* Configure auto termination. */
- outb(SEECS | SEEMS, p->base + SEECTL);
-
- /*
- * First read the status of our cables. Set the rom bank to
- * 0 since the bank setting serves as a multiplexor for the
- * cable detection logic. BRDDAT5 controls the bank switch.
- */
- write_brdctl(p, 0);
+ aic_outb(p, SEECS | SEEMS, SEECTL);
- /*
- * Now read the state of the internal connectors. The
- * bits BRDDAT6 and BRDDAT7 are 0 when cables are present
- * set when cables are not present (BRDDAT6 is INT50 and
- * BRDDAT7 is INT68).
- */
- brdctl_int = read_brdctl(p);
- internal50_present = (brdctl_int & BRDDAT6) ? 0 : 1;
+ if ( (p->type & AHC_AIC7860) == AHC_AIC7860 )
+ {
+ aic785x_cable_detect(p, &internal50_present, &external_present,
+ &eprom_present);
+ }
+ else
+ {
+ aic787x_cable_detect(p, &internal50_present, &internal68_present,
+ &external_present, &eprom_present);
+ }
if (max_targ > 8)
{
- internal68_present = (brdctl_int & BRDDAT7) ? 0 : 1;
+ printk(KERN_INFO "aic7xxx: Cables present (Int-50 %s, Int-68 %s, "
+ "Ext-68 %s)\n",
+ internal50_present ? "YES" : "NO",
+ internal68_present ? "YES" : "NO",
+ external_present ? "YES" : "NO");
}
-
- /*
- * Set the rom bank to 1 and determine
- * the other signals.
- */
- write_brdctl(p, BRDDAT5);
-
- /*
- * Now read the state of the external connectors. BRDDAT6 is
- * 0 when an external cable is present, and BRDDAT7 (EPROMPS) is
- * set when the eprom is present.
- */
- brdctl_ext = read_brdctl(p);
- external_present = (brdctl_ext & BRDDAT6) ? 0 : 1;
- eprom_present = brdctl_ext & BRDDAT7;
- if (aic7xxx_verbose)
+ else
{
- if (max_targ > 8)
- {
- printk(KERN_INFO "aic7xxx: Cables present (Int-50 %s, Int-68 %s, "
- "Ext-68 %s)\n",
- internal50_present ? "YES" : "NO",
- internal68_present ? "YES" : "NO",
- external_present ? "YES" : "NO");
- }
- else
- {
- printk(KERN_INFO "aic7xxx: Cables present (Int-50 %s, Ext-50 %s)\n",
- internal50_present ? "YES" : "NO",
- external_present ? "YES" : "NO");
- }
- printk(KERN_INFO "aic7xxx: eprom %s present, brdctl_int=0x%x, "
- "brdctl_ext=0x%x\n",
- eprom_present ? "is" : "not", brdctl_int, brdctl_ext);
+ printk(KERN_INFO "aic7xxx: Cables present (Int-50 %s, Ext-50 %s)\n",
+ internal50_present ? "YES" : "NO",
+ external_present ? "YES" : "NO");
+ internal68_present = 0;
}
+ if (aic7xxx_verbose & VERBOSE_PROBE2)
+ printk(KERN_INFO "aic7xxx: EEPROM %s present.\n",
+ eprom_present ? "is" : "is not");
/*
* Now set the termination based on what we found. BRDDAT6
@@ -4776,16 +5898,18 @@ configure_termination(struct aic7xxx_host *p, unsigned char *sxfrctl1,
high_on = TRUE;
}
- if ((internal50_present + internal68_present + external_present) <= 1)
+ if ( ( (internal50_present ? 1 : 0) +
+ (internal68_present ? 1 : 0) +
+ (external_present ? 1 : 0) ) <= 1)
{
low_on = TRUE;
}
if (internal50_present && internal68_present && external_present)
{
- printk(KERN_WARNING "aic7xxx: Illegal cable configuration!!\n"
- " Only two connectors on the adapter may be "
- "used at a time!\n");
+ printk(KERN_INFO "aic7xxx: Illegal cable configuration!! Only two\n");
+ printk(KERN_INFO "aic7xxx: connectors on the SCSI controller may be "
+ "in use at a time!\n");
}
if (high_on == TRUE)
@@ -4796,28 +5920,23 @@ configure_termination(struct aic7xxx_host *p, unsigned char *sxfrctl1,
if (low_on == TRUE)
*sxfrctl1 |= STPWEN;
- if (aic7xxx_verbose)
+ if (max_targ > 8)
{
- if (max_targ > 8)
- {
- printk(KERN_INFO "aic7xxx: Termination (Low %s, High %s)\n",
- low_on ? "ON" : "OFF",
- high_on ? "ON" : "OFF");
- }
- else
- {
- printk(KERN_INFO "aic7xxx: Termination %s\n", low_on ? "ON" : "OFF");
- }
+ printk(KERN_INFO "aic7xxx: Termination (Low %s, High %s)\n",
+ low_on ? "ON" : "OFF", high_on ? "ON" : "OFF");
+ }
+ else
+ {
+ printk(KERN_INFO "aic7xxx: Termination %s\n",
+ low_on ? "Enabled" : "Disabled");
}
- aic7xxx_verbose = old_verbose;
}
else
{
if (adapter_control & CFSTERM)
- {
*sxfrctl1 |= STPWEN;
- }
- outb(SEEMS | SEECS, p->base + SEECTL);
+
+ aic_outb(p, SEEMS | SEECS, SEECTL);
/*
* Configure high byte termination.
*/
@@ -4829,7 +5948,7 @@ configure_termination(struct aic7xxx_host *p, unsigned char *sxfrctl1,
{
write_brdctl(p, 0);
}
- if (aic7xxx_verbose)
+ if (aic7xxx_verbose & VERBOSE_PROBE2)
{
printk(KERN_INFO "aic7xxx: Termination (Low %s, High %s)\n",
(adapter_control & CFSTERM) ? "ON" : "OFF",
@@ -4852,7 +5971,6 @@ static void
detect_maxscb(struct aic7xxx_host *p)
{
int i;
- unsigned char max_scbid = 255;
/*
* It's possible that we've already done this for multichannel
@@ -4864,90 +5982,35 @@ detect_maxscb(struct aic7xxx_host *p)
* We haven't initialized the SCB settings yet. Walk the SCBs to
* determince how many there are.
*/
- outb(0, p->base + FREE_SCBH);
+ aic_outb(p, 0, FREE_SCBH);
for (i = 0; i < AIC7XXX_MAXSCB; i++)
{
- outb(i, p->base + SCBPTR);
- outb(i, p->base + SCB_CONTROL);
- if (inb(p->base + SCB_CONTROL) != i)
+ aic_outb(p, i, SCBPTR);
+ aic_outb(p, i, SCB_CONTROL);
+ if (aic_inb(p, SCB_CONTROL) != i)
break;
- outb(0, p->base + SCBPTR);
- if (inb(p->base + SCB_CONTROL) != 0)
+ aic_outb(p, 0, SCBPTR);
+ if (aic_inb(p, SCB_CONTROL) != 0)
break;
- outb(i, p->base + SCBPTR);
- outb(0, p->base + SCB_CONTROL); /* Clear the control byte. */
- outb(i + 1, p->base + SCB_NEXT); /* Set the next pointer. */
- outb(SCB_LIST_NULL, p->base + SCB_TAG); /* Make the tag invalid. */
-
- /* Make the non-tagged targets not busy. */
- outb(SCB_LIST_NULL, p->base + SCB_BUSYTARGETS);
- outb(SCB_LIST_NULL, p->base + SCB_BUSYTARGETS + 1);
- outb(SCB_LIST_NULL, p->base + SCB_BUSYTARGETS + 2);
- outb(SCB_LIST_NULL, p->base + SCB_BUSYTARGETS + 3);
+ aic_outb(p, i, SCBPTR);
+ aic_outb(p, 0, SCB_CONTROL); /* Clear the control byte. */
+ aic_outb(p, i + 1, SCB_NEXT); /* Set the next pointer. */
+ aic_outb(p, SCB_LIST_NULL, SCB_TAG); /* Make the tag invalid. */
}
/* Make sure the last SCB terminates the free list. */
- outb(i - 1, p->base + SCBPTR);
- outb(SCB_LIST_NULL, p->base + SCB_NEXT);
+ aic_outb(p, i - 1, SCBPTR);
+ aic_outb(p, SCB_LIST_NULL, SCB_NEXT);
/* Ensure we clear the first (0) SCBs control byte. */
- outb(0, p->base + SCBPTR);
- outb(0, p->base + SCB_CONTROL);
+ aic_outb(p, 0, SCBPTR);
+ aic_outb(p, 0, SCB_CONTROL);
p->scb_data->maxhscbs = i;
}
- if ((p->flags & PAGE_ENABLED) && (p->scb_data->maxhscbs < AIC7XXX_MAXSCB))
- {
- /* Determine the number of valid bits in the FIFOs. */
- outb(max_scbid, p->base + QINFIFO);
- max_scbid = inb(p->base + QINFIFO);
- p->scb_data->maxscbs = MIN(AIC7XXX_MAXSCB, max_scbid + 1);
- }
- else
- {
- p->scb_data->maxscbs = p->scb_data->maxhscbs;
- }
- if (p->scb_data->maxscbs == p->scb_data->maxhscbs)
- {
- /*
- * Disable paging if the QINFIFO doesn't allow more SCBs than
- * we have in hardware.
- */
- p->flags &= ~PAGE_ENABLED;
- }
-
- /*
- * Set the Queue Full Count. Some cards have more queue space than
- * SCBs.
- */
- switch (p->chip_class)
- {
- case AIC_777x:
- p->qfullcount = 4;
- p->qcntmask = 0x07;
- break;
- case AIC_785x:
- case AIC_786x:
- p->qfullcount = 8;
- p->qcntmask = 0x0f;
- break;
- case AIC_787x:
- case AIC_788x:
- if (p->scb_data->maxhscbs == AIC7XXX_MAXSCB)
- {
- p->qfullcount = AIC7XXX_MAXSCB;
- p->qcntmask = 0xFF;
- }
- else
- {
- p->qfullcount = 16;
- p->qcntmask = 0x1F;
- }
- break;
- }
}
/*+F*************************************************************************
@@ -4958,15 +6021,14 @@ detect_maxscb(struct aic7xxx_host *p)
* Register a Adaptec aic7xxx chip SCSI controller with the kernel.
*-F*************************************************************************/
static int
-aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p)
+aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p,
+ int reset_delay)
{
- int i;
- unsigned char sblkctl, flags = 0;
+ int i, result;
int max_targets;
int found = 1;
- char channel_ids[] = {'A', 'B', 'C'};
unsigned char target_settings;
- unsigned char scsi_conf, sxfrctl1;
+ unsigned char term, scsi_conf, sxfrctl1;
unsigned short ultraenable = 0;
struct Scsi_Host *host;
@@ -4975,78 +6037,12 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p)
*/
request_region(p->base, MAXREG - MINREG, "aic7xxx");
- /*
- * Read the bus type from the SBLKCTL register. Set the FLAGS
- * register in the sequencer for twin and wide bus cards.
- */
- sblkctl = inb(p->base + SBLKCTL);
- if (p->flags & PAGE_ENABLED)
- flags = PAGESCBS;
-
- switch (sblkctl & SELBUS_MASK)
- {
- case SELNARROW: /* narrow/normal bus */
- p->scsi_id = inb(p->base + SCSICONF) & 0x07;
- p->bus_type = AIC_SINGLE;
- p->flags &= ~FLAGS_CHANNEL_B_PRIMARY;
- if (p->flags & MULTI_CHANNEL)
- {
- printk(KERN_INFO "aic7xxx: Channel %c, SCSI ID %d, ",
- channel_ids[p->chan_num], p->scsi_id);
- }
- else
- {
- printk (KERN_INFO "aic7xxx: Single Channel, SCSI ID %d, ",
- p->scsi_id);
- }
- outb(flags | SINGLE_BUS, p->base + SEQ_FLAGS);
- break;
-
- case SELWIDE: /* Wide bus */
- p->scsi_id = inb(p->base + SCSICONF + 1) & HWSCSIID;
- p->bus_type = AIC_WIDE;
- p->flags &= ~FLAGS_CHANNEL_B_PRIMARY;
- if (p->flags & MULTI_CHANNEL)
- {
- printk(KERN_INFO "aic7xxx: Wide Channel %c, SCSI ID %d, ",
- channel_ids[p->chan_num], p->scsi_id);
- }
- else
- {
- printk (KERN_INFO "aic7xxx: Wide Channel, SCSI ID %d, ",
- p->scsi_id);
- }
- outb(flags | WIDE_BUS, p->base + SEQ_FLAGS);
- break;
-
- case SELBUSB: /* Twin bus */
- p->scsi_id = inb(p->base + SCSICONF) & HSCSIID;
- p->scsi_id_b = inb(p->base + SCSICONF + 1) & HSCSIID;
- p->bus_type = AIC_TWIN;
- printk(KERN_INFO "aic7xxx: Twin Channel, A SCSI ID %d, B SCSI ID %d, ",
- p->scsi_id, p->scsi_id_b);
- outb(flags | TWIN_BUS, p->base + SEQ_FLAGS);
- break;
-
- default:
- printk(KERN_WARNING "aic7xxx: Unsupported type 0x%x, please "
- "mail deang@teleport.com\n", inb(p->base + SBLKCTL));
- outb(0, p->base + SEQ_FLAGS);
- return (0);
- }
-
- /*
- * Detect SCB parameters and initialize the SCB array.
- */
- detect_maxscb(p);
- printk("%d/%d SCBs, QFull %d, QMask 0x%x\n",
- p->scb_data->maxhscbs, p->scb_data->maxscbs,
- p->qfullcount, p->qcntmask);
host = p->host;
- host->can_queue = p->scb_data->maxscbs;
- host->cmd_per_lun = 2;
+ p->scb_data->maxscbs = AIC7XXX_MAXSCB;
+ host->can_queue = AIC7XXX_MAXSCB;
+ host->cmd_per_lun = 3;
host->sg_tablesize = AIC7XXX_MAX_SG;
host->select_queue_depths = aic7xxx_select_queue_depth;
host->this_id = p->scsi_id;
@@ -5054,16 +6050,17 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p)
host->n_io_port = 0xFF;
host->base = (unsigned char *) p->mbase;
host->irq = p->irq;
- if (p->bus_type == AIC_WIDE)
+ if (p->type & AHC_WIDE)
{
host->max_id = 16;
}
- if (p->bus_type == AIC_TWIN)
+ if (p->type & AHC_TWIN)
{
host->max_channel = 1;
}
p->host = host;
+ p->last_reset = 0;
p->host_no = host->host_no;
p->isr_count = 0;
p->next = NULL;
@@ -5072,126 +6069,212 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p)
scbq_init(&p->scb_data->free_scbs);
scbq_init(&p->waiting_scbs);
- for (i = 0; i < NUMBER(p->device_status); i++)
+ for (i = 0; i < NUMBER(p->untagged_scbs); i++)
+ {
+ p->untagged_scbs[i] = SCB_LIST_NULL;
+ p->qinfifo[i] = SCB_LIST_NULL;
+ p->qoutfifo[i] = SCB_LIST_NULL;
+ }
+ /*
+ * We currently have no commands of any type
+ */
+ p->qinfifonext = 0;
+ p->qoutfifonext = 0;
+
+ for (i = 0; i < MAX_TARGETS; i++)
+ {
+ p->dev_commands_sent[i] = 0;
+ p->dev_flags[i] = DEVICE_PRINT_WDTR | DEVICE_PRINT_SDTR;
+ p->dev_active_cmds[i] = 0;
+ p->dev_last_reset[i] = 0;
+ p->dev_last_queue_full[i] = 0;
+ p->dev_last_queue_full_count[i] = 0;
+ p->dev_max_queue_depth[i] = 1;
+ p->dev_temp_queue_depth[i] = 1;
+ p->dev_mid_level_queue_depth[i] = 3;
+ scbq_init(&p->delayed_scbs[i]);
+ init_timer(&p->dev_timer[i]);
+ p->dev_timer[i].expires = 0;
+ p->dev_timer[i].data = (unsigned long)p;
+ p->dev_timer[i].function = (void *)aic7xxx_timer;
+ p->syncinfo[i].period = 0;
+ p->syncinfo[i].offset = 0;
+ }
+
+ printk(KERN_INFO "(scsi%d) <%s> found at ", p->host_no,
+ board_names[p->board_name_index]);
+ switch(p->type & 0x1ff1)
+ {
+ case AHC_AIC7770:
+ case AHC_274:
+ printk("EISA slot %d\n", p->pci_device_fn);
+ break;
+ case AHC_284:
+ printk("VLB slot %d\n", p->pci_device_fn);
+ break;
+ default:
+ printk("PCI %d/%d\n", PCI_SLOT(p->pci_device_fn),
+ PCI_FUNC(p->pci_device_fn));
+ break;
+ }
+ if (p->type & AHC_TWIN)
{
- p->device_status[i].commands_sent = 0;
- p->device_status[i].flags = 0;
- p->device_status[i].active_cmds = 0;
- p->device_status[i].last_reset = 0;
+ printk(KERN_INFO "(scsi%d) Twin Channel, A SCSI ID %d, B SCSI ID %d, ",
+ p->host_no, p->scsi_id, p->scsi_id_b);
}
- if (aic7xxx_boards[p->irq] == NULL)
+ else
{
- int result;
- int irq_flags = 0;
+ char *channel;
-#ifdef AIC7XXX_OLD_ISR_TYPE
- irg_flags = SA_INTERRUPT;
-#endif
- /*
- * Warning! This must be done before requesting the irq. It is
- * possible for some boards to raise an interrupt as soon as
- * they are enabled. So when we request the irq from the Linux
- * kernel, an interrupt is triggered immediately. Therefore, we
- * must ensure the board data is correctly set before the request.
- */
- aic7xxx_boards[p->irq] = host;
+ channel = "";
- /*
- * Register IRQ with the kernel. Only allow sharing IRQs with
- * PCI devices.
- */
- if (p->chip_class == AIC_777x)
+ if ((p->type & AHC_39x) != 0)
+ {
+ channel = " A";
+
+ if ( (p->flags & (AHC_CHNLB|AHC_CHNLC)) != 0 )
+ {
+ channel = (p->flags & AHC_CHNLB) ? " B" : " C";
+ }
+ }
+ if (p->type & AHC_WIDE)
{
- result = (request_irq(p->irq, aic7xxx_isr, irq_flags, "aic7xxx", NULL));
+ printk(KERN_INFO "(scsi%d) Wide ", p->host_no);
}
else
{
- result = (request_irq(p->irq, aic7xxx_isr, irq_flags | SA_SHIRQ,
- "aic7xxx", NULL));
+ printk(KERN_INFO "(scsi%d) Narrow ", p->host_no);
}
+ printk("Channel%s, SCSI ID=%d, ", channel, p->scsi_id);
+ }
+ aic_outb(p, 0, SEQ_FLAGS);
+
+ /*
+ * Detect SCB parameters and initialize the SCB array.
+ */
+ detect_maxscb(p);
+ printk("%d/%d SCBs\n", p->scb_data->maxhscbs, p->scb_data->maxscbs);
+ printk(KERN_INFO "(scsi%d) BIOS %sabled, IO Port 0x%lx, IRQ %d\n",
+ p->host_no, (p->flags & AHC_BIOS_ENABLED) ? "en" : "dis",
+ p->base, p->irq);
+ printk(KERN_INFO "(scsi%d) IO Memory at 0x%lx, MMAP Memory at 0x%lx\n",
+ p->host_no, p->mbase, (unsigned long)p->maddr);
+
+
+
+ /*
+ * Register IRQ with the kernel. Only allow sharing IRQs with
+ * PCI devices.
+ */
+ if ((p->type & AHC_AIC7770) == AHC_AIC7770)
+ {
+ result = (request_irq(p->irq, do_aic7xxx_isr, 0, "aic7xxx", p));
+ }
+ else
+ {
+ result = (request_irq(p->irq, do_aic7xxx_isr, SA_SHIRQ,
+ "aic7xxx", p));
if (result < 0)
{
- printk(KERN_WARNING "aic7xxx: Couldn't register IRQ %d, ignoring.\n",
- p->irq);
- aic7xxx_boards[p->irq] = NULL;
- return (0);
+ result = (request_irq(p->irq, do_aic7xxx_isr, SA_INTERRUPT | SA_SHIRQ,
+ "aic7xxx", p));
}
}
- else
+ if (result < 0)
{
- /*
- * We have found a host adapter sharing an IRQ of a previously
- * registered host adapter. Add this host adapter's Scsi_Host
- * to the beginning of the linked list of hosts at the same IRQ.
- */
- p->next = aic7xxx_boards[p->irq];
- aic7xxx_boards[p->irq] = host;
+ printk(KERN_WARNING "(scsi%d) Couldn't register IRQ %d, ignoring.\n",
+ p->host_no, p->irq);
+ return (0);
}
/*
* Set the SCSI Id, SXFRCTL0, SXFRCTL1, and SIMODE1, for both channels
*/
- if (p->bus_type == AIC_TWIN)
+ if (p->type & AHC_TWIN)
{
/*
* The controller is gated to channel B after a chip reset; set
* bus B values first.
*/
- outb(p->scsi_id_b, p->base + SCSIID);
- scsi_conf = inb(p->base + SCSICONF + 1);
- sxfrctl1 = inb(p->base + SXFRCTL1);
- outb((scsi_conf & (ENSPCHK | STIMESEL)) | (sxfrctl1 & STPWEN) |
- ENSTIMER | ACTNEGEN, p->base + SXFRCTL1);
- outb(ENSELTIMO | ENSCSIRST | ENSCSIPERR, p->base + SIMODE1);
- if (p->flags & ULTRA_ENABLED)
+ term = ((p->flags & AHC_TERM_ENB_B) != 0) ? STPWEN : 0;
+ aic_outb(p, p->scsi_id_b, SCSIID);
+ scsi_conf = aic_inb(p, SCSICONF + 1);
+ sxfrctl1 = aic_inb(p, SXFRCTL1);
+ aic_outb(p, (scsi_conf & (ENSPCHK | STIMESEL)) | term |
+ ENSTIMER | ACTNEGEN, SXFRCTL1);
+ aic_outb(p, ENSELTIMO | ENSCSIRST | ENSCSIPERR, SIMODE1);
+ if (p->type & AHC_ULTRA)
{
- outb(DFON | SPIOEN | FAST20, p->base + SXFRCTL0);
+ aic_outb(p, DFON | SPIOEN | FAST20, SXFRCTL0);
}
else
{
- outb(DFON | SPIOEN, p->base + SXFRCTL0);
+ aic_outb(p, DFON | SPIOEN, SXFRCTL0);
+ }
+ if ( (p->type & AHC_AIC7770) == AHC_AIC7770 )
+ {
+ scsi_conf &= ~0x07;
+ scsi_conf |= p->scsi_id_b;
+ aic_outb(p, scsi_conf | (term) ? TERM_ENB : 0, SCSICONF + 1);
}
-
if ((scsi_conf & RESET_SCSI) && (aic7xxx_no_reset == 0))
{
/* Reset SCSI bus B. */
- if (aic7xxx_verbose)
- printk(KERN_INFO "aic7xxx: Resetting channel B\n");
+ if (aic7xxx_verbose & VERBOSE_PROBE)
+ printk(KERN_INFO "(scsi%d) Resetting channel B\n", p->host_no);
aic7xxx_reset_current_bus(p);
}
/* Select channel A */
- outb(SELNARROW, p->base + SBLKCTL);
+ aic_outb(p, SELNARROW, SBLKCTL);
}
- outb(p->scsi_id, p->base + SCSIID);
- scsi_conf = inb(p->base + SCSICONF);
- sxfrctl1 = inb(p->base + SXFRCTL1);
- outb((scsi_conf & (ENSPCHK | STIMESEL)) | (sxfrctl1 & STPWEN) |
- ENSTIMER | ACTNEGEN, p->base + SXFRCTL1);
- outb(ENSELTIMO | ENSCSIRST | ENSCSIPERR, p->base + SIMODE1);
- if (p->flags & ULTRA_ENABLED)
+ term = ((p->flags & AHC_TERM_ENB_A) != 0) ? STPWEN : 0;
+ aic_outb(p, p->scsi_id, SCSIID);
+ scsi_conf = aic_inb(p, SCSICONF);
+ sxfrctl1 = aic_inb(p, SXFRCTL1);
+ aic_outb(p, (scsi_conf & (ENSPCHK | STIMESEL)) | term |
+ ENSTIMER | ACTNEGEN, SXFRCTL1);
+ aic_outb(p, ENSELTIMO | ENSCSIRST | ENSCSIPERR, SIMODE1);
+ if (p->type & AHC_ULTRA)
{
- outb(DFON | SPIOEN | FAST20, p->base + SXFRCTL0);
+ aic_outb(p, DFON | SPIOEN | FAST20, SXFRCTL0);
}
else
{
- outb(DFON | SPIOEN, p->base + SXFRCTL0);
+ aic_outb(p, DFON | SPIOEN, SXFRCTL0);
+ }
+ if ( (p->type & AHC_AIC7770) == AHC_AIC7770 )
+ {
+ scsi_conf &= ~0x07;
+ scsi_conf |= p->scsi_id;
+ aic_outb(p, scsi_conf | (term) ? TERM_ENB : 0, SCSICONF);
}
+
if ((scsi_conf & RESET_SCSI) && (aic7xxx_no_reset == 0))
{
/* Reset SCSI bus A. */
- if (aic7xxx_verbose)
- printk(KERN_INFO "aic7xxx: Resetting channel A\n");
+ if (aic7xxx_verbose & VERBOSE_PROBE)
+ { /* In case we are a 3940, 3985, or 7895, print the right channel */
+ char *channel = "";
+ if (p->flags & AHC_MULTI_CHANNEL)
+ {
+ channel = " A";
+ if (p->flags & (AHC_CHNLB|AHC_CHNLC))
+ channel = (p->flags & AHC_CHNLB) ? " B" : " C";
+ }
+ printk(KERN_INFO "(scsi%d) Resetting channel%s\n", p->host_no, channel);
+ }
aic7xxx_reset_current_bus(p);
/*
* Delay for the reset delay.
*/
- aic7xxx_delay(AIC7XXX_RESET_DELAY);
+ if (!reset_delay)
+ aic7xxx_delay(AIC7XXX_RESET_DELAY);
}
/*
@@ -5206,7 +6289,10 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p)
p->sdtr_pending = 0x0;
p->needwdtr_copy = 0x0;
p->wdtr_pending = 0x0;
- if (p->bus_type == AIC_SINGLE)
+ p->tagenable = 0x0;
+ p->ultraenb = 0x0;
+ p->discenable = 0xffff;
+ if ((p->type & (AHC_TWIN|AHC_WIDE)) == 0)
{
max_targets = 8;
}
@@ -5218,31 +6304,36 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p)
/*
* Grab the disconnection disable table and invert it for our needs
*/
- if (p->flags & USE_DEFAULTS)
+ if (p->flags & AHC_USEDEFAULTS)
{
- printk(KERN_INFO "aic7xxx: Host adapter BIOS disabled. Using default SCSI "
- "device parameters.\n");
- p->discenable = 0xFFFF;
+ printk(KERN_INFO "(scsi%d) Host adapter BIOS disabled. Using default SCSI "
+ "device parameters.\n", p->host_no);
+ if (p->type & AHC_ULTRA)
+ p->ultraenb = 0xffff;
+ p->flags |= AHC_EXTEND_TRANS_A | AHC_EXTEND_TRANS_B;
}
else
{
- p->discenable = ~((inb(p->base + DISC_DSB + 1) << 8) |
- inb(p->base + DISC_DSB));
+ p->discenable = ~((aic_inb(p, DISC_DSB + 1) << 8) |
+ aic_inb(p, DISC_DSB));
+ if (p->type & AHC_ULTRA)
+ p->ultraenb = (aic_inb(p, ULTRA_ENB + 1) << 8) |
+ aic_inb(p, ULTRA_ENB);
}
for (i = 0; i < max_targets; i++)
{
- if (p->flags & USE_DEFAULTS)
+ if (p->flags & AHC_USEDEFAULTS)
{
target_settings = 0; /* 10 or 20 MHz depending on Ultra enable */
p->needsdtr_copy |= (0x01 << i);
p->needwdtr_copy |= (0x01 << i);
- if ((p->chip_class == AIC_786x) || (p->chip_class == AIC_788x))
+ if (p->type & AHC_ULTRA)
ultraenable |= (0x01 << i);
}
else
{
- target_settings = inb(p->base + TARG_SCRATCH + i);
+ target_settings = aic_inb(p, TARG_SCRATCH + i);
if (target_settings & 0x0F)
{
p->needsdtr_copy |= (0x01 << i);
@@ -5260,24 +6351,33 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p)
*/
target_settings &= 0x7F;
}
- if (p->flags & ULTRA_ENABLED)
+ }
+
+ aic_outb(p, target_settings, TARG_SCRATCH + i);
+ if (p->needsdtr_copy & (0x01 << i))
+ {
+ short sxfr, j;
+
+ sxfr = target_settings & SXFR;
+ if ((p->ultraenb & (1 << i)) != 0)
{
- switch (target_settings & 0x70)
- {
- case 0x00:
- case 0x10:
- case 0x20:
- ultraenable |= (0x01 << i);
- break;
- case 0x40: /* treat 10MHz as 10MHz without Ultra enabled */
- target_settings &= ~(0x70);
- break;
- default:
- break;
- }
+ /* Want an ultra speed in the table */
+ sxfr |= 0x100;
}
+ for (j = 0; j < NUMBER(aic7xxx_syncrates); j++)
+ {
+ if (sxfr == aic7xxx_syncrates[j].rate)
+ break;
+ }
+ p->syncinfo[i].period = aic7xxx_syncrates[j].period;
+ p->syncinfo[i].offset =
+ (p->type & AHC_WIDE) ? MAX_OFFSET_16BIT : MAX_OFFSET_8BIT;
+ }
+ else
+ {
+ p->syncinfo[i].period = 0;
+ p->syncinfo[i].offset = 0;
}
- outb(target_settings, p->base + TARG_SCRATCH + i);
}
/*
@@ -5285,26 +6385,14 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p)
* work on some cards that don't leave these fields cleared
* when BIOS is not installed.
*/
- if (p->bus_type != AIC_WIDE)
+ if ( !(p->type & AHC_WIDE))
{
p->needwdtr_copy = 0;
}
p->needsdtr = p->needsdtr_copy;
p->needwdtr = p->needwdtr_copy;
- p->orderedtag = 0;
- outb(ultraenable & 0xFF, p->base + ULTRA_ENB);
- outb((ultraenable >> 8) & 0xFF, p->base + ULTRA_ENB + 1);
-
- /*
- * Set the number of available hardware SCBs.
- */
- outb(p->scb_data->maxhscbs, p->base + SCBCOUNT);
-
- /*
- * 2s compliment of maximum tag value.
- */
- i = p->scb_data->maxscbs;
- outb(-i & 0xFF, p->base + COMP_SCBCOUNT);
+ aic_outb(p, 0, ULTRA_ENB);
+ aic_outb(p, 0, ULTRA_ENB + 1);
/*
* Allocate enough hardware scbs to handle the maximum number of
@@ -5322,20 +6410,10 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p)
p->scb_data->hscbs = kmalloc(array_size, GFP_ATOMIC);
if (p->scb_data->hscbs == NULL)
{
- printk("aic7xxx: Unable to allocate hardware SCB array; "
- "failing detection.\n");
+ printk("(scsi%d) Unable to allocate hardware SCB array; "
+ "failing detection.\n", p->host_no);
release_region(p->base, MAXREG - MINREG);
- /*
- * Ensure that we only free the IRQ when there is _not_ another
- * aic7xxx adapter sharing this IRQ. The adapters are always
- * added to the beginning of the list, so we can grab the next
- * pointer and place it back in the board array.
- */
- if (p->next == NULL)
- {
- free_irq(p->irq, aic7xxx_isr);
- }
- aic7xxx_boards[p->irq] = p->next;
+ free_irq(p->irq, p);
return(0);
}
/* At least the control byte of each SCB needs to be 0. */
@@ -5343,40 +6421,35 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p)
/* Tell the sequencer where it can find the hardware SCB array. */
hscb_physaddr = VIRT_TO_BUS(p->scb_data->hscbs);
- outb(hscb_physaddr & 0xFF, p->base + HSCB_ADDR);
- outb((hscb_physaddr >> 8) & 0xFF, p->base + HSCB_ADDR + 1);
- outb((hscb_physaddr >> 16) & 0xFF, p->base + HSCB_ADDR + 2);
- outb((hscb_physaddr >> 24) & 0xFF, p->base + HSCB_ADDR + 3);
- }
+ aic_outb(p, hscb_physaddr & 0xFF, HSCB_ADDR);
+ aic_outb(p, (hscb_physaddr >> 8) & 0xFF, HSCB_ADDR + 1);
+ aic_outb(p, (hscb_physaddr >> 16) & 0xFF, HSCB_ADDR + 2);
+ aic_outb(p, (hscb_physaddr >> 24) & 0xFF, HSCB_ADDR + 3);
- /*
- * QCount mask to deal with broken aic7850s that sporadically get
- * garbage in the upper bits of their QCNT registers.
- */
- outb(p->qcntmask, p->base + QCNTMASK);
+ /* Set up the fifo areas at the same time */
+ hscb_physaddr = VIRT_TO_BUS(&p->untagged_scbs[0]);
+ aic_outb(p, hscb_physaddr & 0xFF, SCBID_ADDR);
+ aic_outb(p, (hscb_physaddr >> 8) & 0xFF, SCBID_ADDR + 1);
+ aic_outb(p, (hscb_physaddr >> 16) & 0xFF, SCBID_ADDR + 2);
+ aic_outb(p, (hscb_physaddr >> 24) & 0xFF, SCBID_ADDR + 3);
+
+ /* The Q-FIFOs we just set up are all empty */
+ aic_outb(p, 0, QINPOS);
+ aic_outb(p, 0, KERNEL_QINPOS);
+ aic_outb(p, 0, QOUTPOS);
- /*
- * Set FIFO depth and command out count. These are only used when
- * paging is enabled and should not be touched for AIC-7770 based
- * adapters; FIFODEPTH and CMDOUTCNT overlay SCSICONF and SCSICONF+1
- * which are used to control termination.
- */
- if (p->flags & PAGE_ENABLED)
- {
- outb(p->qfullcount, p->base + FIFODEPTH);
- outb(0, p->base + CMDOUTCNT);
}
/*
* We don't have any waiting selections or disconnected SCBs.
*/
- outb(SCB_LIST_NULL, p->base + WAITING_SCBH);
- outb(SCB_LIST_NULL, p->base + DISCONNECTED_SCBH);
+ aic_outb(p, SCB_LIST_NULL, WAITING_SCBH);
+ aic_outb(p, SCB_LIST_NULL, DISCONNECTED_SCBH);
/*
* Message out buffer starts empty
*/
- outb(0, p->base + MSG_LEN);
+ aic_outb(p, MSG_NOOP, MSG_OUT);
/*
* Load the sequencer program, then re-enable the board -
@@ -5387,12 +6460,18 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p)
*/
aic7xxx_loadseq(p);
- if (p->chip_class == AIC_777x)
+ if ( (p->type & AHC_AIC7770) == AHC_AIC7770 )
{
- outb(ENABLE, p->base + BCTL); /* Enable the boards BUS drivers. */
+ aic_outb(p, ENABLE, BCTL); /* Enable the boards BUS drivers. */
}
/*
+ * Link us into the list of valid hosts
+ */
+ p->next = first_aic7xxx;
+ first_aic7xxx = p;
+
+ /*
* Unpause the sequencer before returning and enable
* interrupts - we shouldn't get any until the first
* command is sent to us by the high-level SCSI code.
@@ -5410,38 +6489,56 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p)
* Perform a chip reset on the aic7xxx SCSI controller. The controller
* is paused upon return.
*-F*************************************************************************/
-static void
+int
aic7xxx_chip_reset(struct aic7xxx_host *p)
{
unsigned char hcntrl;
int wait;
/* Retain the IRQ type across the chip reset. */
- hcntrl = (inb(p->base + HCNTRL) & IRQMS) | INTEN;
+ hcntrl = (aic_inb(p, HCNTRL) & IRQMS) | INTEN;
/*
* For some 274x boards, we must clear the CHIPRST bit and pause
* the sequencer. For some reason, this makes the driver work.
*/
- outb(PAUSE | CHIPRST, p->base + HCNTRL);
+ aic_outb(p, PAUSE | CHIPRST, HCNTRL);
/*
* In the future, we may call this function as a last resort for
* error handling. Let's be nice and not do any unecessary delays.
*/
wait = 1000; /* 1 second (1000 * 1000 usec) */
- while ((wait > 0) && ((inb(p->base + HCNTRL) & CHIPRSTACK) == 0))
+ while ((wait > 0) && ((aic_inb(p, HCNTRL) & CHIPRSTACK) == 0))
{
udelay(1000); /* 1 msec = 1000 usec */
wait = wait - 1;
}
- if ((inb(p->base + HCNTRL) & CHIPRSTACK) == 0)
+ if ((aic_inb(p, HCNTRL) & CHIPRSTACK) == 0)
{
printk(KERN_INFO "aic7xxx: Chip reset not cleared; clearing manually.\n");
}
- outb(hcntrl | PAUSE, p->base + HCNTRL);
+ aic_outb(p, hcntrl | PAUSE, HCNTRL);
+
+ switch( aic_inb(p, SBLKCTL) & 0x0a )
+ {
+ case 0: /* normal narrow card */
+ break;
+ case 2: /* Wide card */
+ p->type |= AHC_WIDE;
+ break;
+ case 8: /* Twin card */
+ p->type |= AHC_TWIN;
+ p->flags |= AHC_MULTI_CHANNEL;
+ break;
+ default: /* hmmm...we don't know what this is */
+ printk(KERN_WARNING "aic7xxx: Unsupported adapter type %d, ignoring.\n",
+ aic_inb(p, SBLKCTL) & 0x0a);
+ return(-1);
+ }
+ return(0);
}
/*+F*************************************************************************
@@ -5453,8 +6550,7 @@ aic7xxx_chip_reset(struct aic7xxx_host *p)
* and a pointer to a aic7xxx_host struct upon success.
*-F*************************************************************************/
static struct aic7xxx_host *
-aic7xxx_alloc(Scsi_Host_Template *sht, unsigned int base, unsigned int mbase,
- aha_chip_type chip_type, int flags, scb_data_type *scb_data)
+aic7xxx_alloc(Scsi_Host_Template *sht, struct aic7xxx_host *temp)
{
struct aic7xxx_host *p = NULL;
struct Scsi_Host *host;
@@ -5471,46 +6567,45 @@ aic7xxx_alloc(Scsi_Host_Template *sht, unsigned int base, unsigned int mbase,
memset(p, 0, sizeof(struct aic7xxx_host));
p->host = host;
- if (scb_data != NULL)
+ p->scb_data = kmalloc(sizeof(scb_data_type), GFP_ATOMIC);
+ if (p->scb_data != NULL)
{
- /*
- * We are sharing SCB data areas; use the SCB data pointer
- * provided.
- */
- p->scb_data = scb_data;
- p->flags |= SHARED_SCBDATA;
+ memset(p->scb_data, 0, sizeof(scb_data_type));
+ scbq_init (&p->scb_data->free_scbs);
}
else
{
/*
- * We are not sharing SCB data; allocate one.
+ * For some reason we don't have enough memory. Free the
+ * allocated memory for the aic7xxx_host struct, and return NULL.
*/
- p->scb_data = kmalloc(sizeof(scb_data_type), GFP_ATOMIC);
- if (p->scb_data != NULL)
- {
- memset(p->scb_data, 0, sizeof(scb_data_type));
- scbq_init (&p->scb_data->free_scbs);
- }
- else
- {
- /*
- * For some reason we don't have enough memory. Free the
- * allocated memory for the aic7xxx_host struct, and return NULL.
- */
- scsi_unregister(host);
- p = NULL;
- }
+ scsi_unregister(host);
+ p = NULL;
}
if (p != NULL)
{
p->host_no = host->host_no;
- p->base = base;
- p->mbase = mbase;
- p->maddr = NULL;
- p->flags = flags;
- p->chip_type = chip_type;
- p->unpause = (inb(p->base + HCNTRL) & IRQMS) | INTEN;
- p->pause = p->unpause | PAUSE;
+ p->base = temp->base;
+ p->mbase = temp->mbase;
+ p->maddr = temp->maddr;
+ p->flags = temp->flags;
+ p->type = temp->type;
+ p->unpause = temp->unpause;
+ p->pause = temp->pause;
+ p->pci_bus = temp->pci_bus;
+ p->pci_device_fn = temp->pci_device_fn;
+ p->bios_address = temp->bios_address;
+ p->irq = temp->irq;
+ p->scsi_id = temp->scsi_id;
+ p->scsi_id_b = temp->scsi_id_b;
+ p->discenable = temp->discenable;
+ p->ultraenb = temp->ultraenb;
+ p->tagenable = 0;
+ p->orderedtag = 0;
+ p->board_name_index = temp->board_name_index;
+ p->adapter_control = temp->adapter_control;
+ p->bios_control = temp->bios_control;
+ DRIVER_LOCK_INIT
}
}
return (p);
@@ -5525,49 +6620,48 @@ aic7xxx_alloc(Scsi_Host_Template *sht, unsigned int base, unsigned int mbase,
* the driver (struct aic7xxx_host *).
*-F*************************************************************************/
static void
-aic7xxx_free (struct aic7xxx_host *p)
+aic7xxx_free(struct aic7xxx_host *p)
{
- int i;
+ int i, jump;
/*
- * We should be careful in freeing the scb_data area. For those
- * adapters sharing external SCB RAM(398x), there will be only one
- * scb_data area allocated. The flag SHARED_SCBDATA indicates if
- * one adapter is sharing anothers SCB RAM.
+ * Free the allocated hardware SCB space.
*/
- if (!(p->flags & SHARED_SCBDATA))
+ if (p->scb_data->hscbs != NULL)
{
- /*
- * Free the allocated hardware SCB space.
- */
- if (p->scb_data->hscbs != NULL)
- {
- kfree(p->scb_data->hscbs);
- }
- /*
- * Free the driver SCBs. These were allocated on an as-need
- * basis.
- */
- for (i = 0; i < p->scb_data->numscbs; i++)
- {
- kfree(p->scb_data->scb_array[i]);
- }
- /*
- * Free the hardware SCBs.
- */
- if (p->scb_data->hscbs != NULL)
- {
- kfree(p->scb_data->hscbs);
- }
-
- /*
- * Free the SCB data area.
- */
- kfree(p->scb_data);
+ kfree(p->scb_data->hscbs);
}
/*
+ * Free the driver SCBs. These were allocated on an as-need
+ * basis. However, we allocated them 30 at a time up until the
+ * very last allocation (if there was one). So, we need to free
+ * every 30th pointer to free the array (this also frees the
+ * SG_array structs as well).
+ *
+ * Note, on 64 bit machines we allocate 29 at a time instead.
+ */
+ jump = (sizeof(int) == sizeof(void *)) ? 30 : 29;
+ for (i = 0; i < p->scb_data->numscbs; i += jump)
+ {
+ kfree(p->scb_data->scb_array[i]);
+ }
+ /*
+ * Free the SCB data area.
+ */
+ kfree(p->scb_data);
+
+ /*
* Free the instance of the device structure.
*/
+
+ /*
+ * XXXXXXXX FIXXXXXMEEEEEE. How do we unmap the I/O range we have mapped
+ * if we are doing MMAPed I/O ?????????? Our biggest concern is the issue
+ * of possibly calling unmap on an area that *might* be used on another
+ * controller as well (aka, the 4096 byte MMAPed area is back to back
+ * with another controller, and the PAGE_SIZE is greater then 4096, allowing
+ * us to remap in a shared page).
+ */
scsi_unregister(p->host);
}
@@ -5588,46 +6682,42 @@ load_seeprom (struct aic7xxx_host *p, unsigned char *sxfrctl1)
unsigned short scarray[128];
struct seeprom_config *sc = (struct seeprom_config *) scarray;
- if (aic7xxx_verbose)
+ if (aic7xxx_verbose & VERBOSE_PROBE2)
{
printk(KERN_INFO "aic7xxx: Loading serial EEPROM...");
}
- switch (p->chip_type)
+ switch (p->type & 0x00001ff1)
{
- case AIC_7770: /* None of these adapters have seeproms. */
- case AIC_7771:
- case AIC_7855:
+ case AHC_AIC7770: /* None of these adapters have seeproms. */
+ case AHC_274:
break;
- case AIC_284x:
+ case AHC_284:
have_seeprom = read_284x_seeprom(p, (struct seeprom_config *) scarray);
break;
- case AIC_7850: /* The 2910B is a 7850 with a seeprom. */
- case AIC_7861:
- case AIC_7870:
- case AIC_7871:
- case AIC_7872:
- case AIC_7874:
- case AIC_7881:
- case AIC_7882:
- case AIC_7884:
- have_seeprom = read_seeprom(p, p->chan_num * (sizeof(*sc)/2),
+ case AHC_AIC7850: /* The 2910B is a 7850 with a seeprom. */
+ case AHC_294AU:
+ case AHC_AIC7870: /* For these controllers we try the three possible */
+ case AHC_AIC7895: /* SEEPROM read types. If none works, then we are */
+ case AHC_294: /* SOL. This should catch any SEEPROM variety */
+ case AHC_394: /* Adaptec or some motherboard manufacturer might */
+ case AHC_294U: /* throw at us, and since we perform a checksum */
+ case AHC_394U: /* during the read, we should get bogus seeprom */
+ case AHC_AIC7860: /* reads. */
+ case AHC_AIC7880:
+ case AHC_398:
+ case AHC_398U:
+ have_seeprom = read_seeprom(p, (p->flags & (AHC_CHNLB|AHC_CHNLC)),
scarray, sizeof(*sc)/2, C46);
- break;
-
- case AIC_7860: /* Motherboard Ultra controllers might have RAID port. */
- case AIC_7880:
- have_seeprom = read_seeprom(p, 0, scarray, sizeof(*sc)/2, C46);
if (!have_seeprom)
- {
- have_seeprom = read_seeprom(p, 0, scarray, sizeof(scarray)/2, C56_66);
- }
- break;
-
- case AIC_7873: /* The 3985 adapters use the 93c56 serial EEPROM. */
- case AIC_7883:
- have_seeprom = read_seeprom(p, p->chan_num * (sizeof(*sc)/2),
+ have_seeprom = read_seeprom(p, (p->flags & (AHC_CHNLB|AHC_CHNLC)),
+ scarray, sizeof(scarray)/2, C46);
+ if (!have_seeprom)
+ have_seeprom = read_seeprom(p, (p->flags & (AHC_CHNLB|AHC_CHNLC)),
+ scarray, sizeof(*sc)/2, C56_66);
+ if (!have_seeprom)
+ have_seeprom = read_seeprom(p, (p->flags & (AHC_CHNLB|AHC_CHNLC)),
scarray, sizeof(scarray)/2, C56_66);
break;
@@ -5637,19 +6727,19 @@ load_seeprom (struct aic7xxx_host *p, unsigned char *sxfrctl1)
if (!have_seeprom)
{
- if (aic7xxx_verbose)
+ if (aic7xxx_verbose & VERBOSE_PROBE2)
{
printk("\naic7xxx: No SEEPROM available; using defaults.\n");
}
- p->flags |= USE_DEFAULTS;
+ p->flags |= AHC_USEDEFAULTS;
+ p->flags &= ~AHC_BIOS_ENABLED;
}
else
{
- if (aic7xxx_verbose)
+ if (aic7xxx_verbose & VERBOSE_PROBE2)
{
printk("done\n");
}
- p->flags |= HAVE_SEEPROM;
/*
* Update the settings in sxfrctl1 to match the termination settings.
@@ -5660,14 +6750,17 @@ load_seeprom (struct aic7xxx_host *p, unsigned char *sxfrctl1)
* First process the settings that are different between the VLB
* and PCI adapter seeproms.
*/
- if (p->chip_class == AIC_777x)
+ if (p->type & AHC_284)
{
/* VLB adapter seeproms */
if (sc->bios_control & CF284XEXTEND)
- p->flags |= EXTENDED_TRANSLATION;
+ p->flags |= AHC_EXTEND_TRANS_A;
if (sc->adapter_control & CF284XSTERM)
+ {
*sxfrctl1 |= STPWEN;
+ p->flags |= AHC_TERM_ENB_A;
+ }
/*
* The 284x SEEPROM doesn't have a max targets field. We
* set it to 16 to make sure we take care of the 284x-wide
@@ -5685,30 +6778,90 @@ load_seeprom (struct aic7xxx_host *p, unsigned char *sxfrctl1)
{
/* PCI adapter seeproms */
if (sc->bios_control & CFEXTEND)
- p->flags |= EXTENDED_TRANSLATION;
+ p->flags |= AHC_EXTEND_TRANS_A;
if (sc->adapter_control & CFSTERM)
+ {
*sxfrctl1 |= STPWEN;
+ p->flags |= AHC_TERM_ENB_A;
+ }
/* Limit to 16 targets just in case. */
max_targets = MIN(sc->max_targets & CFMAXTARG, 16);
}
+ p->discenable = 0;
+
+ for (i = 0; i < max_targets; i++)
+ {
+ if( (p->type & AHC_ULTRA) &&
+ !(sc->adapter_control & CFULTRAEN) &&
+ (sc->device_flags[i] & CFSYNCHISULTRA) )
+ {
+ p->flags |= AHC_NEWEEPROM_FMT;
+ break;
+ }
+ }
+
for (i = 0; i < max_targets; i++)
{
target_settings = (sc->device_flags[i] & CFXFER) << 4;
if (sc->device_flags[i] & CFSYNCH)
+ {
target_settings |= SOFS;
+ }
if (sc->device_flags[i] & CFWIDEB)
+ {
target_settings |= WIDEXFER;
+ }
if (sc->device_flags[i] & CFDISC)
+ {
p->discenable |= (0x01 << i);
- outb(target_settings, p->base + TARG_SCRATCH + i);
+ }
+ if (p->flags & AHC_NEWEEPROM_FMT)
+ {
+ if (sc->device_flags[i] & CFSYNCHISULTRA)
+ {
+ p->ultraenb |= (0x01 << i);
+ }
+ }
+ else if (sc->adapter_control & CFULTRAEN)
+ {
+ p->ultraenb |= (0x01 << i);
+ }
+ if ( ((target_settings & 0x70) == 0x40) &&
+ (p->ultraenb & (0x01 << i)) )
+ {
+ target_settings &= ~0x70;
+ p->ultraenb &= ~(0x01 << i);
+ }
+ aic_outb(p, target_settings, TARG_SCRATCH + i);
}
- outb(~(p->discenable & 0xFF), p->base + DISC_DSB);
- outb(~((p->discenable >> 8) & 0xFF), p->base + DISC_DSB + 1);
+ aic_outb(p, ~(p->discenable & 0xFF), DISC_DSB);
+ aic_outb(p, ~((p->discenable >> 8) & 0xFF), DISC_DSB + 1);
+ aic_outb(p, (p->ultraenb & 0xFF), ULTRA_ENB);
+ aic_outb(p, ((p->ultraenb >> 8) & 0xFF), ULTRA_ENB + 1);
p->scsi_id = sc->brtime_id & CFSCSIID;
+ p->adapter_control = sc->adapter_control;
+ p->bios_control = sc->bios_control;
+
+ if (p->bios_control & CFBIOSEN)
+ {
+ p->flags &= ~AHC_USEDEFAULTS;
+ p->flags |= AHC_BIOS_ENABLED;
+ }
+ else
+ {
+ p->flags &= ~AHC_BIOS_ENABLED;
+ p->flags |= AHC_USEDEFAULTS;
+ }
+
+ if ((p->type & 0x1ff1) == AHC_AIC7895)
+ {
+ if (p->adapter_control & CFBPRIMARY)
+ p->flags |= AHC_CHANNEL_B_PRIMARY;
+ }
scsi_conf = (p->scsi_id & 0x7);
if (sc->adapter_control & CFSPARITY)
@@ -5717,37 +6870,39 @@ load_seeprom (struct aic7xxx_host *p, unsigned char *sxfrctl1)
* The 7850 controllers with a seeprom, do not honor the CFRESETB
* flag in the seeprom. Assume that we want to reset the SCSI bus.
*/
- if ((sc->adapter_control & CFRESETB) || (p->chip_class == AIC_7850))
+ if (sc->adapter_control & CFRESETB)
scsi_conf |= RESET_SCSI;
-
- if ((p->chip_class == AIC_786x) || (p->chip_class == AIC_788x))
- {
- /*
- * We allow the operator to override ultra enable through
- * the boot prompt.
- */
- if (!(sc->adapter_control & CFULTRAEN) && (aic7xxx_enable_ultra == 0))
- {
- /* Treat us as a non-ultra card */
- p->flags &= ~ULTRA_ENABLED;
- }
- }
+ /*
+ * We may be a 2842, if so, preserve the TERM_ENB bit in scsi conf
+ */
+ if ( (p->flags & AHC_TERM_ENB_A) &&
+ ((p->type & AHC_AIC7770) == AHC_AIC7770) )
+ scsi_conf |= TERM_ENB;
+ /*
+ * If this is an Ultra card, is Ultra mode enabled? If not, disable
+ * it in the host struct as well
+ */
+ if ( (p->type & AHC_ULTRA) &&
+ !(sc->adapter_control & CFULTRAEN) &&
+ !(p->flags & AHC_NEWEEPROM_FMT) )
+ p->type &= ~AHC_ULTRA;
/* Set the host ID */
- outb(scsi_conf, p->base + SCSICONF);
+ aic_outb(p, scsi_conf, SCSICONF);
/* In case we are a wide card */
- outb(p->scsi_id, p->base + SCSICONF + 1);
+ aic_outb(p, p->scsi_id, SCSICONF + 1);
- if (p->chip_class != AIC_777x)
+ if ((p->type & AHC_AIC7860) == AHC_AIC7860)
{
+ if ( aic_inb(p, SPIOCAP) & SSPIOCPS )
/*
* Update the settings in sxfrctl1 to match the termination
* settings.
*/
- *sxfrctl1 = 0;
- configure_termination(p, sxfrctl1, sc->adapter_control,
- (unsigned char) sc->max_targets & CFMAXTARG);
+ configure_termination(p, sxfrctl1, sc->adapter_control, max_targets);
}
+ else if (have_seeprom && ((p->type & AHC_AIC7770) != AHC_AIC7770))
+ configure_termination(p, sxfrctl1, sc->adapter_control, max_targets);
}
return (have_seeprom);
}
@@ -5767,41 +6922,40 @@ load_seeprom (struct aic7xxx_host *p, unsigned char *sxfrctl1)
int
aic7xxx_detect(Scsi_Host_Template *template)
{
+ struct aic7xxx_host *temp_p = NULL;
+ struct aic7xxx_host *current_p = NULL;
+ struct aic7xxx_host *list_p = NULL;
int found = 0;
- aha_status_type adapter_bios;
- aha_chip_class_type chip_class;
- aha_chip_type chip_type;
- int slot, base;
- int chan_num = 0;
- unsigned char hcntrl, sxfrctl1, sblkctl, hostconf, irq = 0;
- int i;
- struct aic7xxx_host *p;
+ ahc_flag_type flags = 0;
+ ahc_type type;
+ unsigned char sxfrctl1;
+#if defined(__i386__) || defined(__alpha__)
+ unsigned char hcntrl, hostconf;
+ unsigned int slot, base;
+#endif
+#ifdef MODULE
/*
- * Since we may allow sharing of IRQs, it is imperative
- * that we "null-out" the aic7xxx_boards array. It is
- * not guaranteed to be initialized to 0 (NULL). We use
- * a NULL entry to indicate that no prior hosts have
- * been found/registered for that IRQ.
+ * If we are called as a module, the aic7xxx pointer may not be null
+ * and it would point to our bootup string, just like on the lilo
+ * command line. IF not NULL, then process this config string with
+ * aic7xxx_setup
*/
- for (i = 0; i < NUMBER(aic7xxx_boards); i++)
- {
- aic7xxx_boards[i] = NULL;
- }
+ if(aic7xxx)
+ aic7xxx_setup(aic7xxx, NULL);
+
+#endif
template->proc_dir = &proc_scsi_aic7xxx;
- template->name = aic7xxx_info(NULL);
template->sg_tablesize = AIC7XXX_MAX_SG;
- /*
- * Initialize the spurious count to 0.
- */
- aic7xxx_spurious_count = 0;
+#if defined(__i386__) || defined(__alpha__)
/*
* EISA/VL-bus card signature probe.
*/
- for (slot = MINSLOT; slot <= MAXSLOT; slot++)
+ slot = MINSLOT;
+ while (slot <= MAXSLOT)
{
base = SLOTBASE(slot) + MINREG;
@@ -5811,186 +6965,256 @@ aic7xxx_detect(Scsi_Host_Template *template)
* Some other driver has staked a
* claim to this i/o region already.
*/
- continue;
+ slot++;
+ continue; /* back to the beginning of the for loop */
}
-
- chip_type = aic7xxx_probe(slot, base + HID0, &(adapter_bios));
- if (chip_type != AIC_NONE)
+ flags = 0;
+ type = aic7xxx_probe(slot, base + HID0, &flags);
+ switch (type)
{
-
- switch (chip_type)
- {
- case AIC_7770:
- case AIC_7771:
+ case AHC_AIC7770:
+ if (aic7xxx_verbose & VERBOSE_PROBE2)
printk("aic7xxx: <%s> at EISA %d\n",
- board_names[chip_type], slot);
- break;
- case AIC_284x:
+ board_names[2], slot);
+ break;
+ case AHC_274:
+ if (aic7xxx_verbose & VERBOSE_PROBE2)
+ printk("aic7xxx: <%s> at EISA %d\n",
+ board_names[3], slot);
+ break;
+ case AHC_284:
+ if (aic7xxx_verbose & VERBOSE_PROBE2)
printk("aic7xxx: <%s> at VLB %d\n",
- board_names[chip_type], slot);
- break;
- default:
- break;
- }
-
- /*
- * We found a card, allow 1 spurious interrupt.
- */
- aic7xxx_spurious_count = 1;
+ board_names[4], slot);
+ break;
+ default:
+ slot++;
+ continue; /* back to the beginning of the while loop */
+ }
+ temp_p = kmalloc(sizeof(struct aic7xxx_host), GFP_ATOMIC);
+ if (temp_p == NULL)
+ {
+ printk(KERN_WARNING "aic7xxx: Unable to allocate device space.\n");
+ slot++;
+ continue; /* back to the beginning of the while loop */
+ }
+ /*
+ * Pause the card preserving the IRQ type. Allow the operator
+ * to override the IRQ trigger.
+ */
+ if (aic7xxx_irq_trigger == 1)
+ hcntrl = IRQMS; /* Level */
+ else if (aic7xxx_irq_trigger == 0)
+ hcntrl = 0; /* Edge */
+ else
+ hcntrl = inb(base + HCNTRL) & IRQMS; /* Default */
+ memset(temp_p, 0, sizeof(struct aic7xxx_host));
+ temp_p->unpause = hcntrl | INTEN;
+ temp_p->pause = hcntrl | PAUSE | INTEN;
+ temp_p->base = base;
+ temp_p->type = type;
+ temp_p->flags = flags | AHC_PAGESCBS;
+ temp_p->mbase = 0;
+ temp_p->maddr = 0;
+ temp_p->pci_bus = 0;
+ temp_p->pci_device_fn = slot;
+ aic_outb(temp_p, hcntrl | PAUSE, HCNTRL);
+ while( (aic_inb(temp_p, HCNTRL) & PAUSE) == 0 ) ;
+ if (aic7xxx_chip_reset(temp_p) == -1)
+ temp_p->irq = 0;
+ else
+ temp_p->irq = aic_inb(temp_p, INTDEF) & 0x0F;
+ switch (temp_p->irq)
+ {
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ case 14:
+ case 15:
+ break;
- /*
- * Pause the card preserving the IRQ type. Allow the operator
- * to override the IRQ trigger.
- */
- if (aic7xxx_irq_trigger == 1)
- hcntrl = IRQMS; /* Level */
- else if (aic7xxx_irq_trigger == 0)
- hcntrl = 0; /* Edge */
- else
- hcntrl = inb(base + HCNTRL) & IRQMS; /* Default */
- outb(hcntrl | PAUSE, base + HCNTRL);
+ default:
+ printk(KERN_WARNING "aic7xxx: Host adapter uses unsupported IRQ "
+ "level %d, ignoring.\n", temp_p->irq);
+ kfree(temp_p);
+ slot++;
+ continue; /* back to the beginning of the while loop */
+ }
- p = aic7xxx_alloc(template, base, 0, chip_type, 0, NULL);
- if (p == NULL)
- {
- printk(KERN_WARNING "aic7xxx: Unable to allocate device space.\n");
- continue;
- }
- aic7xxx_chip_reset(p);
+ /*
+ * We are commited now, everything has been checked and this card
+ * has been found, now we just set it up
+ */
+ /*
+ * Insert our new struct into the list at the end
+ */
+ if (list_p == NULL)
+ {
+ list_p = current_p = temp_p;
+ }
+ else
+ {
+ current_p = list_p;
+ while (current_p->next != NULL)
+ current_p = current_p->next;
+ current_p->next = temp_p;
+ }
+ if (aic7xxx_extended)
+ {
+ temp_p->flags |= AHC_EXTEND_TRANS_A;
+ if (temp_p->flags & AHC_MULTI_CHANNEL)
+ temp_p->flags |= AHC_EXTEND_TRANS_B;
+ }
- irq = inb(INTDEF + base) & 0x0F;
- switch (irq)
+ switch (temp_p->type & 0x1ff1)
+ {
+ case AHC_AIC7770:
+ temp_p->board_name_index = 2;
+ case AHC_274:
{
- case 9:
- case 10:
- case 11:
- case 12:
- case 14:
- case 15:
- break;
-
- default:
- printk(KERN_WARNING "aic7xxx: Host adapter uses unsupported IRQ "
- "level %d, ignoring.\n", irq);
- irq = 0;
- aic7xxx_free(p);
- break;
- }
+ temp_p->bios_control = aic_inb(temp_p, HA_274_BIOSCTRL);
- if (irq != 0)
- {
- p->irq = irq & 0x0F;
- p->chip_class = AIC_777x;
-#ifdef AIC7XXX_PAGE_ENABLE
- p->flags |= PAGE_ENABLED;
-#endif
- p->instance = found;
- if (aic7xxx_extended)
+ /*
+ * Get the primary channel information. Right now we don't
+ * do anything with this, but someday we will be able to inform
+ * the mid-level SCSI code which channel is primary.
+ */
+ if (temp_p->board_name_index == 0)
+ temp_p->board_name_index = 3;
+ if (temp_p->bios_control & CHANNEL_B_PRIMARY)
{
- p->flags |= EXTENDED_TRANSLATION;
+ temp_p->flags |= AHC_CHANNEL_B_PRIMARY;
}
- switch (p->chip_type)
+ if ((temp_p->bios_control & BIOSMODE) == BIOSDISABLED)
{
- case AIC_7770:
- case AIC_7771:
+ temp_p->flags |= AHC_USEDEFAULTS;
+ temp_p->flags &= ~AHC_BIOS_ENABLED;
+ }
+ else
+ {
+ temp_p->flags &= ~AHC_USEDEFAULTS;
+ temp_p->flags |= AHC_BIOS_ENABLED;
+ if ( (temp_p->bios_control & 0x20) == 0 )
{
- unsigned char biosctrl = inb(p->base + HA_274_BIOSCTRL);
-
- /*
- * Get the primary channel information. Right now we don't
- * do anything with this, but someday we will be able to inform
- * the mid-level SCSI code which channel is primary.
- */
- if (biosctrl & CHANNEL_B_PRIMARY)
- {
- p->flags |= FLAGS_CHANNEL_B_PRIMARY;
- }
-
- if ((biosctrl & BIOSMODE) == BIOSDISABLED)
+ switch(temp_p->bios_control & 0x07)
{
- p->flags |= USE_DEFAULTS;
+ case 0x0:
+ temp_p->bios_address = 0xcc000;
+ break;
+ case 0x1:
+ temp_p->bios_address = 0xd0000;
+ break;
+ case 0x2:
+ temp_p->bios_address = 0xd4000;
+ break;
+ case 0x3:
+ temp_p->bios_address = 0xd8000;
+ break;
+ case 0x4:
+ temp_p->bios_address = 0xdc000;
+ break;
+ case 0x5:
+ temp_p->bios_address = 0xe0000;
+ break;
+ case 0x6:
+ temp_p->bios_address = 0xe4000;
+ break;
+ case 0x7:
+ temp_p->bios_address = 0xe8000;
+ break;
+ default:
+ break; /* can't get here */
}
- break;
}
-
- case AIC_284x:
- if (!load_seeprom(p, &sxfrctl1))
+ else
+ {
+ switch(temp_p->bios_control & 0x06)
{
- if (aic7xxx_verbose)
- printk(KERN_INFO "aic7xxx: SEEPROM not available.\n");
+ case 0x0:
+ temp_p->bios_address = 0xd0000;
+ break;
+ case 0x2:
+ temp_p->bios_address = 0xd8000;
+ break;
+ case 0x4:
+ temp_p->bios_address = 0xe0000;
+ break;
+ case 0x6:
+ temp_p->bios_address = 0xe8000;
+ break;
+ default:
+ break; /* can't get here */
}
- break;
-
- default: /* Won't get here. */
- break;
+ }
}
- printk(KERN_INFO "aic7xxx: BIOS %sabled, IO Port 0x%x, IRQ %d (%s), ",
- (p->flags & USE_DEFAULTS) ? "dis" : "en", p->base, p->irq,
- (p->pause & IRQMS) ? "level sensitive" : "edge triggered");
- /*
- * Check for Rev C or E boards. Rev E boards can supposedly have
- * more than 4 SCBs, while the Rev C boards are limited to 4 SCBs.
- * It's still not clear extactly what is different about the Rev E
- * boards, but we think it allows 8 bit entries in the QOUTFIFO to
- * support "paging" SCBs (more than 4 commands can be active at once).
- *
- * The Rev E boards have a read/write autoflush bit in the
- * SBLKCTL register, while in the Rev C boards it is read only.
- */
- sblkctl = inb(p->base + SBLKCTL) ^ AUTOFLUSHDIS;
- outb(sblkctl, p->base + SBLKCTL);
- if (inb(p->base + SBLKCTL) == sblkctl)
+ temp_p->adapter_control = aic_inb(temp_p, SCSICONF) << 8;
+ temp_p->adapter_control |= aic_inb(temp_p, SCSICONF + 1);
+ if (temp_p->flags & AHC_USEDEFAULTS)
{
- /*
- * We detected a Rev E board, we allow paging on this board.
- */
- printk("Revision >= E\n");
- outb(sblkctl & ~AUTOFLUSHDIS, base + SBLKCTL);
+ temp_p->scsi_id = temp_p->scsi_id_b = 7;
+ temp_p->flags |= AHC_TERM_ENB_A | AHC_TERM_ENB_B;
}
else
{
- /* Do not allow paging. */
- p->flags &= ~PAGE_ENABLED;
- printk("Revision <= C\n");
+ if ( ((temp_p->adapter_control >> 8) & TERM_ENB) != 0 )
+ temp_p->flags |= AHC_TERM_ENB_A;
+ if ( (temp_p->adapter_control & TERM_ENB) != 0 )
+ temp_p->flags |= AHC_TERM_ENB_B;
+ temp_p->scsi_id = (temp_p->adapter_control >> 8) & HSCSIID;
+ temp_p->scsi_id_b = temp_p->adapter_control & HSCSIID;
}
+ break;
+ }
- if (aic7xxx_verbose)
- printk(KERN_INFO "aic7xxx: Extended translation %sabled.\n",
- (p->flags & EXTENDED_TRANSLATION) ? "en" : "dis");
-
- /*
- * Set the FIFO threshold and the bus off time.
- */
- hostconf = inb(p->base + HOSTCONF);
- outb(hostconf & DFTHRSH, p->base + BUSSPD);
- outb((hostconf << 2) & BOFF, p->base + BUSTIME);
-
- /*
- * Try to initialize the card and register it with the kernel.
- */
- if (aic7xxx_register(template, p))
+ case AHC_284:
+ load_seeprom(temp_p, &sxfrctl1);
+ temp_p->board_name_index = 4;
+ switch( aic_inb(temp_p, STATUS_2840) & BIOS_SEL )
{
- /*
- * We successfully found a board and registered it.
- */
- found = found + 1;
- }
- else
- {
- /*
- * Something went wrong; release and free all resources.
- */
- aic7xxx_free(p);
+ case 0x00:
+ temp_p->bios_address = 0xe0000;
+ break;
+ case 0x20:
+ temp_p->bios_address = 0xc8000;
+ break;
+ case 0x40:
+ temp_p->bios_address = 0xd0000;
+ break;
+ case 0x60:
+ temp_p->bios_address = 0xd8000;
+ break;
+ default:
+ break; /* can't get here */
}
- }
- /*
- * Disallow spurious interrupts.
- */
- aic7xxx_spurious_count = 0;
+ break;
+
+ default: /* Won't get here. */
+ break;
}
+ if (aic7xxx_verbose & VERBOSE_PROBE2)
+ {
+ printk(KERN_INFO "aic7xxx: BIOS %sabled, IO Port 0x%lx, IRQ %d (%s)\n",
+ (temp_p->flags & AHC_USEDEFAULTS) ? "dis" : "en", temp_p->base,
+ temp_p->irq,
+ (temp_p->pause & IRQMS) ? "level sensitive" : "edge triggered");
+ printk(KERN_INFO "aic7xxx: Extended translation %sabled.\n",
+ (temp_p->flags & AHC_EXTEND_TRANS_A) ? "en" : "dis");
+ }
+
+ /*
+ * Set the FIFO threshold and the bus off time.
+ */
+ hostconf = aic_inb(temp_p, HOSTCONF);
+ aic_outb(temp_p, hostconf & DFTHRSH, BUSSPD);
+ aic_outb(temp_p, (hostconf << 2) & BOFF, BUSTIME);
+ slot++;
+ found++;
}
+#endif /* defined(__i386__) || defined(__alpha__) */
+
#ifdef CONFIG_PCI
/*
* PCI-bus probe.
@@ -6001,180 +7225,311 @@ aic7xxx_detect(Scsi_Host_Template *template)
{
unsigned short vendor_id;
unsigned short device_id;
- aha_chip_type chip_type;
- aha_chip_class_type chip_class;
+ ahc_type type;
+ ahc_flag_type flags;
+ int board_name_index;
} const aic7xxx_pci_devices[] = {
- {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7850, AIC_7850, AIC_785x},
- {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7855, AIC_7855, AIC_785x},
- {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7860, AIC_7860, AIC_786x},
- {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7861, AIC_7861, AIC_786x},
- {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7870, AIC_7870, AIC_787x},
- {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7871, AIC_7871, AIC_787x},
- {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7872, AIC_7872, AIC_787x},
- {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7873, AIC_7873, AIC_787x},
- {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7874, AIC_7874, AIC_787x},
- {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7880, AIC_7880, AIC_788x},
- {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7881, AIC_7881, AIC_788x},
- {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7882, AIC_7882, AIC_788x},
- {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7883, AIC_7883, AIC_788x},
- {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7884, AIC_7884, AIC_788x}
+ {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7810, AHC_NONE,
+ AHC_FNONE, 1 },
+ {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7850, AHC_AIC7850,
+ AHC_PAGESCBS | AHC_USEDEFAULTS, 5 },
+ {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7855, AHC_AIC7850,
+ AHC_PAGESCBS | AHC_USEDEFAULTS, 6 },
+ {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7860, AHC_AIC7860,
+ AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, 7 },
+ {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7861, AHC_294AU,
+ AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, 8 },
+ {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7870, AHC_AIC7870,
+ AHC_PAGESCBS | AHC_BIOS_ENABLED, 9 },
+ {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7871, AHC_294,
+ AHC_PAGESCBS | AHC_BIOS_ENABLED, 10 },
+ {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7872, AHC_394,
+ AHC_PAGESCBS | AHC_BIOS_ENABLED, 11 },
+ {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7873, AHC_398,
+ AHC_PAGESCBS | AHC_BIOS_ENABLED, 12 },
+ {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7874, AHC_294,
+ AHC_PAGESCBS | AHC_BIOS_ENABLED, 13 },
+ {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7880, AHC_AIC7880,
+ AHC_PAGESCBS | AHC_BIOS_ENABLED, 14 },
+ {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7881, AHC_294U,
+ AHC_PAGESCBS | AHC_BIOS_ENABLED, 15 },
+ {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7882, AHC_394U,
+ AHC_PAGESCBS | AHC_BIOS_ENABLED, 16 },
+ {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7883, AHC_398U,
+ AHC_PAGESCBS | AHC_BIOS_ENABLED, 17 },
+ {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7884, AHC_294U,
+ AHC_PAGESCBS | AHC_BIOS_ENABLED, 18 },
+ {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7895, AHC_AIC7895,
+ AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, 19 }
};
- int error, flags;
- int done = 0;
- unsigned int iobase, mbase;
- unsigned short index = 0;
- unsigned char pci_bus, pci_device_fn;
- unsigned char ultra_enb = 0;
- unsigned int devconfig, class_revid;
- scb_data_type *shared_scb_data = NULL;
- char rev_id[] = {'B', 'C', 'D'};
+ unsigned short command;
+ unsigned int devconfig, i;
+#ifdef MMAPIO
+ unsigned long page_offset;
+#endif
+ struct aic7xxx_host *first_7895 = NULL;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
+ struct pci_dev *pdev = NULL;
+#else
+ int index;
+ unsigned int piobase, mmapbase;
+ unsigned char pci_bus, pci_devfn;
+#endif
for (i = 0; i < NUMBER(aic7xxx_pci_devices); i++)
{
- done = FALSE;
- while (!done)
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
+ pdev = NULL;
+ while ((pdev = pci_find_device(aic7xxx_pci_devices[i].vendor_id,
+ aic7xxx_pci_devices[i].device_id,
+ pdev)))
+#else
+ index = 0;
+ while (!(pcibios_find_device(aic7xxx_pci_devices[i].vendor_id,
+ aic7xxx_pci_devices[i].device_id,
+ index++, &pci_bus, &pci_devfn)) )
+#endif
{
- if (pcibios_find_device(aic7xxx_pci_devices[i].vendor_id,
- aic7xxx_pci_devices[i].device_id,
- index, &pci_bus, &pci_device_fn))
- {
- index = 0;
- done = TRUE;
- }
- else /* Found an Adaptec PCI device. */
+ if ( i == 0 ) /* We found one, but it's the 7810 RAID cont. */
{
- chip_class = aic7xxx_pci_devices[i].chip_class;
- chip_type = aic7xxx_pci_devices[i].chip_type;
- chan_num = 0;
- flags = 0;
- switch (aic7xxx_pci_devices[i].chip_type)
+ if (aic7xxx_verbose & (VERBOSE_PROBE|VERBOSE_PROBE2))
{
- case AIC_7855:
- flags |= USE_DEFAULTS;
- break;
-
- case AIC_7872: /* 3940 */
- case AIC_7882: /* 3940-Ultra */
- flags |= MULTI_CHANNEL;
- chan_num = number_of_3940s & 0x1; /* Has 2 controllers */
- number_of_3940s++;
- break;
-
- case AIC_7873: /* 3985 */
- case AIC_7883: /* 3985-Ultra */
- chan_num = number_of_3985s; /* Has 3 controllers */
- flags |= MULTI_CHANNEL;
- number_of_3985s++;
- if (number_of_3985s == 3)
- {
- number_of_3985s = 0;
- shared_scb_data = NULL;
- }
- break;
-
- default:
- break;
+ printk(KERN_INFO "aic7xxx: The 7810 RAID controller is not "
+ "supported by\n");
+ printk(KERN_INFO " this driver, we are ignoring it.\n");
}
+ }
+ else if ( (temp_p = kmalloc(sizeof(struct aic7xxx_host),
+ GFP_ATOMIC)) != NULL )
+ {
+ memset(temp_p, 0, sizeof(struct aic7xxx_host));
+ temp_p->type = aic7xxx_pci_devices[i].type;
+ temp_p->flags = aic7xxx_pci_devices[i].flags;
+ temp_p->board_name_index = aic7xxx_pci_devices[i].board_name_index;
/*
* Read sundry information from PCI BIOS.
*/
- error = pcibios_read_config_dword(pci_bus, pci_device_fn,
- PCI_BASE_ADDRESS_0, &iobase);
- error += pcibios_read_config_byte(pci_bus, pci_device_fn,
- PCI_INTERRUPT_LINE, &irq);
- error += pcibios_read_config_dword(pci_bus, pci_device_fn,
- PCI_BASE_ADDRESS_1, &mbase);
- error += pcibios_read_config_dword(pci_bus, pci_device_fn,
- DEVCONFIG, &devconfig);
- error += pcibios_read_config_dword(pci_bus, pci_device_fn,
- CLASS_PROGIF_REVID, &class_revid);
-
- printk("aic7xxx: <%s> at PCI %d\n",
- board_names[chip_type], PCI_SLOT(pci_device_fn));
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
+ temp_p->irq = pdev->irq;
+ temp_p->pci_bus = pdev->bus->number;
+ temp_p->pci_device_fn = pdev->devfn;
+ temp_p->base = pdev->base_address[0];
+ temp_p->mbase = pdev->base_address[1];
+ pci_read_config_word(pdev, PCI_COMMAND, &command);
+ pci_write_config_word(pdev, PCI_COMMAND,
+ command | PCI_COMMAND_MASTER |
+ PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
+#else
+ temp_p->pci_bus = pci_bus;
+ temp_p->pci_device_fn = pci_devfn;
+ pcibios_read_config_byte(pci_bus, pci_devfn, PCI_INTERRUPT_LINE,
+ &temp_p->irq);
+ pcibios_read_config_dword(pci_bus, pci_devfn, PCI_BASE_ADDRESS_0,
+ &piobase);
+ temp_p->base = piobase;
+ pcibios_read_config_dword(pci_bus, pci_devfn, PCI_BASE_ADDRESS_1,
+ &mmapbase);
+ temp_p->mbase = mmapbase;
+ pcibios_read_config_word(pci_bus, pci_devfn, PCI_COMMAND, &command);
+ pcibios_write_config_word(pci_bus, pci_devfn, PCI_COMMAND,
+ command | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY |
+ PCI_COMMAND_IO);
+#endif
+
+ if (aic7xxx_verbose & VERBOSE_PROBE2)
+ printk("aic7xxx: <%s> at PCI %d/%d\n",
+ board_names[aic7xxx_pci_devices[i].board_name_index],
+ PCI_SLOT(temp_p->pci_device_fn),
+ PCI_FUNC(temp_p->pci_device_fn));
/*
* The first bit (LSB) of PCI_BASE_ADDRESS_0 is always set, so
* we mask it off.
*/
- iobase &= PCI_BASE_ADDRESS_IO_MASK;
-
- p = aic7xxx_alloc(template, iobase, mbase, chip_type, flags,
- shared_scb_data);
-
- if (p == NULL)
+ temp_p->base &= PCI_BASE_ADDRESS_IO_MASK;
+ temp_p->mbase &= PCI_BASE_ADDRESS_MEM_MASK;
+ temp_p->unpause = (aic_inb(temp_p, HCNTRL) & IRQMS) | INTEN;
+ temp_p->pause = temp_p->unpause | PAUSE;
+
+#ifdef MMAPIO
+ base = temp_p->mbase & PAGE_MASK;
+ page_offset = temp_p->mbase - base;
+ /*
+ * replace the next line with this one if you are using 2.1.x:
+ * temp_p->maddr = ioremap(base, page_offset + 256);
+ */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
+ temp_p->maddr = ioremap(base, page_offset + 256);
+#else
+ temp_p->maddr = vremap(base, page_offset + 256);
+#endif
+ if(temp_p->maddr)
{
- printk(KERN_WARNING "aic7xxx: Unable to allocate device space.\n");
- continue;
+ temp_p->maddr += page_offset;
}
-
- /* Remember to set the channel number, irq, and chip class. */
- p->chan_num = chan_num;
- p->irq = irq;
- p->chip_class = chip_class;
-#ifdef AIC7XXX_PAGE_ENABLE
- p->flags |= PAGE_ENABLED;
#endif
- p->instance = found;
+
+ aic_outb(temp_p, temp_p->pause, HCNTRL);
+ while( (aic_inb(temp_p, HCNTRL) & PAUSE) == 0 ) ;
+
+ temp_p->bios_address = 0;
/*
* Remember how the card was setup in case there is no seeprom.
*/
- p->scsi_id = inb(p->base + SCSIID) & OID;
- if ((p->chip_class == AIC_786x) || (p->chip_class == AIC_788x))
+ temp_p->scsi_id = aic_inb(temp_p, SCSIID) & OID;
+ /*
+ * Get current termination setting
+ */
+ sxfrctl1 = aic_inb(temp_p, SXFRCTL1) & STPWEN;
+
+ if (aic7xxx_chip_reset(temp_p) == -1)
{
- p->flags |= ULTRA_ENABLED;
- ultra_enb = inb(p->base + SXFRCTL1) & FAST20;
+ kfree(temp_p);
+ temp_p = NULL;
+ continue;
}
- sxfrctl1 = inb(p->base + SXFRCTL1) & STPWEN;
- aic7xxx_chip_reset(p);
-
-#ifdef AIC7XXX_USE_EXT_SCBRAM
- if (devconfig & RAMPSM)
+ switch (temp_p->type & 0x1ff1)
{
- printk(KERN_INFO "aic7xxx: External RAM detected; enabling RAM "
- "access.\n");
- /*
- * XXX - Assume 9 bit SRAM and enable parity checking.
- */
- devconfig |= EXTSCBPEN;
+ case AHC_394: /* 3940 */
+ case AHC_394U: /* 3940-Ultra */
+ temp_p->flags |= AHC_MULTI_CHANNEL;
+ switch(PCI_SLOT(temp_p->pci_device_fn))
+ {
+ case 5:
+ temp_p->flags |= AHC_CHNLB;
+ break;
+ default:
+ break;
+ }
+ break;
- /*
- * XXX - Assume fast SRAM and only enable 2 cycle access if we
- * are sharing the SRAM across multiple adapters (398x).
- */
- if ((devconfig & MPORTMODE) == 0)
- {
- devconfig |= EXTSCBTIME;
- }
- devconfig &= ~SCBRAMSEL;
- pcibios_write_config_dword(pci_bus, pci_device_fn,
- DEVCONFIG, devconfig);
- }
+ case AHC_398: /* 3985 */
+ case AHC_398U: /* 3985-Ultra */
+ temp_p->flags |= AHC_MULTI_CHANNEL;
+ switch(PCI_SLOT(temp_p->pci_device_fn))
+ {
+ case 8:
+ temp_p->flags |= AHC_CHNLB;
+ break;
+ case 12:
+ temp_p->flags |= AHC_CHNLC;
+ break;
+ default:
+ break;
+ }
+ break;
+
+ case AHC_AIC7895:
+ temp_p->flags |= AHC_MULTI_CHANNEL;
+ if (PCI_FUNC(temp_p->pci_device_fn) != 0)
+ {
+ temp_p->flags |= AHC_CHNLB;
+ }
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
+ pci_read_config_dword(pdev, DEVCONFIG, &devconfig);
+ devconfig |= SCBSIZE32;
+ pci_write_config_dword(pdev, DEVCONFIG, devconfig);
+#else
+ pcibios_read_config_dword(pci_bus, pci_devfn, DEVCONFIG,
+ &devconfig);
+ devconfig |= SCBSIZE32;
+ pcibios_write_config_dword(pci_bus, pci_devfn, DEVCONFIG,
+ devconfig);
#endif
+ if (aic7xxx_7895_irq_hack != -1)
+ {
+ if (first_7895 == NULL)
+ {
+ printk(KERN_INFO "aic7xxx: Using 7895_irq_hack. Please "
+ "upgrade your motherboard BIOS\n");
+ first_7895 = temp_p;
+ }
+ else if (aic7xxx_7895_irq_hack == 0)
+ {
+ if (temp_p->flags & AHC_CHNLB)
+ temp_p->irq = first_7895->irq;
+ else
+ first_7895->irq = temp_p->irq;
+ first_7895 = NULL;
+ }
+ else
+ {
+ if ( !(temp_p->flags & AHC_CHNLB) )
+ temp_p->irq = first_7895->irq;
+ else
+ first_7895->irq = temp_p->irq;
+ first_7895 = NULL;
+ }
+ }
+ break;
+ default:
+ break;
+ }
- if ((p->flags & USE_DEFAULTS) == 0)
+ /*
+ * Loading of the SEEPROM needs to come after we've set the flags
+ * to indicate possible CHNLB and CHNLC assigments. Otherwise,
+ * on 394x and 398x cards we'll end up reading the wrong settings
+ * for channels B and C
+ */
+ if ( !(load_seeprom(temp_p, &sxfrctl1)) )
{
- load_seeprom(p, &sxfrctl1);
+ temp_p->flags |= AHC_USEDEFAULTS;
+ if (sxfrctl1 & STPWEN)
+ temp_p->flags |= AHC_TERM_ENB_A | AHC_TERM_ENB_B;
+ temp_p->scsi_id = temp_p->scsi_id_b = 7;
+ }
+
+ /*
+ * and then we need another switch based on the type in order to
+ * make sure the channel B primary flag is set properly on 7895
+ * controllers....Arrrgggghhh!!!
+ */
+ switch(temp_p->type & 0x1ff1)
+ {
+ case AHC_AIC7895:
+ current_p = list_p;
+ while(current_p != NULL)
+ {
+ if ( (current_p->pci_bus == temp_p->pci_bus) &&
+ (PCI_SLOT(current_p->pci_device_fn) ==
+ PCI_SLOT(temp_p->pci_device_fn)) )
+ {
+ if ( PCI_FUNC(current_p->pci_device_fn) == 0 )
+ temp_p->flags |=
+ (current_p->flags & AHC_CHANNEL_B_PRIMARY);
+ else
+ current_p->flags |=
+ (temp_p->flags & AHC_CHANNEL_B_PRIMARY);
+ }
+ current_p = current_p->next;
+ }
+ break;
+ default:
+ break;
}
/*
* Take the LED out of diagnostic mode
*/
- sblkctl = inb(p->base + SBLKCTL);
- outb((sblkctl & ~(DIAGLEDEN | DIAGLEDON)), p->base + SBLKCTL);
+ aic_outb(temp_p,
+ (aic_inb(temp_p, SBLKCTL) & ~(DIAGLEDEN | DIAGLEDON)),
+ SBLKCTL);
/*
* We don't know where this is set in the SEEPROM or by the
* BIOS, so we default to 100%.
*/
- outb(DFTHRSH_100, p->base + DSPCISTATUS);
+ aic_outb(temp_p, DFTHRSH_100, DSPCISTATUS);
- if (p->flags & USE_DEFAULTS)
+ if (temp_p->flags & AHC_USEDEFAULTS)
{
int j;
+ unsigned char k;
/*
* Default setup; should only be used if the adapter does
* not have a SEEPROM.
@@ -6186,128 +7541,315 @@ aic7xxx_detect(Scsi_Host_Template *template)
*/
for (j = TARG_SCRATCH; j < 0x60; j++)
{
- if (inb(p->base + j) != 0x00) /* Check for all zeroes. */
+ k = aic_inb(temp_p, j);
+ /* Check for all zeros and ones. Break out if we pass */
+ if( (k != 0x00) && (k != 0xff) )
break;
}
- if (j == TARG_SCRATCH)
- {
- for (j = TARG_SCRATCH; j < 0x60; j++)
- {
- if (inb(p->base + 1) != 0xFF) /* Check for all ones. */
- break;
- }
- }
- if ((j != 0x60) && (p->scsi_id != 0))
+ /* If j makes it to 0x60, then all entries are either 0x00 or
+ * 0xff. We would then assume we have *not* been initialized
+ * and drop through here. OTOH, if even one entry is inited,
+ * then as long as we appear to have a valid SCSI ID, we'll use
+ * the leftover BIOS values.
+ */
+ if ((j != 0x60) && (temp_p->scsi_id != 0))
{
- p->flags &= ~USE_DEFAULTS;
- if (aic7xxx_verbose)
+ temp_p->flags &= ~AHC_USEDEFAULTS;
+ if (aic7xxx_verbose & VERBOSE_PROBE2)
{
printk(KERN_INFO "aic7xxx: Using leftover BIOS values.\n");
}
}
else
{
- if (aic7xxx_verbose)
- {
- printk(KERN_INFO "aic7xxx: No BIOS found; using default "
- "settings.\n");
- }
/*
* Assume only one connector and always turn on
* termination.
*/
+ temp_p->flags &= ~AHC_BIOS_ENABLED;
+ temp_p->flags |= AHC_TERM_ENB_A | AHC_TERM_ENB_B;
sxfrctl1 = STPWEN;
- p->scsi_id = 7;
+ temp_p->scsi_id = 7;
}
- outb((p->scsi_id & HSCSIID) | ENSPCHK | RESET_SCSI,
- p->base + SCSICONF);
+ aic_outb(temp_p, (temp_p->scsi_id & HSCSIID) | ENSPCHK | RESET_SCSI,
+ SCSICONF);
/* In case we are a wide card. */
- outb(p->scsi_id, p->base + SCSICONF + 1);
- if ((ultra_enb == 0) && ((p->flags & USE_DEFAULTS) == 0))
- {
- /*
- * If there wasn't a BIOS or the board wasn't in this mode
- * to begin with, turn off Ultra.
- */
- p->flags &= ~ULTRA_ENABLED;
- }
+ aic_outb(temp_p, temp_p->scsi_id, SCSICONF + 1);
}
-
- /*
- * Print some additional information about the adapter.
- */
- printk(KERN_INFO "aic7xxx: BIOS %sabled, IO Port 0x%x, "
- "IO Mem 0x%x, IRQ %d",
- (p->flags & USE_DEFAULTS) ? "dis" : "en",
- p->base, p->mbase, p->irq);
- if ((class_revid & DEVREVID) < 3)
+ else /* not using defaults */
{
- printk(", Revision %c", rev_id[class_revid & DEVREVID]);
+ if (sxfrctl1 & STPWEN)
+ temp_p->flags |= AHC_TERM_ENB_A;
}
- printk("\n");
-
- /*
- * I don't think we need to bother with allowing
- * spurious interrupts for the 787x/785x, but what
- * the hey.
- */
- aic7xxx_spurious_count = 1;
if (aic7xxx_extended)
- p->flags |= EXTENDED_TRANSLATION;
-
- if (aic7xxx_verbose)
- printk(KERN_INFO "aic7xxx: Extended translation %sabled.\n",
- (p->flags & EXTENDED_TRANSLATION) ? "en" : "dis");
+ temp_p->flags |= AHC_EXTEND_TRANS_A;
/*
* Put our termination setting into sxfrctl1 now that the
* generic initialization is complete.
*/
- sxfrctl1 |= inb(p->base + SXFRCTL1);
- outb(sxfrctl1, p->base + SXFRCTL1);
-
- if (aic7xxx_register(template, p) == 0)
+ sxfrctl1 |= aic_inb(temp_p, SXFRCTL1);
+ aic_outb(temp_p, sxfrctl1, SXFRCTL1);
+ if ( list_p == NULL )
{
- aic7xxx_free(p);
+ list_p = current_p = temp_p;
}
else
{
- found = found + 1;
+ current_p = list_p;
+ while(current_p->next != NULL)
+ current_p = current_p->next;
+ current_p->next = temp_p;
+ }
+ temp_p->next = NULL;
+ found++;
+ } /* Found an Adaptec PCI device. */
+ else /* Well, we found one, but we couldn't get any memory */
+ {
+ printk("aic7xxx: Found <%s>\n",
+ board_names[aic7xxx_pci_devices[i].board_name_index]);
+ printk(KERN_INFO "aic7xxx: Unable to allocate device memory, "
+ "skipping.\n");
+ }
+ } /* while(pdev=....) */
+ } /* for PCI_DEVICES */
+ } /* PCI BIOS present */
+#endif CONFIG_PCI
+ /*
+ * Now, we re-order the probed devices by BIOS address and BUS class.
+ * In general, we follow this algorithm to make the adapters show up
+ * in the same order under linux that the computer finds them.
+ * 1: All VLB/EISA cards with BIOS_ENABLED first, according to BIOS
+ * address, going from lowest to highest.
+ * 2: All PCI controllers with BIOS_ENABLED next, according to BIOS
+ * address, going from lowest to highest.
+ * 3: Remaining VLB/EISA controllers going in slot order.
+ * 4: Remaining PCI controllers, going in PCI device order (reversable)
+ */
+
+ {
+ struct aic7xxx_host *vlb_enab, *vlb_disab, *pci;
+ struct aic7xxx_host *prev_p;
+ struct aic7xxx_host *p;
+ unsigned char left;
+
+ prev_p = vlb_enab = vlb_disab = pci = NULL;
-#ifdef AIC7XXX_USE_EXT_SCBRAM
+ temp_p = list_p;
+ while (temp_p != NULL)
+ {
+ switch(temp_p->type)
+ {
+ case AHC_AIC7770:
+ case AHC_274:
+ case AHC_284:
+ if (temp_p->flags & AHC_BIOS_ENABLED)
+ {
+ if (vlb_enab == NULL)
+ {
+ vlb_enab = temp_p;
+ temp_p = temp_p->next;
+ vlb_enab->next = NULL;
+ }
+ else
+ {
+ current_p = vlb_enab;
+ prev_p = NULL;
+ while ( (current_p != NULL) &&
+ (current_p->bios_address < temp_p->bios_address))
+ {
+ prev_p = current_p;
+ current_p = current_p->next;
+ }
+ if (prev_p != NULL)
+ {
+ prev_p->next = temp_p;
+ temp_p = temp_p->next;
+ prev_p->next->next = current_p;
+ }
+ else
+ {
+ vlb_enab = temp_p;
+ temp_p = temp_p->next;
+ vlb_enab->next = current_p;
+ }
+ }
+ }
+ else
+ {
+ if (vlb_disab == NULL)
+ {
+ vlb_disab = temp_p;
+ temp_p = temp_p->next;
+ vlb_disab->next = NULL;
+ }
+ else
+ {
+ current_p = vlb_disab;
+ prev_p = NULL;
+ while ( (current_p != NULL) &&
+ (current_p->base < temp_p->base))
+ {
+ prev_p = current_p;
+ current_p = current_p->next;
+ }
+ if (prev_p != NULL)
+ {
+ prev_p->next = temp_p;
+ temp_p = temp_p->next;
+ prev_p->next->next = current_p;
+ }
+ else
+ {
+ vlb_disab = temp_p;
+ temp_p = temp_p->next;
+ vlb_disab->next = current_p;
+ }
+ }
+ }
+ break;
+ default: /* All PCI controllers fall through to default */
+ if (pci == NULL)
+ {
+ pci = temp_p;
+ temp_p = temp_p->next;
+ pci->next = NULL;
+ }
+ else
+ {
+ current_p = pci;
+ prev_p = NULL;
+ if (!aic7xxx_reverse_scan)
+ {
+ while ( (current_p != NULL) &&
+ ( (PCI_SLOT(current_p->pci_device_fn) |
+ (current_p->pci_bus << 8)) <
+ (PCI_SLOT(temp_p->pci_device_fn) |
+ (temp_p->pci_bus << 8)) ) )
+ {
+ prev_p = current_p;
+ current_p = current_p->next;
+ }
+ }
+ else
+ {
+ while ( (current_p != NULL) &&
+ ( (PCI_SLOT(current_p->pci_device_fn) |
+ (current_p->pci_bus << 8)) >
+ (PCI_SLOT(temp_p->pci_device_fn) |
+ (temp_p->pci_bus << 8)) ) )
+ {
+ prev_p = current_p;
+ current_p = current_p->next;
+ }
+ }
/*
- * Set the shared SCB data once we've successfully probed a
- * 398x adapter.
- *
- * Note that we can only do this if the use of external
- * SCB RAM is enabled.
+ * Are we dealing with a 7985 where we need to sort the
+ * channels as well, if so, the bios_address values should
+ * be the same
*/
- if ((p->chip_type == AIC_7873) || (p->chip_type == AIC_7883))
+ if ( (current_p) && (temp_p->flags & AHC_MULTI_CHANNEL) &&
+ (temp_p->pci_bus == current_p->pci_bus) &&
+ (PCI_SLOT(temp_p->pci_device_fn) ==
+ PCI_SLOT(current_p->pci_device_fn)) )
{
- if (shared_scb_data == NULL)
+ if (temp_p->flags & AHC_CHNLB)
{
- shared_scb_data = p->scb_data;
+ if ( !(temp_p->flags & AHC_CHANNEL_B_PRIMARY) )
+ {
+ prev_p = current_p;
+ current_p = current_p->next;
+ }
+ }
+ else
+ {
+ if (temp_p->flags & AHC_CHANNEL_B_PRIMARY)
+ {
+ prev_p = current_p;
+ current_p = current_p->next;
+ }
}
}
-#endif
+ if (prev_p != NULL)
+ {
+ prev_p->next = temp_p;
+ temp_p = temp_p->next;
+ prev_p->next->next = current_p;
+ }
+ else
+ {
+ pci = temp_p;
+ temp_p = temp_p->next;
+ pci->next = current_p;
+ }
}
-
- index++;
- /*
- * Disable spurious interrupts.
- */
- aic7xxx_spurious_count = 0;
- } /* Found an Adaptec PCI device. */
+ break;
+ } /* End of switch(temp_p->type) */
+ } /* End of while (temp_p != NULL) */
+ /*
+ * At this point, the cards have been broken into 4 sorted lists, now
+ * we run through the lists in order and register each controller
+ */
+ left = found;
+ temp_p = vlb_enab;
+ while(temp_p != NULL)
+ {
+ template->name = board_names[temp_p->board_name_index];
+ p = aic7xxx_alloc(template, temp_p);
+ if (p != NULL)
+ {
+ p->instance = found - left;
+ if (aic7xxx_register(template, p, (--left)) == 0)
+ {
+ found--;
+ aic7xxx_free(p);
+ }
}
+ current_p = temp_p;
+ temp_p = (struct aic7xxx_host *)temp_p->next;
+ kfree(current_p);
+ }
+ temp_p = pci;
+ while(temp_p != NULL)
+ {
+ template->name = board_names[temp_p->board_name_index];
+ p = aic7xxx_alloc(template, temp_p);
+ if (p != NULL)
+ {
+ p->instance = found - left;
+ if (aic7xxx_register(template, p, (--left)) == 0)
+ {
+ found--;
+ aic7xxx_free(p);
+ }
+ }
+ current_p = temp_p;
+ temp_p = (struct aic7xxx_host *)temp_p->next;
+ kfree(current_p);
+ }
+ temp_p = vlb_disab;
+ while(temp_p != NULL)
+ {
+ template->name = board_names[temp_p->board_name_index];
+ p = aic7xxx_alloc(template, temp_p);
+ if (p != NULL)
+ {
+ p->instance = found - left;
+ if (aic7xxx_register(template, p, (--left)) == 0)
+ {
+ found--;
+ aic7xxx_free(p);
+ }
+ }
+ current_p = temp_p;
+ temp_p = (struct aic7xxx_host *)temp_p->next;
+ kfree(current_p);
}
}
-#endif CONFIG_PCI
-
return (found);
}
-
/*+F*************************************************************************
* Function:
* aic7xxx_buildscb
@@ -6329,57 +7871,61 @@ aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
* Setup the control byte if we need negotiation and have not
* already requested it.
*/
+ hscb->control = 0;
+ scb->tag_action = 0;
if (p->discenable & mask)
{
hscb->control |= DISCENB;
-#ifdef AIC7XXX_TAGGED_QUEUEING
- if (cmd->device->tagged_queue)
+ if (p->tagenable & mask)
{
cmd->tag = hscb->tag;
- p->device_status[TARGET_INDEX(cmd)].commands_sent++;
- if (p->device_status[TARGET_INDEX(cmd)].commands_sent < 75)
+ p->dev_commands_sent[TARGET_INDEX(cmd)]++;
+ if (p->dev_commands_sent[TARGET_INDEX(cmd)] < 200)
{
hscb->control |= MSG_SIMPLE_Q_TAG;
+ scb->tag_action = MSG_SIMPLE_Q_TAG;
}
else
{
- hscb->control |= MSG_ORDERED_Q_TAG;
- p->device_status[TARGET_INDEX(cmd)].commands_sent = 0;
+ if (p->orderedtag & mask)
+ {
+ hscb->control |= MSG_ORDERED_Q_TAG;
+ scb->tag_action = MSG_ORDERED_Q_TAG;
+ }
+ else
+ {
+ hscb->control |= MSG_SIMPLE_Q_TAG;
+ scb->tag_action = MSG_SIMPLE_Q_TAG;
+ }
+ p->dev_commands_sent[TARGET_INDEX(cmd)] = 0;
}
}
-#endif /* Tagged queueing */
}
-
- if ((p->needwdtr & mask) && !(p->wdtr_pending & mask))
+ if ( (p->needwdtr & mask) &&
+ !(p->wdtr_pending & mask) &&
+ !(scb->tag_action))
{
p->wdtr_pending |= mask;
hscb->control |= MK_MESSAGE;
- scb->flags |= SCB_MSGOUT_WDTR;
-#if 0
- printk("scsi%d: Sending WDTR request to target %d.\n",
- p->host_no, cmd->target);
-#endif
+ if (p->needwdtr_copy & mask)
+ scb->flags |= SCB_MSGOUT_WDTR_16BIT;
+ else
+ scb->flags |= SCB_MSGOUT_WDTR_8BIT;
}
else
{
- if ((p->needsdtr & mask) && !(p->sdtr_pending & mask))
+ if ( (p->needsdtr & mask) &&
+ !(p->sdtr_pending & mask) &&
+ !(p->wdtr_pending & mask) &&
+ !(scb->tag_action) )
{
p->sdtr_pending |= mask;
hscb->control |= MK_MESSAGE;
scb->flags |= SCB_MSGOUT_SDTR;
-#if 0
- printk("scsi%d: Sending SDTR request to target %d.\n",
- p->host_no, cmd->target);
-#endif
}
}
-#if 0
- printk("aic7xxx: (build_scb) Target %d, cmd(0x%x) size(%u) wdtr(0x%x) "
- "mask(0x%x).\n",
- cmd->target, cmd->cmnd[0], cmd->cmd_len, p->needwdtr, mask);
-#endif
hscb->target_channel_lun = ((cmd->target << 4) & 0xF0) |
- ((cmd->channel & 0x01) << 3) | (cmd->lun & 0x07);
+ ((cmd->channel & 0x01) << 3) | (cmd->lun & 0x07);
/*
* The interpretation of request_buffer and request_bufflen
@@ -6393,7 +7939,7 @@ aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
* little-endian format.
*/
hscb->SCSI_cmd_length = cmd->cmd_len;
- hscb->SCSI_cmd_pointer = VIRT_TO_BUS(cmd->cmnd);
+ hscb->SCSI_cmd_pointer = cpu_to_le32(VIRT_TO_BUS(cmd->cmnd));
if (cmd->use_sg)
{
@@ -6408,46 +7954,42 @@ aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
int i;
sg = (struct scatterlist *)cmd->request_buffer;
+ scb->sg_length = 0;
for (i = 0; i < cmd->use_sg; i++)
{
- scb->sg_list[i].address = VIRT_TO_BUS(sg[i].address);
- scb->sg_list[i].length = (unsigned int) sg[i].length;
+ scb->sg_list[i].address = cpu_to_le32(VIRT_TO_BUS(sg[i].address));
+ scb->sg_list[i].length = cpu_to_le32(sg[i].length);
+ scb->sg_length += sg[i].length;
}
- hscb->SG_list_pointer = VIRT_TO_BUS(scb->sg_list);
+ hscb->SG_list_pointer = cpu_to_le32(VIRT_TO_BUS(scb->sg_list));
hscb->SG_segment_count = cmd->use_sg;
- scb->sg_count = hscb->SG_segment_count;
+ scb->sg_count = cmd->use_sg;
/* Copy the first SG into the data pointer area. */
hscb->data_pointer = scb->sg_list[0].address;
- hscb->data_count = scb->sg_list[0].length | (SCB_LIST_NULL << 24);
-#if 0
- printk("aic7xxx: (build_scb) SG segs(%d), length(%u), sg[0].length(%d).\n",
- cmd->use_sg, aic7xxx_length(cmd, 0), hscb->data_count);
-#endif
+ hscb->data_count = scb->sg_list[0].length;
}
else
{
-#if 0
- printk("aic7xxx: (build_scb) Creating scatterlist, addr(0x%lx) length(%d).\n",
- (unsigned long) cmd->request_buffer, cmd->request_bufflen);
-#endif
if (cmd->request_bufflen)
{
- hscb->SG_segment_count = 1;
scb->sg_count = 1;
- scb->sg_list[0].address = VIRT_TO_BUS(cmd->request_buffer);
- scb->sg_list[0].length = cmd->request_bufflen;
- hscb->SG_list_pointer = VIRT_TO_BUS(&scb->sg_list[0]);
- hscb->data_count = scb->sg_list[0].length | (SCB_LIST_NULL << 24);
- hscb->data_pointer = VIRT_TO_BUS(cmd->request_buffer);
+ scb->sg_list[0].address = cpu_to_le32(VIRT_TO_BUS(cmd->request_buffer));
+ scb->sg_list[0].length = cpu_to_le32(cmd->request_bufflen);
+ scb->sg_length = cmd->request_bufflen;
+ hscb->SG_segment_count = 1;
+ hscb->SG_list_pointer = cpu_to_le32(VIRT_TO_BUS(&scb->sg_list[0]));
+ hscb->data_count = scb->sg_list[0].length;
+ hscb->data_pointer = scb->sg_list[0].address;
}
else
{
- hscb->SG_segment_count = 0;
scb->sg_count = 0;
+ scb->sg_length = 0;
+ hscb->SG_segment_count = 0;
hscb->SG_list_pointer = 0;
+ hscb->data_count = 0;
hscb->data_pointer = 0;
- hscb->data_count = SCB_LIST_NULL << 24;
}
}
}
@@ -6462,58 +8004,53 @@ aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
int
aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
{
- long processor_flags;
struct aic7xxx_host *p;
struct aic7xxx_scb *scb;
+ int tindex = TARGET_INDEX(cmd);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+ unsigned long cpu_flags = 0;
+#endif
p = (struct aic7xxx_host *) cmd->host->hostdata;
- if (p->host != cmd->host)
- {
- printk(KERN_INFO "scsi%d: Internal host structure != scsi.c host "
- "structure.\n", p->host_no);
- }
-
/*
* Check to see if channel was scanned.
*/
- if (!(p->flags & A_SCANNED) && (cmd->channel == 0))
+ if (!(p->flags & AHC_A_SCANNED) && (cmd->channel == 0))
{
- printk(KERN_INFO "scsi%d: Scanning channel A for devices.\n", p->host_no);
- p->flags |= A_SCANNED;
+ printk(INFO_LEAD "Scanning channel for devices.\n",
+ p->host_no, 0, -1, -1);
+ p->flags |= AHC_A_SCANNED;
}
else
{
- if (!(p->flags & B_SCANNED) && (cmd->channel == 1))
+ if (!(p->flags & AHC_B_SCANNED) && (cmd->channel == 1))
{
- printk(KERN_INFO "scsi%d: Scanning channel B for devices.\n", p->host_no);
- p->flags |= B_SCANNED;
+ printk(INFO_LEAD "Scanning channel for devices.\n",
+ p->host_no, 1, -1, -1);
+ p->flags |= AHC_B_SCANNED;
}
}
-#if 0
- printk("aic7xxx: (queue) cmd(0x%x) size(%u), target %d, channel %d, lun %d.\n",
- cmd->cmnd[0], cmd->cmd_len, cmd->target, cmd->channel,
- cmd->lun & 0x07);
-#endif
-
- if (p->device_status[TARGET_INDEX(cmd)].active_cmds
- > cmd->device->queue_depth)
+ if (p->dev_active_cmds[tindex] > cmd->device->queue_depth)
{
- printk(KERN_WARNING "(scsi%d:%d:%d) Commands queued exceeds queue depth\n",
- p->host_no, cmd->target, cmd->channel);
+ printk(WARN_LEAD "Commands queued exceeds queue "
+ "depth, active=%d\n",
+ p->host_no, CTL_OF_CMD(cmd),
+ p->dev_active_cmds[tindex]);
+ if ( p->dev_active_cmds[tindex] > 220 )
+ p->dev_active_cmds[tindex] = 0;
}
- scb = aic7xxx_allocate_scb(p);
+ DRIVER_LOCK
+ scb = aic7xxx_allocate_scb(p, FALSE);
+ DRIVER_UNLOCK
if (scb == NULL)
{
- panic("aic7xxx: (aic7xxx_queue) Couldn't find a free SCB.\n");
+ panic("(scsi%d) aic7xxx_queue:Couldn't get a free SCB.\n", p->host_no);
}
else
{
scb->cmd = cmd;
aic7xxx_position(cmd) = scb->hscb->tag;
-#if 0
- debug_scb(scb);
-#endif;
/*
* Construct the SCB beforehand, so the sequencer is
@@ -6521,17 +8058,6 @@ aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
*/
aic7xxx_buildscb(p, cmd, scb);
-#if 0
- if (scb != (p->scb_data->scb_array[scb->hscb->tag]))
- {
- printk("aic7xxx: (queue) Address of SCB by position does not match SCB "
- "address.\n");
- }
- printk("aic7xxx: (queue) SCB pos(%d) cmdptr(0x%x) state(%d) freescb(0x%x)\n",
- scb->hscb->tag, (unsigned int) scb->cmd,
- scb->flags, (unsigned int) p->free_scb);
-#endif
-
/*
* Make sure the Scsi_Cmnd pointer is saved, the struct it points to
* is set up properly, and the parity error flag is reset, then send
@@ -6546,19 +8072,20 @@ aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
scb->flags |= SCB_ACTIVE | SCB_WAITINGQ;
- save_flags(processor_flags);
- cli();
- scbq_insert_tail(&p->waiting_scbs, scb);
- if ((p->flags & (IN_ISR | IN_TIMEOUT)) == 0)
+ DRIVER_LOCK
+ if (p->delayed_scbs[tindex].head != NULL)
+ {
+ scbq_insert_tail(&p->delayed_scbs[tindex], scb);
+ }
+ else
+ {
+ scbq_insert_tail(&p->waiting_scbs, scb);
+ }
+ if ( (p->flags & (AHC_IN_ISR | AHC_IN_ABORT | AHC_IN_RESET)) == 0)
{
aic7xxx_run_waiting_queues(p);
}
-
- restore_flags(processor_flags);
-#if 0
- printk("aic7xxx: (queue) After - cmd(0x%lx) scb->cmd(0x%lx) pos(%d).\n",
- (long) cmd, (long) scb->cmd, scb->hscb->tag);
-#endif;
+ DRIVER_UNLOCK
}
return (0);
}
@@ -6579,103 +8106,58 @@ aic7xxx_bus_device_reset(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
{
struct aic7xxx_scb *scb;
struct aic7xxx_hwscb *hscb;
- unsigned char bus_state;
int result = -1;
- char channel;
+ int channel;
+ unsigned char saved_scbptr, lastphase;
+ unsigned char hscb_index;
+ int disconnected;
scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]);
hscb = scb->hscb;
- /*
- * Ensure that the card doesn't do anything behind our back.
- * Also make sure that we didn't just miss an interrupt that
- * could affect this abort/reset.
- */
- pause_sequencer(p);
- while (inb(p->base + INTSTAT) & INT_PEND);
- {
- aic7xxx_isr(p->irq, (void *) NULL, (void *) NULL);
- pause_sequencer(p);
- }
- if ((cmd != scb->cmd) || ((scb->flags & SCB_ACTIVE) == 0))
+ lastphase = aic_inb(p, LASTPHASE);
+ if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
{
- result = SCSI_RESET_NOT_RUNNING;
- unpause_sequencer(p, /* unpause_always */ TRUE);
- return(result);
- }
-
-
- printk(KERN_WARNING "(scsi%d:%d:%d) Abort_reset, scb flags 0x%x, ",
- p->host_no, TC_OF_SCB(scb), scb->flags);
- bus_state = inb(p->base + LASTPHASE);
-
- switch (bus_state)
- {
- case P_DATAOUT:
- printk("Data-Out phase, ");
- break;
- case P_DATAIN:
- printk("Data-In phase, ");
- break;
- case P_COMMAND:
- printk("Command phase, ");
- break;
- case P_MESGOUT:
- printk("Message-Out phase, ");
- break;
- case P_STATUS:
- printk("Status phase, ");
- break;
- case P_MESGIN:
- printk("Message-In phase, ");
- break;
- default:
+ printk(INFO_LEAD "Bus Device reset, scb flags 0x%x, ",
+ p->host_no, CTL_OF_SCB(scb), scb->flags);
+ switch (lastphase)
+ {
+ case P_DATAOUT:
+ printk("Data-Out phase\n");
+ break;
+ case P_DATAIN:
+ printk("Data-In phase\n");
+ break;
+ case P_COMMAND:
+ printk("Command phase\n");
+ break;
+ case P_MESGOUT:
+ printk("Message-Out phase\n");
+ break;
+ case P_STATUS:
+ printk("Status phase\n");
+ break;
+ case P_MESGIN:
+ printk("Message-In phase\n");
+ break;
+ default:
/*
* We're not in a valid phase, so assume we're idle.
*/
- printk("while idle, LASTPHASE = 0x%x, ", bus_state);
- break;
+ printk("while idle, LASTPHASE = 0x%x\n", lastphase);
+ break;
+ }
+ printk(INFO_LEAD "SCSISIGI 0x%x, SEQADDR 0x%x, SSTAT0 0x%x, SSTAT1 "
+ "0x%x\n", p->host_no, CTL_OF_SCB(scb),
+ aic_inb(p, SCSISIGI),
+ aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8),
+ aic_inb(p, SSTAT0), aic_inb(p, SSTAT1));
}
- printk("SCSISIGI 0x%x, SEQADDR 0x%x, SSTAT0 0x%x, SSTAT1 0x%x\n",
- inb(p->base + SCSISIGI),
- inb(p->base + SEQADDR0) | (inb(p->base + SEQADDR1) << 8),
- inb(p->base + SSTAT0), inb(p->base + SSTAT1));
- channel = hscb->target_channel_lun & SELBUSB ? 'B': 'A';
- /*
- * Determine our course of action.
- */
- if (scb->flags & SCB_ABORT)
- {
- /*
- * Been down this road before; do a full bus reset.
- */
- scb->flags |= SCB_RECOVERY_SCB;
- unpause_sequencer(p, /* unpause_always */ TRUE);
- result = -1;
- }
-#if 0
- else if (hscb->control & TAG_ENB)
- {
- /*
- * We could be starving this command; try sending and ordered tag
- * command to the target we come from.
- */
- scb->flags |= SCB_SENTORDEREDTAG | SCB_RECOVERY_SCB;
- p->orderedtag = p->orderedtag | 0xFF;
- result = SCSI_RESET_PENDING;
- unpause_sequencer(p, /* unpause_always */ TRUE);
- printk(KERN_WARNING "scsi%d: Abort_reset, odered tag queued.\n",
- p->host_no);
- }
-#endif
- else
- {
- unsigned char active_scb_index, saved_scbptr;
- struct aic7xxx_scb *active_scb;
+ channel = cmd->channel;
/*
- * Send an Abort Message:
+ * Send a Device Reset Message:
* The target that is holding up the bus may not be the same as
* the one that triggered this timeout (different commands have
* different timeout lengths). Our strategy here is to queue an
@@ -6686,154 +8168,155 @@ aic7xxx_bus_device_reset(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
* fails, we'll get another timeout a few seconds later which will
* attempt a bus reset.
*/
- saved_scbptr = inb(p->base + SCBPTR);
- active_scb_index = inb(p->base + SCB_TAG);
- active_scb = p->scb_data->scb_array[active_scb_index];
+ saved_scbptr = aic_inb(p, SCBPTR);
+ disconnected = FALSE;
- if (bus_state != P_BUSFREE)
+ if (lastphase != P_BUSFREE)
+ {
+ if (aic_inb(p, SCB_TAG) >= p->scb_data->numscbs)
{
- if (active_scb_index >= p->scb_data->numscbs)
+ printk(WARN_LEAD "Invalid SCB ID %d is active, "
+ "SCB flags = 0x%x.\n", p->host_no,
+ CTL_OF_CMD(cmd), scb->hscb->tag, scb->flags);
+ return(SCSI_RESET_ERROR);
+ }
+ if (scb->hscb->tag == aic_inb(p, SCB_TAG))
+ {
+ if ( (lastphase != P_MESGOUT) && (lastphase != P_MESGIN) )
{
- /*
- * Perform a bus reset.
- *
- * XXX - We want to queue an abort for the timedout SCB
- * instead.
- */
- result = -1;
- printk(KERN_WARNING "scsi%d: Invalid SCB ID %d is active, "
- "SCB flags = 0x%x.\n", p->host_no, scb->hscb->tag, scb->flags);
+ /* Send the abort message to the active SCB. */
+ aic_outb(p, MSG_BUS_DEV_RESET, MSG_OUT);
+ aic_outb(p, lastphase | ATNO, SCSISIGO);
+ if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+ printk(INFO_LEAD "Device reset message in "
+ "message buffer\n", p->host_no, CTL_OF_SCB(scb));
+ scb->flags |= SCB_RESET | SCB_DEVICE_RESET;
+ aic7xxx_error(scb->cmd) = DID_RESET;
+ p->dev_flags[TARGET_INDEX(scb->cmd)] &=
+ ~DEVICE_SUCCESS;
+ p->dev_flags[TARGET_INDEX(scb->cmd)] |=
+ BUS_DEVICE_RESET_PENDING;
+ return(SCSI_RESET_PENDING);
}
else
{
- /* Send the abort message to the active SCB. */
- outb(1, p->base + MSG_LEN);
- if (active_scb->hscb->control & TAG_ENB)
- {
- outb(MSG_ABORT_TAG, p->base + MSG_OUT);
- }
- else
- {
- outb(MSG_ABORT, p->base + MSG_OUT);
- }
- outb(bus_state | ATNO, p->base + SCSISIGO);
- printk(KERN_WARNING "scsi%d: abort message in message buffer\n",
- p->host_no);
- active_scb->flags |= SCB_ABORT | SCB_RECOVERY_SCB;
- if (active_scb != scb)
- {
- /*
- * XXX - We would like to increment the timeout on scb, but
- * access to that routine is denied because it is hidden
- * in scsi.c. If we were able to do this, it would give
- * scb a new lease on life.
- */
- result = SCSI_RESET_PENDING;
- aic7xxx_error(active_scb->cmd) = DID_RESET;
- }
- else
- {
- aic7xxx_error(scb->cmd) = DID_RESET;
- result = SCSI_RESET_PENDING;
- }
- unpause_sequencer(p, /* unpause_always */ TRUE);
+ /* We want to send out the message, but it could screw an already */
+ /* in place and being used message. Instead, we return an error */
+ /* to try and start the bus reset phase since this command is */
+ /* probably hung (aborts failed, and now reset is failing). We */
+ /* also make sure to set BUS_DEVICE_RESET_PENDING so we won't try */
+ /* any more on this device, but instead will escalate to a bus or */
+ /* host reset (additionally, we won't try to abort any more). */
+ printk(WARN_LEAD "Device reset, Message buffer "
+ "in use\n", p->host_no, CTL_OF_SCB(scb));
+ scb->flags |= SCB_RESET | SCB_DEVICE_RESET;
+ aic7xxx_error(scb->cmd) = DID_RESET;
+ p->dev_flags[TARGET_INDEX(scb->cmd)] &=
+ ~DEVICE_SUCCESS;
+ p->dev_flags[TARGET_INDEX(scb->cmd)] |=
+ BUS_DEVICE_RESET_PENDING;
+ return(SCSI_RESET_ERROR);
}
}
- else
+ } /* if (last_phase != P_BUSFREE).....indicates we are idle and can work */
+ hscb_index = aic7xxx_find_scb(p, scb);
+ if (hscb_index == SCB_LIST_NULL)
+ {
+ disconnected = (aic7xxx_scb_on_qoutfifo(p, scb)) ? FALSE : TRUE;
+ }
+ else
+ {
+ aic_outb(p, hscb_index, SCBPTR);
+ if (aic_inb(p, SCB_CONTROL) & DISCONNECTED)
{
- unsigned char hscb_index, linked_next;
- int disconnected;
-
- disconnected = FALSE;
- hscb_index = aic7xxx_find_scb(p, scb);
- if (hscb_index == SCB_LIST_NULL)
- {
- disconnected = TRUE;
- linked_next = (scb->hscb->data_count >> 24) & 0xFF;
- }
- else
- {
- outb(hscb_index, p->base + SCBPTR);
- if (inb(p->base + SCB_CONTROL) & DISCONNECTED)
- {
- disconnected = TRUE;
- }
- linked_next = inb(p->base + SCB_LINKED_NEXT);
- }
- if (disconnected)
- {
+ disconnected = TRUE;
+ }
+ }
+ if (disconnected)
+ {
/*
- * Simply set the ABORT_SCB control bit and preserve the
- * linked next pointer.
+ * Simply set the MK_MESSAGE flag and the SEQINT handler will do
+ * the rest on a reconnect.
*/
- scb->hscb->control |= ABORT_SCB | MK_MESSAGE;
- scb->hscb->data_count &= ~0xFF000000;
- scb->hscb->data_count |= linked_next << 24;
- if ((p->flags & PAGE_ENABLED) == 0)
- {
- scb->hscb->control &= ~DISCONNECTED;
- }
- scb->flags |= SCB_QUEUED_ABORT | SCB_ABORT | SCB_RECOVERY_SCB;
- if (hscb_index != SCB_LIST_NULL)
- {
- unsigned char scb_control;
+ scb->hscb->control |= MK_MESSAGE;
+ scb->flags |= SCB_RESET | SCB_DEVICE_RESET;
+ p->dev_flags[TARGET_INDEX(scb->cmd)] &= ~DEVICE_SUCCESS;
+ p->dev_flags[TARGET_INDEX(scb->cmd)] |=
+ BUS_DEVICE_RESET_PENDING;
+ if (hscb_index != SCB_LIST_NULL)
+ {
+ unsigned char scb_control;
- scb_control = inb(p->base + SCB_CONTROL);
- outb(scb_control | MK_MESSAGE| ABORT_SCB, p->base + SCB_CONTROL);
- }
+ aic_outb(p, hscb_index, SCBPTR);
+ scb_control = aic_inb(p, SCB_CONTROL);
+ aic_outb(p, scb_control | MK_MESSAGE, SCB_CONTROL);
+ }
/*
* Actually requeue this SCB in case we can select the
* device before it reconnects. If the transaction we
- * want to abort is not tagged, unbusy it first so that
- * we don't get held back from sending the command.
+ * want to abort is not tagged, then this will be the only
+ * outstanding command and we can simply shove it on the
+ * qoutfifo and be done. If it is tagged, then it goes right
+ * in with all the others, no problem :) We need to add it
+ * to the qinfifo and let the sequencer know it is there.
+ * Now, the only problem left to deal with is, *IF* this
+ * command completes, in spite of the MK_MESSAGE bit in the
+ * control byte, then we need to pick that up in the interrupt
+ * routine and clean things up. This *shouldn't* ever happen.
*/
- if ((scb->hscb->control & TAG_ENB) == 0)
- {
- unsigned char target;
- int lun;
-
- target = scb->cmd->target;
- lun = scb->cmd->lun;
- aic7xxx_search_qinfifo(p, target, channel, lun, SCB_LIST_NULL,
- 0, /* requeue */ TRUE);
- }
- printk(KERN_WARNING "(scsi%d:%d:%d) Queueing an Abort SCB.\n",
- p->host_no, TC_OF_SCB(scb));
- scbq_insert_head(&p->waiting_scbs, scb);
- scb->flags |= SCB_WAITINGQ;
- outb(saved_scbptr, p->base + SCBPTR);
- if ((p->flags & IN_ISR) == 0)
- {
- /*
- * Processing the waiting queue may unpause us.
- */
- aic7xxx_run_waiting_queues(p);
- /*
- * If we are using AAP, aic7xxx_run_waiting_queues() will not
- * unpause us, so ensure we are unpaused.
- */
- unpause_sequencer(p, /*unpause_always*/ FALSE);
- }
- else
- {
- unpause_sequencer(p, /*unpause_always*/ TRUE);
- }
- result = SCSI_RESET_PENDING;
- }
- else
- {
- scb->flags |= SCB_RECOVERY_SCB;
- unpause_sequencer(p, /* unpause_always */ TRUE);
- result = -1;
- }
- }
+ if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+ printk(INFO_LEAD "Queueing device reset "
+ "command.\n", p->host_no, CTL_OF_SCB(scb));
+ p->qinfifo[p->qinfifonext++] = scb->hscb->tag;
+ aic_outb(p, p->qinfifonext, KERNEL_QINPOS);
+ scb->flags |= SCB_QUEUED_ABORT;
+ result = SCSI_RESET_PENDING;
}
+ else if (result == -1)
+ {
+ result = SCSI_RESET_ERROR;
+ }
+ aic_outb(p, saved_scbptr, SCBPTR);
return (result);
}
/*+F*************************************************************************
* Function:
+ * aic7xxx_panic_abort
+ *
+ * Description:
+ * Abort the current SCSI command(s).
+ *-F*************************************************************************/
+void
+aic7xxx_panic_abort(struct aic7xxx_host *p)
+{
+ int i;
+
+ printk("aic7xxx driver version %s\n", AIC7XXX_C_VERSION);
+ printk("Controller type:\n %s\n", board_names[p->board_name_index]);
+ for(i=0; i<MAX_TARGETS; i++)
+ {
+ if(p->dev_flags[i] & DEVICE_PRESENT)
+ {
+ printk(INFO_LEAD "dev_flags=0x%x, WDTR:%s, SDTR:%s, q_depth=%d:%d\n",
+ p->host_no, 0, i, 0, p->dev_flags[i],
+ (p->needwdtr_copy & (1 << i)) ? "Yes" : "No",
+ (p->needsdtr_copy & (1 << i)) ? "Yes" : "No",
+ p->dev_max_queue_depth[i], p->dev_mid_level_queue_depth[i]);
+ }
+ }
+ printk("SIMODE0=0x%x, SIMODE1=0x%x, SSTAT0=0x%x, SSTAT1=0x%x, INTSTAT=0x%x\n",
+ aic_inb(p, SIMODE0), aic_inb(p, SIMODE1), aic_inb(p, SSTAT0),
+ aic_inb(p, SSTAT1), aic_inb(p, INTSTAT) );
+ printk("p->flags=0x%x, p->type=0x%x, sequencer %s paused\n",
+ p->flags, p->type,
+ (aic_inb(p, HCNTRL) & PAUSE) ? "is" : "isn't" );
+ panic("Stopping to debug\n");
+}
+
+/*+F*************************************************************************
+ * Function:
* aic7xxx_abort
*
* Description:
@@ -6844,86 +8327,309 @@ aic7xxx_abort(Scsi_Cmnd *cmd)
{
struct aic7xxx_scb *scb = NULL;
struct aic7xxx_host *p;
- int base, result;
- unsigned long processor_flags;
+ int result, found=0;
+ unsigned char tmp_char, saved_hscbptr, next_hscbptr, prev_hscbptr;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+ unsigned long cpu_flags = 0;
+#endif
+ Scsi_Cmnd *cmd_next, *cmd_prev;
p = (struct aic7xxx_host *) cmd->host->hostdata;
scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]);
- base = p->base;
- save_flags(processor_flags);
- cli();
+ /*
+ * I added a new config option to the driver: "panic_on_abort" that will
+ * cause the driver to panic and the machine to stop on the first abort
+ * or reset call into the driver. At that point, it prints out a lot of
+ * usefull information for me which I can then use to try and debug the
+ * problem. Simply enable the boot time prompt in order to activate this
+ * code.
+ */
+ if (aic7xxx_panic_on_abort)
+ aic7xxx_panic_abort(p);
-#ifdef AIC7XXX_DEBUG_ABORT
- if (scb != NULL)
+ DRIVER_LOCK
+
+/*
+ * Run the isr to grab any command in the QOUTFIFO and any other misc.
+ * assundry tasks. This should also set up the bh handler if there is
+ * anything to be done, but it won't run until we are done here since
+ * we are following a straight code path without entering the scheduler
+ * code.
+ */
+
+ pause_sequencer(p);
+ while ( (aic_inb(p, INTSTAT) & INT_PEND) && !(p->flags & AHC_IN_ISR))
{
- printk("(scsi%d:%d:%d) Aborting scb %d, flags 0x%x\n",
- p->host_no, TC_OF_SCB(scb), scb->hscb->tag, scb->flags);
+ aic7xxx_isr(p->irq, p, (void *)NULL);
+ pause_sequencer(p);
}
- else
+
+ if ((scb == NULL) || (cmd->serial_number != cmd->serial_number_at_timeout))
+ /* Totally bogus cmd since it points beyond our */
+ { /* valid SCB range or doesn't even match it's own*/
+ /* timeout serial number. */
+ if (aic7xxx_verbose & VERBOSE_ABORT_MID)
+ printk(INFO_LEAD "Abort called with bogus Scsi_Cmnd "
+ "pointer.\n", p->host_no, CTL_OF_CMD(cmd));
+ unpause_sequencer(p, FALSE);
+ DRIVER_UNLOCK
+ return(SCSI_ABORT_NOT_RUNNING);
+ }
+ if (scb->cmd != cmd) /* Hmmm...either this SCB is currently free with a */
+ { /* NULL cmd pointer (NULLed out when freed) or it */
+ /* has already been recycled for another command */
+ /* Either way, this SCB has nothing to do with this*/
+ /* command and we need to deal with cmd without */
+ /* touching the SCB. */
+ /* The theory here is to return a value that will */
+ /* make the queued for complete command actually */
+ /* finish successfully, or to indicate that we */
+ /* don't have this cmd any more and the mid level */
+ /* code needs to find it. */
+ cmd_next = p->completeq.head;
+ cmd_prev = NULL;
+ while (cmd_next != NULL)
+ {
+ if (cmd_next == cmd)
+ {
+ if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
+ printk(INFO_LEAD "Abort called for command "
+ "on completeq, completing.\n", p->host_no, CTL_OF_CMD(cmd));
+ if ( cmd_prev == NULL )
+ p->completeq.head = (Scsi_Cmnd *)cmd_next->host_scribble;
+ else
+ cmd_prev->host_scribble = cmd_next->host_scribble;
+ cmd_next->done(cmd_next);
+ unpause_sequencer(p, FALSE);
+ DRIVER_UNLOCK
+ return(SCSI_ABORT_NOT_RUNNING); /* It's already back as a successful
+ * completion */
+ }
+ cmd_prev = cmd_next;
+ cmd_next = (Scsi_Cmnd *)cmd_next->host_scribble;
+ }
+ if (aic7xxx_verbose & VERBOSE_ABORT_MID)
+ printk(INFO_LEAD "Abort called for already completed"
+ " command.\n", p->host_no, CTL_OF_CMD(cmd));
+ unpause_sequencer(p, FALSE);
+ DRIVER_UNLOCK
+ return(SCSI_ABORT_NOT_RUNNING);
+ }
+
+/* At this point we know the following:
+ * the SCB pointer is valid
+ * the command pointer passed in to us and the scb->cmd pointer match
+ * this then means that the command we need to abort is the same as the
+ * command held by the scb pointer and is a valid abort request.
+ * Now, we just have to figure out what to do from here. Current plan is:
+ * if we have already been here on this command, escalate to a reset
+ * if scb is on waiting list or QINFIFO, send it back as aborted
+ * if scb is on WAITING_SCB list in sequencer, free scb and send back
+ * if scb is disconnected and not completed, abort with abort message
+ * if scb is currently running, then it may be causing the bus to hang
+ * so we want a return value that indicates a reset would be appropriate
+ * if the command does not finish shortly
+ * if scb is already complete but not on completeq, we're screwed because
+ * this can't happen (except if the command is in the QOUTFIFO, in which
+ * case we would like it to complete successfully instead of having to
+ * to be re-done)
+ * All other scenarios already dealt with by previous code.
+ */
+
+ if ( scb->flags & (SCB_ABORT | SCB_RESET | SCB_QUEUED_ABORT) )
{
- printk("aic7xxx: Abort called with no SCB for cmd.\n");
+ if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
+ printk(INFO_LEAD "SCB aborted once already, "
+ "escalating.\n", p->host_no, CTL_OF_SCB(scb));
+ unpause_sequencer(p, FALSE);
+ DRIVER_UNLOCK
+ return(SCSI_ABORT_SNOOZE);
}
-#endif
+ if ( (p->flags & (AHC_RESET_PENDING | AHC_ABORT_PENDING)) ||
+ (p->dev_flags[TARGET_INDEX(scb->cmd)] &
+ BUS_DEVICE_RESET_PENDING) )
+ {
+ if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
+ printk(INFO_LEAD "Reset/Abort pending for this "
+ "device, not wasting our time.\n", p->host_no, CTL_OF_SCB(scb));
+ unpause_sequencer(p, FALSE);
+ DRIVER_UNLOCK
+ return(SCSI_ABORT_PENDING);
+ }
+
+ found = 0;
+ p->flags |= AHC_IN_ABORT;
+ if (aic7xxx_verbose & VERBOSE_ABORT)
+ printk(INFO_LEAD "Aborting scb %d, flags 0x%x\n",
+ p->host_no, CTL_OF_SCB(scb), scb->hscb->tag, scb->flags);
- if (p->flags & IN_TIMEOUT)
+/*
+ * First, let's check to see if the currently running command is our target
+ * since if it is, the return is fairly easy and quick since we don't want
+ * to touch the command in case it might complete, but we do want a timeout
+ * in case it's actually hung, so we really do nothing, but tell the mid
+ * level code to reset the timeout.
+ */
+
+ if ( scb->hscb->tag == aic_inb(p, SCB_TAG) )
{
- /*
- * We've already started a recovery operation.
- */
- if ((scb->flags & SCB_RECOVERY_SCB) == 0)
- {
- restore_flags(processor_flags);
- return (SCSI_ABORT_PENDING);
- }
- else
+ /*
+ * Check to see if the sequencer is just sitting on this command, or
+ * if it's actively being run.
+ */
+ result = aic_inb(p, LASTPHASE);
+ switch (result)
{
- /*
- * This is the second time we've tried to abort the recovery
- * SCB. We want the mid-level SCSI code to call the reset
- * function to reset the SCSI bus.
- */
- restore_flags(processor_flags);
- return (SCSI_ABORT_NOT_RUNNING);
+ case P_DATAOUT: /* For any of these cases, we can assume we are */
+ case P_DATAIN: /* an active command and act according. For */
+ case P_COMMAND: /* anything else we are going to fall on through*/
+ case P_STATUS: /* The SCSI_ABORT_SNOOZE will give us two abort */
+ case P_MESGOUT: /* chances to finish and then escalate to a */
+ case P_MESGIN: /* reset call */
+ if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
+ printk(INFO_LEAD "SCB is currently active. "
+ "Waiting on completion.\n", p->host_no, CTL_OF_SCB(scb));
+ unpause_sequencer(p, FALSE);
+ p->flags &= ~AHC_IN_ABORT;
+ scb->flags |= SCB_RECOVERY_SCB; /* Note the fact that we've been */
+ p->flags |= AHC_ABORT_PENDING; /* here so we will know not to */
+ DRIVER_UNLOCK /* muck with other SCBs if this */
+ return(SCSI_ABORT_PENDING); /* one doesn't complete and clear */
+ break; /* out. */
+ default:
+ break;
}
}
- if (cmd->serial_number != cmd->serial_number_at_timeout)
+
+ if ((found == 0) && (scb->flags & SCB_WAITINGQ))
{
- result = SCSI_ABORT_NOT_RUNNING;
+ int tindex = TARGET_INDEX(cmd);
+
+ if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
+ printk(INFO_LEAD "SCB found on waiting list and "
+ "aborted.\n", p->host_no, CTL_OF_SCB(scb));
+ scbq_remove(&p->waiting_scbs, scb);
+ scbq_remove(&p->delayed_scbs[tindex], scb);
+ p->dev_active_cmds[tindex]++;
+ p->activescbs++;
+ scb->flags &= ~(SCB_WAITINGQ | SCB_ACTIVE);
+ scb->flags |= SCB_ABORT | SCB_QUEUED_FOR_DONE;
+ found = 1;
}
- else if (scb == NULL)
+
+/*
+ * We just checked the waiting_q, now for the QINFIFO
+ */
+ if ( found == 0 )
{
- result = SCSI_ABORT_NOT_RUNNING;
+ if ( ((found = aic7xxx_search_qinfifo(p, cmd->target,
+ cmd->channel,
+ cmd->lun, scb->hscb->tag, SCB_ABORT | SCB_QUEUED_FOR_DONE,
+ FALSE, NULL)) != 0) &&
+ (aic7xxx_verbose & VERBOSE_ABORT_PROCESS))
+ printk(INFO_LEAD "SCB found in QINFIFO and "
+ "aborted.\n", p->host_no, CTL_OF_SCB(scb));
}
- else if ((scb->cmd != cmd) || (!(scb->flags & SCB_ACTIVE)))
+
+/*
+ * QINFIFO, waitingq, completeq done. Next, check WAITING_SCB list in card
+ */
+
+ if ( found == 0 )
{
- result = SCSI_ABORT_NOT_RUNNING;
+ unsigned char scb_next_ptr;
+ prev_hscbptr = SCB_LIST_NULL;
+ saved_hscbptr = aic_inb(p, SCBPTR);
+ next_hscbptr = aic_inb(p, WAITING_SCBH);
+ while ( next_hscbptr != SCB_LIST_NULL )
+ {
+ aic_outb(p, next_hscbptr, SCBPTR );
+ if ( scb->hscb->tag == aic_inb(p, SCB_TAG) )
+ {
+ found = 1;
+ if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
+ printk(INFO_LEAD "SCB found on hardware waiting"
+ " list and aborted.\n", p->host_no, CTL_OF_SCB(scb));
+ if ( prev_hscbptr == SCB_LIST_NULL )
+ {
+ aic_outb(p, aic_inb(p, SCB_NEXT), WAITING_SCBH);
+ aic_outb(p, 0, SCSISEQ); /* stop the selection since we just
+ * grabbed the scb out from under the
+ * card */
+ }
+ else
+ {
+ scb_next_ptr = aic_inb(p, SCB_NEXT);
+ aic_outb(p, prev_hscbptr, SCBPTR);
+ aic_outb(p, scb_next_ptr, SCB_NEXT);
+ aic_outb(p, next_hscbptr, SCBPTR);
+ }
+ aic_outb(p, SCB_LIST_NULL, SCB_TAG);
+ aic_outb(p, 0, SCB_CONTROL);
+ aic7xxx_add_curscb_to_free_list(p);
+ scb->flags = SCB_ABORT | SCB_QUEUED_FOR_DONE;
+ break;
+ }
+ prev_hscbptr = next_hscbptr;
+ next_hscbptr = aic_inb(p, SCB_NEXT);
+ }
+ aic_outb(p, saved_hscbptr, SCBPTR );
}
- else
+
+/*
+ * Hmmm...completeq, QOUTFIFO, QINFIFO, WAITING_SCBH, waitingq all checked.
+ * OK...the sequencer's paused, interrupts are off, and we haven't found the
+ * command anyplace where it could be easily aborted. Time for the hard
+ * work. We also know the command is valid. This essentially means the
+ * command is disconnected, or connected but not into any phases yet, which
+ * we know due to the tests we ran earlier on the current active scb phase.
+ * At this point we can queue the abort tag and go on with life.
+ */
+
+ if ( found == 0 )
{
- /*
- * XXX - Check use of IN_TIMEOUT to see if we're Doing the
- * Right Thing with it.
- */
- p->flags |= IN_TIMEOUT;
- result = aic7xxx_bus_device_reset(p, scb->cmd);
- switch (result)
+ p->flags |= AHC_ABORT_PENDING;
+ scb->flags |= SCB_QUEUED_ABORT | SCB_ABORT | SCB_RECOVERY_SCB;
+ scb->hscb->control |= MK_MESSAGE;
+ result=aic7xxx_find_scb(p, scb);
+ if ( result != SCB_LIST_NULL )
{
- case SCSI_RESET_NOT_RUNNING:
- p->flags &= ~IN_TIMEOUT;
- result = SCSI_ABORT_NOT_RUNNING;
- break;
- case SCSI_RESET_PENDING:
- result = SCSI_ABORT_PENDING;
- break;
- default:
- p->flags &= ~IN_TIMEOUT;
- result = SCSI_ABORT_SNOOZE;
- break;
- }
+ saved_hscbptr = aic_inb(p, SCBPTR);
+ aic_outb(p, result, SCBPTR);
+ tmp_char = aic_inb(p, SCB_CONTROL);
+ aic_outb(p, tmp_char | MK_MESSAGE, SCB_CONTROL);
+ aic_outb(p, saved_hscbptr, SCBPTR);
+ }
+ if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
+ printk(INFO_LEAD "SCB disconnected. Queueing Abort"
+ " SCB.\n", p->host_no, CTL_OF_SCB(scb));
+ p->qinfifo[p->qinfifonext++] = scb->hscb->tag;
+ aic_outb(p, p->qinfifonext, KERNEL_QINPOS);
}
- restore_flags(processor_flags);
- return (result);
+ if (found)
+ {
+ aic7xxx_run_done_queue(p, TRUE);
+ aic7xxx_run_waiting_queues(p);
+ }
+ p->flags &= ~AHC_IN_ABORT;
+ unpause_sequencer(p, FALSE);
+ DRIVER_UNLOCK
+
+/*
+ * On the return value. If we found the command and aborted it, then we know
+ * it's already sent back and there is no reason for a further timeout, so
+ * we use SCSI_ABORT_SUCCESS. On the queued abort side, we aren't so certain
+ * there hasn't been a bus hang or something that might keep the abort from
+ * from completing. Therefore, we use SCSI_ABORT_PENDING. The first time this
+ * is passed back, the timeout on the command gets extended, the second time
+ * we pass this back, the mid level SCSI code calls our reset function, which
+ * would shake loose a hung bus.
+ */
+ if ( found != 0 )
+ return(SCSI_ABORT_SUCCESS);
+ else
+ return(SCSI_ABORT_PENDING);
}
@@ -6942,189 +8648,259 @@ aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags)
{
struct aic7xxx_scb *scb = NULL;
struct aic7xxx_host *p;
- int base, found, tindex, min_target, max_target;
+ int tindex;
int result = -1;
- char channel = 'A';
- unsigned long processor_flags;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+ unsigned long cpu_flags = 0;
+#endif
+#define DEVICE_RESET 0x01
+#define BUS_RESET 0x02
+#define HOST_RESET 0x04
+#define FAIL 0x08
+#define RESET_DELAY 0x10
+ int action;
+ Scsi_Cmnd *cmd_prev, *cmd_next;
- p = (struct aic7xxx_host *) cmd->host->hostdata;
- scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]);
- base = p->base;
- channel = cmd->channel ? 'B': 'A';
- tindex = TARGET_INDEX(cmd);
-#if 0 /* AIC7XXX_DEBUG_ABORT */
- if (scb != NULL)
- {
- printk("(scsi%d:%d:%d) Reset called, scb %d, flags 0x%x\n",
- p->host_no, TC_OF_SCB(scb), scb->hscb->tag, scb->flags);
- }
- else
+ if ( cmd == NULL )
{
- printk("aic7xxx: Reset called with no SCB for cmd.\n");
+ printk(KERN_WARNING "(scsi?:?:?:?) Reset called with NULL Scsi_Cmnd "
+ "pointer, failing.\n");
+ return(SCSI_RESET_SNOOZE);
}
-#endif
- /*
- * This routine is called by scsi.c, in which case the interrupts
- * very well may be on when we are called. As such, we need to save
- * the flags to be sure, then turn interrupts off, and then call our
- * various method funtions which all assume interrupts are off.
+ p = (struct aic7xxx_host *) cmd->host->hostdata;
+ scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]);
+ tindex = TARGET_INDEX(cmd);
+
+ /*
+ * I added a new config option to the driver: "panic_on_abort" that will
+ * cause the driver to panic and the machine to stop on the first abort
+ * or reset call into the driver. At that point, it prints out a lot of
+ * usefull information for me which I can then use to try and debug the
+ * problem. Simply enable the boot time prompt in order to activate this
+ * code.
*/
- save_flags(processor_flags);
- cli();
+ if (aic7xxx_panic_on_abort)
+ aic7xxx_panic_abort(p);
- if (scb->cmd != cmd)
- scb = NULL;
+ DRIVER_LOCK
- if (p->flags & IN_TIMEOUT)
+ pause_sequencer(p);
+ while ( (aic_inb(p, INTSTAT) & INT_PEND) && !(p->flags & AHC_IN_ISR))
{
- /*
- * We've already started a recovery operation.
- */
- if ((scb->flags & SCB_RECOVERY_SCB) == 0)
+ aic7xxx_isr(p->irq, p, (void *)NULL );
+ pause_sequencer(p);
+ }
+
+ if (scb == NULL)
+ {
+ if (aic7xxx_verbose & VERBOSE_RESET_MID)
+ printk(INFO_LEAD "Reset called with bogus Scsi_Cmnd"
+ "->SCB mapping, improvising.\n", p->host_no, CTL_OF_CMD(cmd));
+ if ( flags & SCSI_RESET_SUGGEST_HOST_RESET )
{
- restore_flags(processor_flags);
- return (SCSI_RESET_PENDING);
+ action = HOST_RESET;
+ }
+ else
+ {
+ action = BUS_RESET;
}
}
- else
+ else if (scb->cmd != cmd)
{
- if (!(flags & (SCSI_RESET_SUGGEST_HOST_RESET | SCSI_RESET_SUGGEST_BUS_RESET))
- && (scb != NULL))
+ if (aic7xxx_verbose & VERBOSE_RESET_MID)
+ printk(INFO_LEAD "Reset called with recycled SCB "
+ "for cmd.\n", p->host_no, CTL_OF_CMD(cmd));
+ cmd_prev = NULL;
+ cmd_next = p->completeq.head;
+ while ( cmd_next != NULL )
{
- /*
- * Attempt a bus device reset if commands have completed successfully
- * since the last bus device reset, or it has been less than 100ms
- * since the last reset.
- */
- if ((p->flags & DEVICE_SUCCESS) ||
- ((jiffies - p->device_status[tindex].last_reset) < HZ/10))
+ if (cmd_next == cmd)
{
- if (cmd->serial_number != cmd->serial_number_at_timeout)
- {
- result = SCSI_RESET_NOT_RUNNING;
- }
- else if (scb == NULL)
- {
- result = SCSI_RESET_NOT_RUNNING;
- }
- else if (flags & SCSI_RESET_ASYNCHRONOUS)
- {
- if (scb->flags & SCB_ABORTED)
- {
- result = SCSI_RESET_PENDING;
- }
- else if (!(scb->flags & SCB_ACTIVE))
- {
- result = SCSI_RESET_NOT_RUNNING;
- }
- }
-
- if (result == -1)
- {
- if ((flags & SCSI_RESET_SYNCHRONOUS) &&
- (p->device_status[tindex].flags & BUS_DEVICE_RESET_PENDING))
- {
- scb->flags |= SCB_ABORTED;
- result = SCSI_RESET_PENDING;
- }
- else
- {
- p->flags |= IN_TIMEOUT;
- result = aic7xxx_bus_device_reset(p, cmd);
- if (result == 0)
- {
- p->flags &= ~IN_TIMEOUT;
- result = SCSI_RESET_PENDING;
- }
- }
- }
+ if (aic7xxx_verbose & VERBOSE_RESET_RETURN)
+ printk(INFO_LEAD "Reset, found cmd on completeq"
+ ", completing.\n", p->host_no, CTL_OF_CMD(cmd));
+ unpause_sequencer(p, FALSE);
+ DRIVER_UNLOCK
+ return(SCSI_RESET_NOT_RUNNING);
}
+ cmd_prev = cmd_next;
+ cmd_next = (Scsi_Cmnd *)cmd_next->host_scribble;
+ }
+ if ( !(flags & SCSI_RESET_SYNCHRONOUS) )
+ {
+ if (aic7xxx_verbose & VERBOSE_RESET_RETURN)
+ printk(INFO_LEAD "Reset, cmd not found,"
+ " failing.\n", p->host_no, CTL_OF_CMD(cmd));
+ unpause_sequencer(p, FALSE);
+ DRIVER_UNLOCK
+ return(SCSI_RESET_NOT_RUNNING);
+ }
+ else
+ {
+ if (aic7xxx_verbose & VERBOSE_RESET_MID)
+ printk(INFO_LEAD "Reset called, no scb, "
+ "flags 0x%x\n", p->host_no, CTL_OF_CMD(cmd), flags);
+ scb = NULL;
+ action = HOST_RESET;
}
}
- if (result == -1)
+ else
{
- /*
- * The bus device reset failed; try resetting the channel.
- */
- if (!(flags & (SCSI_RESET_SUGGEST_BUS_RESET | SCSI_RESET_SUGGEST_HOST_RESET))
- && (flags & SCSI_RESET_ASYNCHRONOUS))
+ if (aic7xxx_verbose & VERBOSE_RESET_MID)
+ printk(INFO_LEAD "Reset called, scb %d, flags "
+ "0x%x\n", p->host_no, CTL_OF_SCB(scb), scb->hscb->tag, scb->flags);
+ if ( aic7xxx_scb_on_qoutfifo(p, scb) )
{
- if (scb == NULL)
- {
- result = SCSI_RESET_NOT_RUNNING;
- }
- else if (!(scb->flags & SCB_ACTIVE))
- {
- result = SCSI_RESET_NOT_RUNNING;
- }
- else if ((scb->flags & SCB_ABORTED) &&
- (!(p->device_status[tindex].flags & BUS_DEVICE_RESET_PENDING)))
- {
- result = SCSI_RESET_PENDING;
- }
+ if(aic7xxx_verbose & VERBOSE_RESET_RETURN)
+ printk(INFO_LEAD "SCB on qoutfifo, returning.\n", p->host_no,
+ CTL_OF_SCB(scb));
+ unpause_sequencer(p, FALSE);
+ DRIVER_UNLOCK
+ return(SCSI_RESET_NOT_RUNNING);
}
-
- if (result == -1)
+ if ( flags & SCSI_RESET_SUGGEST_HOST_RESET )
{
- /*
- * The reset channel function assumes that the sequencer is paused.
- */
- pause_sequencer(p);
- found = aic7xxx_reset_channel(p, channel, TRUE);
- p->flags = p->flags & ~IN_TIMEOUT;
-
- /*
- * If this is a synchronous reset and there is no SCB for this
- * command, perform completion processing.
- *
- */
- if ((flags & SCSI_RESET_SYNCHRONOUS) && (scb == NULL))
+ action = HOST_RESET;
+ }
+ else if ( flags & SCSI_RESET_SUGGEST_BUS_RESET )
+ {
+ action = BUS_RESET;
+ }
+ else
+ {
+ action = DEVICE_RESET;
+ }
+ }
+ if ( (action & DEVICE_RESET) &&
+ (p->dev_flags[tindex] & BUS_DEVICE_RESET_PENDING) )
+ {
+ if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+ printk(INFO_LEAD "Bus device reset already sent to "
+ "device, escalating.\n", p->host_no, CTL_OF_CMD(cmd));
+ action = BUS_RESET;
+ }
+ if ( (action & DEVICE_RESET) &&
+ (scb->flags & SCB_QUEUED_ABORT) )
+ {
+ if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+ {
+ printk(INFO_LEAD "Have already attempted to reach "
+ "device with queued\n", p->host_no, CTL_OF_CMD(cmd));
+ printk(INFO_LEAD "message, will escalate to bus "
+ "reset.\n", p->host_no, CTL_OF_CMD(cmd));
+ }
+ action = BUS_RESET;
+ }
+ if ( (action & DEVICE_RESET) &&
+ (p->flags & (AHC_RESET_PENDING | AHC_ABORT_PENDING)) )
+ {
+ if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+ printk(INFO_LEAD "Bus device reset stupid when "
+ "other action has failed.\n", p->host_no, CTL_OF_CMD(cmd));
+ action = BUS_RESET;
+ }
+ if ( (action & BUS_RESET) && !(p->type & AHC_TWIN) )
+ {
+ action = HOST_RESET;
+ }
+ if ( ((jiffies - p->dev_last_reset[tindex]) < (HZ * 3)) &&
+ !(action & (HOST_RESET | BUS_RESET)))
+ {
+ if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+ {
+ printk(INFO_LEAD "Reset called too soon after last "
+ "reset without requesting\n", p->host_no, CTL_OF_CMD(cmd));
+ printk(INFO_LEAD "bus or host reset, escalating.\n", p->host_no,
+ CTL_OF_CMD(cmd));
+ }
+ action = BUS_RESET;
+ }
+ if ( ((jiffies - p->last_reset) < (HZ * 3)) &&
+ (action & (HOST_RESET | BUS_RESET)) )
+ {
+ if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+ printk(INFO_LEAD "Reset called too soon after "
+ "last bus reset, delaying.\n", p->host_no, CTL_OF_CMD(cmd));
+ action = RESET_DELAY;
+ }
+ if ( (action & (BUS_RESET | HOST_RESET)) && (p->flags & AHC_IN_RESET)
+ && ((jiffies - p->reset_start) > (2 * HZ * 3)) )
+ {
+ printk(KERN_ERR "(scsi%d:%d:%d:%d) Yikes!! Card must have left to go "
+ "back to Adaptec!!\n", p->host_no, CTL_OF_CMD(cmd));
+ unpause_sequencer(p, FALSE);
+ DRIVER_UNLOCK
+ return(SCSI_RESET_SNOOZE);
+ }
+/*
+ * By this point, we want to already know what we are going to do and
+ * only have the following code implement our course of action.
+ */
+ switch (action)
+ {
+ case RESET_DELAY:
+ unpause_sequencer(p, FALSE);
+ DRIVER_UNLOCK
+ return(SCSI_RESET_PENDING);
+ break;
+ case FAIL:
+ unpause_sequencer(p, FALSE);
+ DRIVER_UNLOCK
+ return(SCSI_RESET_ERROR);
+ break;
+ case DEVICE_RESET:
+ p->flags |= AHC_IN_RESET;
+ result = aic7xxx_bus_device_reset(p, cmd);
+ aic7xxx_run_done_queue(p, TRUE);
+ /* We can't rely on run_waiting_queues to unpause the sequencer for
+ * PCI based controllers since we use AAP */
+ aic7xxx_run_waiting_queues(p);
+ unpause_sequencer(p, FALSE);
+ p->flags &= ~AHC_IN_RESET;
+ DRIVER_UNLOCK
+ return(result);
+ break;
+ case BUS_RESET:
+ case HOST_RESET:
+ default:
+ p->reset_start = jiffies;
+ p->flags |= AHC_IN_RESET;
+ aic7xxx_reset_channel(p, cmd->channel, TRUE);
+ if ( (p->type & AHC_TWIN) && (action & HOST_RESET) )
{
- cmd->result = DID_RESET << 16;
- cmd->scsi_done(cmd);
+ aic7xxx_reset_channel(p, cmd->channel ^ 0x01, TRUE);
+ restart_sequencer(p);
}
-
- switch (p->bus_type)
+ if (scb == NULL)
{
- case AIC_TWIN:
- if (channel == 'B')
- {
- min_target = 8;
- max_target = 15;
- }
- else
- {
- min_target = 0;
- max_target = 7;
- }
- break;
-
- case AIC_WIDE:
- min_target = 0;
- max_target = 15;
- break;
-
- case AIC_SINGLE:
- default:
- min_target = 0;
- max_target = 7;
- break;
+ cmd->result = DID_RESET << 16;
+ cmd->done(cmd);
}
-
- for (tindex = min_target; tindex <= max_target; tindex++)
+ p->last_reset = jiffies;
+ if (action != HOST_RESET)
+ result = SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET;
+ else
{
- p->device_status[tindex].last_reset = jiffies;
+ result = SCSI_RESET_SUCCESS | SCSI_RESET_HOST_RESET;
+ aic_outb(p, aic_inb(p, SIMODE1) & ~(ENREQINIT|ENBUSFREE),
+ SIMODE1);
+ aic7xxx_clear_intstat(p);
+ p->flags &= ~AHC_HANDLING_REQINITS;
+ p->msg_type = MSG_TYPE_NONE;
+ p->msg_index = 0;
+ p->msg_len = 0;
}
-
- result = SCSI_RESET_SUCCESS | SCSI_RESET_HOST_RESET;
- p->flags &= ~IN_TIMEOUT;
- }
+ p->flags &= ~AHC_IN_RESET;
+ /* We can't rely on run_waiting_queues to unpause the sequencer for
+ * PCI based controllers since we use AAP */
+ aic7xxx_run_waiting_queues(p);
+ unpause_sequencer(p, FALSE);
+ DRIVER_UNLOCK
+ return(result);
+ break;
}
- aic7xxx_run_waiting_queues(p);
- restore_flags(processor_flags);
- return (result);
}
/*+F*************************************************************************
@@ -7151,7 +8927,7 @@ aic7xxx_biosparam(Disk *disk, kdev_t dev, int geom[])
sectors = 32;
cylinders = disk->capacity / (heads * sectors);
- if ((p->flags & EXTENDED_TRANSLATION) && (cylinders > 1024))
+ if ((p->flags & AHC_EXTEND_TRANS_A) && (cylinders > 1024))
{
heads = 255;
sectors = 63;
diff --git a/drivers/scsi/aic7xxx.h b/drivers/scsi/aic7xxx.h
index fd40554f3..8da5edba0 100644
--- a/drivers/scsi/aic7xxx.h
+++ b/drivers/scsi/aic7xxx.h
@@ -23,34 +23,88 @@
#ifndef _aic7xxx_h
#define _aic7xxx_h
-#define AIC7XXX_H_VERSION "$Revision: 3.2 $"
+#define AIC7XXX_H_VERSION "3.2.4"
+
+#ifndef LINUX_VERSION_CODE
+#include <linux/version.h>
+#endif
+
+#ifndef KERNEL_VERSION
+#define KERNEL_VERSION(x,y,z) (((x)<<16)+((y)<<8)+(z))
+#endif
+
+#if defined(__i386__)
+# define AIC7XXX_BIOSPARAM aic7xxx_biosparam
+#else
+# define AIC7XXX_BIOSPARAM NULL
+#endif
/*
* Scsi_Host_Template (see hosts.h) for AIC-7xxx - some fields
* to do with card config are filled in after the card is detected.
*/
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,65)
#define AIC7XXX { \
- proc_info: aic7xxx_proc_info, \
- detect: aic7xxx_detect, \
- info: aic7xxx_info, \
- queuecommand: aic7xxx_queue, \
- abort: aic7xxx_abort, \
- reset: aic7xxx_reset, \
- bios_param: aic7xxx_biosparam, \
- can_queue: -1, /* max simultaneous cmds */\
- this_id: -1, /* scsi id of host adapter */\
- sg_tablesize: SG_ALL, /* max scatter-gather cmds */\
- cmd_per_lun: 2, /* cmds per lun (linked cmds) */\
- use_clustering: ENABLE_CLUSTERING, \
- use_new_eh_code: 0 /* Enable new error code */ \
+ next: NULL, \
+ module: NULL, \
+ proc_dir: NULL, \
+ proc_info: aic7xxx_proc_info, \
+ name: NULL, \
+ detect: aic7xxx_detect, \
+ release: NULL, \
+ info: aic7xxx_info, \
+ command: NULL, \
+ queuecommand: aic7xxx_queue, \
+ eh_strategy_handler: NULL, \
+ eh_abort_handler: NULL, \
+ eh_device_reset_handler: NULL, \
+ eh_bus_reset_handler: NULL, \
+ eh_host_reset_handler: NULL, \
+ abort: aic7xxx_abort, \
+ reset: aic7xxx_reset, \
+ slave_attach: NULL, \
+ bios_param: AIC7XXX_BIOSPARAM, \
+ can_queue: 255, /* max simultaneous cmds */\
+ this_id: -1, /* scsi id of host adapter */\
+ sg_tablesize: 0, /* max scatter-gather cmds */\
+ cmd_per_lun: 3, /* cmds per lun (linked cmds) */\
+ present: 0, /* number of 7xxx's present */\
+ unchecked_isa_dma: 0, /* no memory DMA restrictions */\
+ use_clustering: ENABLE_CLUSTERING, \
+ use_new_eh_code: 0 \
}
+#else
+#define AIC7XXX { \
+ next: NULL, \
+ usage_count: NULL, \
+ proc_dir: NULL, \
+ proc_info: aic7xxx_proc_info, \
+ name: NULL, \
+ detect: aic7xxx_detect, \
+ release: NULL, \
+ info: aic7xxx_info, \
+ command: NULL, \
+ queuecommand: aic7xxx_queue, \
+ abort: aic7xxx_abort, \
+ reset: aic7xxx_reset, \
+ slave_attach: NULL, \
+ bios_param: AIC7XXX_BIOSPARAM, \
+ can_queue: 255, /* max simultaneous cmds */\
+ this_id: -1, /* scsi id of host adapter */\
+ sg_tablesize: 0, /* max scatter-gather cmds */\
+ cmd_per_lun: 3, /* cmds per lun (linked cmds) */\
+ present: 0, /* number of 7xxx's present */\
+ unchecked_isa_dma: 0, /* no memory DMA restrictions */\
+ use_clustering: ENABLE_CLUSTERING \
+}
+#endif
extern int aic7xxx_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *));
extern int aic7xxx_biosparam(Disk *, kdev_t, int[]);
extern int aic7xxx_detect(Scsi_Host_Template *);
extern int aic7xxx_command(Scsi_Cmnd *);
-extern int aic7xxx_abort(Scsi_Cmnd *);
extern int aic7xxx_reset(Scsi_Cmnd *, unsigned int);
+extern int aic7xxx_abort(Scsi_Cmnd *);
extern const char *aic7xxx_info(struct Scsi_Host *);
diff --git a/drivers/scsi/aic7xxx/aic7xxx.reg b/drivers/scsi/aic7xxx/aic7xxx.reg
index ac8549b34..fad02eef8 100644
--- a/drivers/scsi/aic7xxx/aic7xxx.reg
+++ b/drivers/scsi/aic7xxx/aic7xxx.reg
@@ -10,10 +10,7 @@
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions, and the following disclaimer,
* without modification, immediately at the beginning of the file.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
+ * 2. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* Where this Software is combined with software released under the terms of
@@ -35,7 +32,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: aic7xxx.reg,v 1.3 1997/12/15 12:47:28 ralf Exp $
+ * $Id: aic7xxx.reg,v 1.4 1998/05/04 10:59:18 ralf Exp $
*/
/*
@@ -393,6 +390,27 @@ register SELID {
}
/*
+ * Serial Port I/O Cabability register (p. 4-95 aic7860 Data Book)
+ * Indicates if external logic has been attached to the chip to
+ * perform the tasks of accessing a serial eeprom, testing termination
+ * strength, and performing cable detection. On the aic7860, most of
+ * these features are handled on chip, but on the aic7855 an attached
+ * aic3800 does the grunt work.
+ */
+register SPIOCAP {
+ address 0x01b
+ access_mode RW
+ bit SOFT1 0x80
+ bit SOFT0 0x40
+ bit SOFTCMDEN 0x20
+ bit HAS_BRDCTL 0x10 /* External Board control */
+ bit SEEPROM 0x08 /* External serial eeprom logic */
+ bit EEPROM 0x04 /* Writable external BIOS ROM */
+ bit ROM 0x02 /* Logic for accessing external ROM */
+ bit SSPIOCPS 0x01 /* Termination and cable detection */
+}
+
+/*
* SCSI Block Control (p. 3-32)
* Controls Bus type and channel selection. In a twin channel configuration
* addresses 0x00-0x1e are gated to the appropriate channel based on this
@@ -622,26 +640,19 @@ register INTSTAT {
mask NO_IDENT 0x20|SEQINT /* no IDENTIFY after reconnect*/
mask NO_MATCH 0x30|SEQINT /* no cmd match for reconnect */
mask EXTENDED_MSG 0x40|SEQINT /* Extended message received */
- mask NO_MATCH_BUSY 0x50|SEQINT /* Couldn't find BUSY SCB */
+ mask ABORT_REQUESTED 0x50|SEQINT /* Reconect of aborted SCB */
mask REJECT_MSG 0x60|SEQINT /* Reject message received */
mask BAD_STATUS 0x70|SEQINT /* Bad status from target */
mask RESIDUAL 0x80|SEQINT /* Residual byte count != 0 */
- mask ABORT_CMDCMPLT 0x91 /*
- * Command tagged for abort
- * completed successfully.
- */
mask AWAITING_MSG 0xa0|SEQINT /*
* Kernel requested to specify
- * a message to this target
- * (command was null), so tell
- * it that it can fill the
- * message buffer.
- */
- mask MSG_BUFFER_BUSY 0xc0|SEQINT /*
- * Sequencer wants to use the
- * message buffer, but it
- * already contains a message
+ * a message to this target
+ * (command was null), so tell
+ * it that it can fill the
+ * message buffer.
*/
+ mask TRACEPOINT 0xb0|SEQINT
+ mask TRACEPOINT2 0xc0|SEQINT
mask MSGIN_PHASEMIS 0xd0|SEQINT /*
* Target changed phase on us
* when we were expecting
@@ -665,7 +676,10 @@ register INTSTAT {
register ERROR {
address 0x092
access_mode RO
- bit PARERR 0x08
+ bit PCIERRSTAT 0x40 /* PCI only */
+ bit MPARERR 0x20 /* PCI only */
+ bit DPARERR 0x10 /* PCI only */
+ bit SQPARERR 0x08
bit ILLOPCODE 0x04
bit ILLSADDR 0x02
bit ILLHADDR 0x01
@@ -677,6 +691,7 @@ register ERROR {
register CLRINT {
address 0x092
access_mode WO
+ bit CLRPARERR 0x10 /* PCI only */
bit CLRBRKADRINT 0x08
bit CLRSCSIINT 0x04
bit CLRCMDINT 0x02
@@ -771,8 +786,6 @@ scb {
bit MK_MESSAGE 0x80
bit DISCENB 0x40
bit TAG_ENB 0x20
- bit MUST_DMAUP_SCB 0x10
- bit ABORT_SCB 0x08
bit DISCONNECTED 0x04
mask SCB_TAG_TYPE 0x03
}
@@ -801,10 +814,11 @@ scb {
size 4
}
SCB_DATACNT {
- size 3
- }
- SCB_LINKED_NEXT {
- size 1
+ /*
+ * Really only 3 bytes, but padded to make
+ * the kernel's job easier.
+ */
+ size 4
}
SCB_CMDPTR {
size 4
@@ -924,6 +938,9 @@ scratch_ram {
TARG_SCRATCH {
size 16
}
+ /*
+ * Bit vector of targets that have ULTRA enabled.
+ */
ULTRA_ENB {
size 2
}
@@ -934,14 +951,11 @@ scratch_ram {
size 2
}
/*
- * Length of pending message
+ * Single byte buffer used to designate the type or message
+ * to send to a target.
*/
- MSG_LEN {
- size 1
- }
- /* We reserve 8bytes to store outgoing messages */
MSG_OUT {
- size 8
+ size 1
}
/* Parameters for DMA Logic */
DMAPARAMS {
@@ -956,35 +970,12 @@ scratch_ram {
bit FIFOFLUSH 0x02
bit FIFORESET 0x01
}
- /*
- * Number of SCBs supported by
- * this card.
- */
- SCBCOUNT {
- size 1
- }
- /*
- * Two's complement of SCBCOUNT
- */
- COMP_SCBCOUNT {
- size 1
- }
- /*
- * Mask of bits to test against
- * when looking at the Queue Count
- * registers. Works around a bug
- * on aic7850 chips.
- */
- QCNTMASK {
- size 1
- }
SEQ_FLAGS {
size 1
- bit RESELECTED 0x80
- bit IDENTIFY_SEEN 0x40
- bit TAGGED_SCB 0x20
+ bit IDENTIFY_SEEN 0x80
+ bit SCBPTR_VALID 0x20
bit DPHASE 0x10
- bit PAGESCBS 0x04
+ bit AMTARGET 0x08
bit WIDE_BUS 0x02
bit TWIN_BUS 0x01
}
@@ -996,34 +987,15 @@ scratch_ram {
SAVED_TCL {
size 1
}
+ /* Working value of the number of SG segments left */
SG_COUNT {
size 1
}
- /* working value of SG pointer */
+ /* Working value of SG pointer */
SG_NEXT {
size 4
}
/*
- * head of list of SCBs awaiting
- * selection
- */
- WAITING_SCBH {
- size 1
- }
- SAVED_LINKPTR {
- size 1
- }
- SAVED_SCBPTR {
- size 1
- }
- /*
- * The sequencer will stick the frist byte of any rejected message here
- * so we can see what is getting thrown away.
- */
- REJBYTE {
- size 1
- }
- /*
* The last bus phase as seen by the sequencer.
*/
LASTPHASE {
@@ -1040,23 +1012,12 @@ scratch_ram {
mask P_MESGIN CDI|IOI|MSGI
mask P_BUSFREE 0x01
}
- MSGIN_EXT_LEN {
- size 1
- }
- MSGIN_EXT_OPCODE {
- size 1
- }
/*
- * location 3, stores the last
- * byte of an extended message if
- * it passes the two bytes of space
- * we allow now. This byte isn't
- * used for anything, it just makes
- * the code shorter for tossing
- * extra bytes.
+ * head of list of SCBs awaiting
+ * selection
*/
- MSGIN_EXT_BYTES {
- size 3
+ WAITING_SCBH {
+ size 1
}
/*
* head of list of SCBs that are
@@ -1073,10 +1034,40 @@ scratch_ram {
FREE_SCBH {
size 1
}
+ /*
+ * Address of the hardware scb array in the host.
+ */
HSCB_ADDR {
size 4
}
- CUR_SCBID {
+ /*
+ * Address of the 256 byte array storing the SCBID of outstanding
+ * untagged SCBs indexed by TCL.
+ */
+ SCBID_ADDR {
+ size 4
+ }
+ /*
+ * Address of the array of command descriptors used to store
+ * information about incoming selections.
+ */
+ TMODE_CMDADDR {
+ size 4
+ }
+ KERNEL_QINPOS {
+ size 1
+ }
+ QINPOS {
+ size 1
+ }
+ QOUTPOS {
+ size 1
+ }
+ /*
+ * Offset into the command descriptor array for the next
+ * available desciptor to use.
+ */
+ TMODE_CMDADDR_NEXT {
size 1
}
ARG_1 {
@@ -1084,30 +1075,13 @@ scratch_ram {
mask SEND_MSG 0x80
mask SEND_SENSE 0x40
mask SEND_REJ 0x20
+ mask MSGOUT_PHASEMIS 0x10
alias RETURN_1
}
/*
- * Running count of commands placed in
- * the QOUTFIFO. This is cleared by the
- * kernel driver every FIFODEPTH commands.
- *
- * NOTE: These scratch RAM registers are overlaying SCSICONF
- * and SCSICONF2 and are only used on cards that are
- * capable of SCB paging. Currently, only the PCI
- * controllers can do this, which is good because the
- * AIC-7770 based controllers use the SCSICONF register
- * to control termination. In other words, do not
- * destroy the contents of SCSICONF and SCSICONF2 for
- * AIC-7770 based controllers.
+ * Snapshot of MSG_OUT taken after each message is sent.
*/
- CMDOUTCNT {
- size 1
- }
- /*
- * Maximum number of entries allowed in
- * the QOUT/INFIFO.
- */
- FIFODEPTH {
+ LAST_MSG {
size 1
}
/*
@@ -1118,12 +1092,10 @@ scratch_ram {
SCSICONF {
address 0x05a
size 1
+ bit TERM_ENB 0x80
bit RESET_SCSI 0x40
- }
- SCSICONF2 {
- address 0x05b
- size 1
- bit RESET_SCSI 0x40
+ mask HSCSIID 0x07 /* our SCSI ID */
+ mask HWSCSIID 0x0f /* our SCSI ID if Wide Bus */
}
HOSTCONF {
address 0x05d
@@ -1140,6 +1112,10 @@ scratch_ram {
const SCB_LIST_NULL 0xff
+/* Offsets into the SCBID array where different data is stored */
+const UNTAGGEDSCB_OFFSET 0
+const QOUTFIFO_OFFSET 1
+const QINFIFO_OFFSET 2
/* WDTR Message values */
const BUS_8_BIT 0x00
@@ -1147,3 +1123,24 @@ const BUS_16_BIT 0x01
const BUS_32_BIT 0x02
const MAX_OFFSET_8BIT 0x0f
const MAX_OFFSET_16BIT 0x08
+const HOST_MSG 0xFF
+
+/* Target mode command processing constants */
+const CMD_GROUP_CODE_SHIFT 0x05
+const CMD_GROUP0_BYTE_DELTA -4
+const CMD_GROUP2_BYTE_DELTA -6
+const CMD_GROUP4_BYTE_DELTA 4
+const CMD_GROUP5_BYTE_DELTA 11
+
+/*
+ * Downloaded (kernel inserted) constants
+ */
+/*
+ * Mask of bits to test against when looking at the Queue Count
+ * registers. Works around a bug on aic7850 chips.
+ */
+const QCNTMASK download
+/*
+ * Number of command descriptors in the command descriptor array.
+ */
+const TMODE_NUMCMDS download
diff --git a/drivers/scsi/aic7xxx/aic7xxx.seq b/drivers/scsi/aic7xxx/aic7xxx.seq
index d08fd7aaf..50cb2b67d 100644
--- a/drivers/scsi/aic7xxx/aic7xxx.seq
+++ b/drivers/scsi/aic7xxx/aic7xxx.seq
@@ -10,10 +10,7 @@
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions, and the following disclaimer,
* without modification, immediately at the beginning of the file.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
+ * 2. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* Where this Software is combined with software released under the terms of
@@ -35,11 +32,11 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: aic7xxx.seq,v 1.2 1997/08/30 02:17:29 ralf Exp $
+ * $Id: aic7xxx.seq,v 1.3 1998/05/04 10:59:18 ralf Exp $
*/
-#include <aic7xxx.reg>
-#include <scsi_message.h>
+#include "aic7xxx.reg"
+#include "scsi_message.h"
/*
* A few words on the waiting SCB list:
@@ -59,18 +56,21 @@
* automatically consume the entries.
*/
-/*
- * We assume that the kernel driver may reset us at any time, even in the
- * middle of a DMA, so clear DFCNTRL too.
- */
reset:
clr SCSISIGO; /* De-assert BSY */
/* Always allow reselection */
+.if ( TARGET_MODE )
+ mvi SCSISEQ, ENSELI|ENRSELI|ENAUTOATNP;
+.else
mvi SCSISEQ, ENRSELI|ENAUTOATNP;
+.endif
call clear_target_state;
+ and SXFRCTL0, ~SPIOEN;
poll_for_work:
- test SSTAT0,SELDO jnz select;
- test SSTAT0,SELDI jnz reselect;
+ mov A, QINPOS;
+poll_for_work_loop:
+ and SEQCTL, ~PAUSEDIS;
+ test SSTAT0, SELDO|SELDI jnz selection;
test SCSISEQ, ENSELO jnz poll_for_work;
.if ( TWIN_CHANNEL )
/*
@@ -80,16 +80,17 @@ poll_for_work:
* either a selection or reselection occurs.
*/
xor SBLKCTL,SELBUSB; /* Toggle to the other bus */
- test SSTAT0,SELDO jnz select;
- test SSTAT0,SELDI jnz reselect;
+ test SSTAT0, SELDO|SELDI jnz selection;
test SCSISEQ, ENSELO jnz poll_for_work;
xor SBLKCTL,SELBUSB; /* Toggle back */
.endif
cmp WAITING_SCBH,SCB_LIST_NULL jne start_waiting;
test_queue:
/* Has the driver posted any work for us? */
- mov A, QCNTMASK;
- test QINCNT,A jz poll_for_work;
+ or SEQCTL, PAUSEDIS;
+ cmp KERNEL_QINPOS, A je poll_for_work_loop;
+ inc QINPOS;
+ and SEQCTL, ~PAUSEDIS;
/*
* We have at least one queued SCB now and we don't have any
@@ -99,76 +100,24 @@ test_queue:
*/
.if ( SCB_PAGING )
mov ALLZEROS call get_free_or_disc_scb;
- cmp SINDEX, SCB_LIST_NULL je poll_for_work;
.endif
dequeue_scb:
- mov CUR_SCBID,QINFIFO;
+ add A, -1, QINPOS;
+ mvi QINFIFO_OFFSET call set_SCBID_host_addr_and_cnt;
+ mvi DFCNTRL, HDMAEN|DIRECTION|FIFORESET;
+
+ call dma_finish;
+ mov SINDEX, DFDAT;
.if !( SCB_PAGING )
/* In the non-paging case, the SCBID == hardware SCB index */
- mov SCBPTR, CUR_SCBID;
+ mov SCBPTR, SINDEX;
.endif
dma_queued_scb:
/*
* DMA the SCB from host ram into the current SCB location.
*/
mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
- mov CUR_SCBID call dma_scb;
-
-/*
- * See if there is not already an active SCB for this target. This code
- * locks out on a per target basis instead of target/lun. Although this
- * is not ideal for devices that have multiple luns active at the same
- * time, it is faster than looping through all SCB's looking for active
- * commands. We also don't have enough spare SCB space for us to store the
- * SCBID of the currently busy transaction for each target/lun making it
- * impossible to link up the SCBs.
- */
-test_busy:
- test SCB_CONTROL, TAG_ENB|ABORT_SCB jnz start_scb;
- mvi SEQCTL, PAUSEDIS|FASTMODE;
- mov SAVED_SCBPTR, SCBPTR;
- mov SCB_TCL call index_untagged_scb;
- mov ARG_1, SINDIR; /*
- * ARG_1 should
- * now have the SCB ID of
- * any active, non-tagged,
- * command for this target.
- */
- cmp ARG_1, SCB_LIST_NULL je make_busy;
-.if ( SCB_PAGING )
- /*
- * Put this SCB back onto the free list. It
- * may be necessary to satisfy the search for
- * the active SCB.
- */
- mov SCBPTR, SAVED_SCBPTR;
- call add_scb_to_free_list;
- /* Find the active SCB */
- mov ALLZEROS call findSCB;
- /*
- * If we couldn't find it, tell the kernel. This should
- * never happen.
- */
- cmp SINDEX, SCB_LIST_NULL jne paged_busy_link;
- mvi INTSTAT, NO_MATCH_BUSY;
-paged_busy_link:
- /* Link us in */
- mov SCB_LINKED_NEXT, CUR_SCBID;
- /* Put it back on the disconnected list */
- call add_scb_to_disc_list;
- mvi SEQCTL, FASTMODE;
- jmp poll_for_work;
-.else
-simple_busy_link:
- mov SCBPTR, ARG_1;
- mov SCB_LINKED_NEXT, CUR_SCBID;
- mvi SEQCTL, FASTMODE;
- jmp poll_for_work;
-.endif
-make_busy:
- mov DINDIR, CUR_SCBID;
- mov SCBPTR, SAVED_SCBPTR;
- mvi SEQCTL, FASTMODE;
+ call dma_scb;
start_scb:
/*
@@ -179,9 +128,7 @@ start_scb:
mov WAITING_SCBH, SCBPTR;
start_waiting:
/*
- * Pull the first entry off of the waiting SCB list
- * We don't have to "test_busy" because only transactions that
- * have passed that test can be in the WAITING_SCB list.
+ * Pull the first entry off of the waiting SCB list.
*/
mov SCBPTR, WAITING_SCBH;
call start_selection;
@@ -199,17 +146,170 @@ initialize_scsiid:
and SCSIID, OID; /* Clear old target */
or SCSIID, A;
mvi SCSISEQ, ENSELO|ENAUTOATNO|ENRSELI|ENAUTOATNP ret;
+
+/*
+ * Initialize Ultra mode setting and clear the SCSI channel.
+ * SINDEX should contain any additional bit's the client wants
+ * set in SXFRCTL0.
+ */
+initialize_channel:
+ or A, CLRSTCNT|CLRCHN, SINDEX;
+ or SXFRCTL0, A;
+.if ( ULTRA )
+ultra:
+ mvi SINDEX, ULTRA_ENB+1;
+ test SAVED_TCL, 0x80 jnz ultra_2; /* Target ID > 7 */
+ dec SINDEX;
+ultra_2:
+ mov FUNCTION1,SAVED_TCL;
+ mov A,FUNCTION1;
+ test SINDIR, A jz ndx_dtr;
+ or SXFRCTL0, FAST20;
+.endif
+
+/*
+ * Initialize SCSIRATE with the appropriate value for this target.
+ * The SCSIRATE settings for each target are stored in an array
+ * based at TARG_SCRATCH.
+ */
+ndx_dtr:
+ shr A,4,SAVED_TCL;
+ test SBLKCTL,SELBUSB jz ndx_dtr_2;
+ or SAVED_TCL, SELBUSB; /* Add the channel bit while we're here */
+ or A,0x08; /* Channel B entries add 8 */
+ndx_dtr_2:
+ add SINDEX,TARG_SCRATCH,A;
+ mov SCSIRATE,SINDIR ret;
+
+
+selection:
+ test SSTAT0,SELDO jnz select_out;
+select_in:
+.if ( TARGET_MODE )
+ test SSTAT0, TARGET jz initiator_reselect;
+ /*
+ * We've just been selected. Assert BSY and
+ * setup the phase for receiving the messages
+ * from the target.
+ */
+ mvi SCSISIGO, P_MESGOUT|BSYO;
+ mvi CLRSINT0, CLRSELDO;
+
+ /*
+ * If ATN isn't asserted, go directly to bus free.
+ */
+ test SCSISIGI, ATNI jz target_busfree;
+
+ /*
+ * Setup the DMA for sending the identify and
+ * command information.
+ */
+ mov A, TMODE_CMDADDR_NEXT;
+ mvi TMODE_CMDADDR call set_32byte_haddr_and_clrcnt;
+ mvi DFCNTRL, FIFORESET;
+
+ clr SINDEX;
+ /* Watch ATN closely now */
+message_loop:
+ or SXFRCTL0, SPIOEN;
+ test SSTAT0, SPIORDY jz .;
+ and SXFRCTL0, ~SPIOEN;
+ mov DINDEX, SCSIDATL;
+ mov DFDAT, DINDEX;
+ inc SINDEX;
+
+ /* Message Testing... */
+ test DINDEX, MSG_IDENTIFYFLAG jz . + 2;
+ mov ARG_1, DINDEX;
+
+ test SCSISIGI, ATNI jnz message_loop;
+ add A, -4, SINDEX;
+ jc target_cmdphase;
+ mvi DFDAT, SCB_LIST_NULL; /* Terminate the message list */
+
+target_cmdphase:
+ add HCNT[0], 1, A;
+ mvi SCSISIGO, P_COMMAND|BSYO;
+ or SXFRCTL0, SPIOEN;
+ test SSTAT0, SPIORDY jz .;
+ mov A, SCSIDATL;
+ mov DFDAT, A; /* Store for host */
+
+ /*
+ * Determine the number of bytes to read
+ * based on the command group code. Count is
+ * one less than the total since we've already
+ * fetched the first byte.
+ */
+ clr SINDEX;
+ shr A, CMD_GROUP_CODE_SHIFT;
+ add SEQADDR0, A;
+
+ add SINDEX, CMD_GROUP0_BYTE_DELTA;
+ nop; /* Group 1 and 2 are the same */
+ add SINDEX, CMD_GROUP2_BYTE_DELTA;
+ nop; /* Group 3 is reserved */
+ add SINDEX, CMD_GROUP4_BYTE_DELTA;
+ add SINDEX, CMD_GROUP5_BYTE_DELTA;
+ /* Group 6 and 7 are not handled yet */
+
+ mov A, SINDEX;
+ add HCNT[0], A;
+
+command_loop:
+ test SSTAT0, SPIORDY jz .;
+ cmp SINDEX, 1 jne . + 2;
+ and SXFRCTL0, ~SPIOEN; /* Last Byte */
+ mov DFDAT, SCSIDATL;
+ dec SINDEX;
+ test SINDEX, 0xFF jnz command_loop;
+
+ or DFCNTRL, HDMAEN|FIFOFLUSH;
+
+ call dma_finish;
+
+ test ARG_1, MSG_IDENTIFY_DISCFLAG jz selectin_post;
+
+ mvi SCSISIGO, P_MESGIN|BSYO;
+
+ or SXFRCTL0, SPIOEN;
+
+ mvi MSG_DISCONNECT call target_outb;
+
+selectin_post:
+ inc TMODE_CMDADDR_NEXT;
+ cmp TMODE_CMDADDR_NEXT, TMODE_NUMCMDS jne . + 2;
+ clr TMODE_CMDADDR_NEXT;
+ mvi QOUTFIFO, SCB_LIST_NULL;
+ mvi INTSTAT,CMDCMPLT;
+
+ test ARG_1, MSG_IDENTIFY_DISCFLAG jnz target_busfree;
+
+ /* Busy loop on something then go to data or status phase */
+
+target_busfree:
+ clr SCSISIGO;
+ jmp poll_for_work;
+
+.endif /* TARGET_MODE */
/*
* Reselection has been initiated by a target. Make a note that we've been
* reselected, but haven't seen an IDENTIFY message from the target yet.
*/
-reselect:
- clr MSG_LEN; /* Don't have anything in the mesg buffer */
+initiator_reselect:
mvi CLRSINT0, CLRSELDI;
/* XXX test for and handle ONE BIT condition */
and SAVED_TCL, SELID_MASK, SELID;
- or SEQ_FLAGS,RESELECTED;
- jmp select2;
+ mvi CLRSINT1,CLRBUSFREE;
+ or SIMODE1, ENBUSFREE; /*
+ * We aren't expecting a
+ * bus free, so interrupt
+ * the kernel driver if it
+ * happens.
+ */
+ mvi SPIOEN call initialize_channel;
+ mvi MSG_OUT, MSG_NOOP; /* No message to send */
+ jmp ITloop;
/*
* After the selection, remove this SCB from the "waiting SCB"
@@ -217,7 +317,7 @@ reselect:
* WAITING_SCBH. Our next pointer will be set to null the next time this
* SCB is used, so don't bother with it now.
*/
-select:
+select_out:
/* Turn off the selection hardware */
mvi SCSISEQ, ENRSELI|ENAUTOATNP; /*
* ATN on parity errors
@@ -227,41 +327,6 @@ select:
mov SCBPTR, WAITING_SCBH;
mov WAITING_SCBH,SCB_NEXT;
mov SAVED_TCL, SCB_TCL;
-/*
- * As soon as we get a successful selection, the target should go
- * into the message out phase since we have ATN asserted. Prepare
- * the message to send.
- *
- * Messages are stored in scratch RAM starting with a length byte
- * followed by the message itself.
- */
-
-mk_identify:
- and MSG_OUT,0x7,SCB_TCL; /* lun */
- and A,DISCENB,SCB_CONTROL; /* mask off disconnect privledge */
- or MSG_OUT,A; /* or in disconnect privledge */
- or MSG_OUT,MSG_IDENTIFYFLAG;
- mvi MSG_LEN, 1;
-
-/*
- * Send a tag message if TAG_ENB is set in the SCB control block.
- * Use SCB_TAG (the position in the kernel's SCB array) as the tag value.
- */
-mk_tag:
- test SCB_CONTROL,TAG_ENB jz mk_message;
- and MSG_OUT[1],TAG_ENB|SCB_TAG_TYPE,SCB_CONTROL;
- mov MSG_OUT[2],SCB_TAG;
- add MSG_LEN,2; /* update message length */
-
-/*
- * Interrupt the driver, and allow it to tweak the message buffer
- * if it asks.
- */
-mk_message:
- test SCB_CONTROL,MK_MESSAGE jz select2;
- mvi INTSTAT,AWAITING_MSG;
-
-select2:
mvi CLRSINT1,CLRBUSFREE;
or SIMODE1, ENBUSFREE; /*
* We aren't expecting a
@@ -269,54 +334,24 @@ select2:
* the kernel driver if it
* happens.
*/
+ mvi SPIOEN call initialize_channel;
/*
- * Initialize Ultra mode setting and clear the SCSI channel.
- */
- or SXFRCTL0, CLRSTCNT|SPIOEN|CLRCHN;
-.if ( ULTRA )
-ultra:
- mvi SINDEX, ULTRA_ENB+1;
- test SAVED_TCL, 0x80 jnz ultra_2; /* Target ID > 7 */
- dec SINDEX;
-ultra_2:
- mov FUNCTION1,SAVED_TCL;
- mov A,FUNCTION1;
- test SINDIR, A jz ndx_dtr;
- or SXFRCTL0, FAST20;
-.endif
-
-/*
- * Initialize SCSIRATE with the appropriate value for this target.
- * The SCSIRATE settings for each target are stored in an array
- * based at TARG_SCRATCH.
+ * As soon as we get a successful selection, the target should go
+ * into the message out phase since we have ATN asserted.
*/
-ndx_dtr:
- shr A,4,SAVED_TCL;
- test SBLKCTL,SELBUSB jz ndx_dtr_2;
- or SAVED_TCL, SELBUSB; /* Add the channel bit while we're here */
- or A,0x08; /* Channel B entries add 8 */
-ndx_dtr_2:
- add SINDEX,TARG_SCRATCH,A;
- mov SCSIRATE,SINDIR;
-
+ mvi MSG_OUT, MSG_IDENTIFYFLAG;
+ or SEQ_FLAGS, IDENTIFY_SEEN;
/*
- * Main loop for information transfer phases. If BSY is false, then
- * we have a bus free condition, expected or not. Otherwise, wait
- * for the target to assert REQ before checking MSG, C/D and I/O
- * for the bus phase.
- *
+ * Main loop for information transfer phases. Wait for the target
+ * to assert REQ before checking MSG, C/D and I/O for the bus phase.
*/
ITloop:
- test SSTAT1,REQINIT jz ITloop;
- test SSTAT1, SCSIPERR jnz ITloop;
+ call phase_lock;
- and A,PHASE_MASK,SCSISIGI;
- mov LASTPHASE,A;
- mov SCSISIGO,A;
+ mov A, LASTPHASE;
- cmp ALLZEROS,A je p_dataout;
- cmp A,P_DATAIN je p_datain;
+ test A, ~P_DATAIN jz p_data;
cmp A,P_COMMAND je p_command;
cmp A,P_MESGOUT je p_mesgout;
cmp A,P_STATUS je p_status;
@@ -329,25 +364,27 @@ await_busfree:
and SIMODE1, ~ENBUSFREE;
call clear_target_state;
mov NONE, SCSIDATL; /* Ack the last byte */
+ and SXFRCTL0, ~SPIOEN;
test SSTAT1,REQINIT|BUSFREE jz .;
test SSTAT1, BUSFREE jnz poll_for_work;
mvi INTSTAT, BAD_PHASE;
clear_target_state:
- clr DFCNTRL;
+ clr DFCNTRL; /*
+ * We assume that the kernel driver
+ * may reset us at any time, even
+ * in the middle of a DMA, so clear
+ * DFCNTRL too.
+ */
clr SCSIRATE; /*
* We don't know the target we will
* connect to, so default to narrow
* transfers to avoid parity problems.
*/
- and SXFRCTL0, ~FAST20;
+ and SXFRCTL0, ~(FAST20);
mvi LASTPHASE, P_BUSFREE;
/* clear target specific flags */
- and SEQ_FLAGS,~(RESELECTED|IDENTIFY_SEEN|TAGGED_SCB|DPHASE) ret;
-
-p_dataout:
- mvi DMAPARAMS, WIDEODD|SCSIEN|SDMAEN|HDMAEN|DIRECTION|FIFORESET;
- jmp data_phase_init;
+ and SEQ_FLAGS, (WIDE_BUS|TWIN_BUS) ret;
/*
* If we re-enter the data phase after going through another phase, the
@@ -358,9 +395,10 @@ data_phase_reinit:
mvi SCB_RESID_DCNT call bcopy_3;
jmp data_phase_loop;
-p_datain:
+p_data:
mvi DMAPARAMS, WIDEODD|SCSIEN|SDMAEN|HDMAEN|FIFORESET;
-data_phase_init:
+ test LASTPHASE, IOI jnz . + 2;
+ or DMAPARAMS, DIRECTION;
call assert; /*
* Ensure entering a data
* phase is okay - seen identify, etc.
@@ -398,6 +436,7 @@ data_phase_loop:
mvi HCNT[1], 0xff;
mvi HCNT[2], 0xff;
call set_stcnt_from_hcnt;
+ and DMAPARAMS, ~(HDMAEN|SDMAEN);
data_phase_inbounds:
/* If we are the last SG block, ensure wideodd is off. */
@@ -512,54 +551,85 @@ p_status:
jmp ITloop;
/*
- * Message out phase. If there is not an active message, but the target
- * took us into this phase anyway, build a no-op message and send it.
+ * Message out phase. If MSG_OUT is 0x80, build I full indentify message
+ * sequence and send it to the target. In addition, if the MK_MESSAGE bit
+ * is set in the SCB_CONTROL byte, interrupt the host and allow it to send
+ * it's own message.
+ *
+ * If MSG_OUT is == HOST_MSG, also interrupt the host and take a message.
+ * This is done to allow the hsot to send messages outside of an identify
+ * sequence while protecting the seqencer from testing the MK_MESSAGE bit
+ * on an SCB that might not be for the current nexus. (For example, a
+ * BDR message in responce to a bad reselection would leave us pointed to
+ * an SCB that doesn't have anything to do with the current target).
+
+ * Otherwise, treat MSG_OUT as a 1 byte message to send (abort, abort tag,
+ * bus device reset).
+ *
+ * When there are no messages to send, MSG_OUT should be set to MSG_NOOP,
+ * in case the target decides to put us in this phase for some strange
+ * reason.
*/
p_mesgout:
- test MSG_LEN, 0xff jnz p_mesgout_start;
- mvi MSG_NOOP call mk_mesg; /* build NOP message */
-p_mesgout_start:
+ mov SINDEX, MSG_OUT;
+ cmp SINDEX, MSG_IDENTIFYFLAG jne p_mesgout_from_host;
+p_mesgout_identify:
+.if ( WIDE )
+ and SINDEX,0xf,SCB_TCL; /* lun */
+.else
+ and SINDEX,0x7,SCB_TCL; /* lun */
+.endif
+ and A,DISCENB,SCB_CONTROL; /* mask off disconnect privledge */
+ or SINDEX,A; /* or in disconnect privledge */
+ or SINDEX,MSG_IDENTIFYFLAG;
+p_mesgout_mk_message:
+ test SCB_CONTROL,MK_MESSAGE jz p_mesgout_tag;
+ mov SCSIDATL, SINDEX; /* Send the last byte */
+ jmp p_mesgout_from_host + 1;/* Skip HOST_MSG test */
/*
- * Set up automatic PIO transfer from MSG_OUT. Bit 3 in
- * SXFRCTL0 (SPIOEN) is already on.
+ * Send a tag message if TAG_ENB is set in the SCB control block.
+ * Use SCB_TAG (the position in the kernel's SCB array) as the tag value.
*/
- mvi SINDEX,MSG_OUT;
- mov DINDEX,MSG_LEN;
-
+p_mesgout_tag:
+ test SCB_CONTROL,TAG_ENB jz p_mesgout_onebyte;
+ mov SCSIDATL, SINDEX; /* Send the identify message */
+ call phase_lock;
+ cmp LASTPHASE, P_MESGOUT jne p_mesgout_done;
+ and SCSIDATL,TAG_ENB|SCB_TAG_TYPE,SCB_CONTROL;
+ call phase_lock;
+ cmp LASTPHASE, P_MESGOUT jne p_mesgout_done;
+ mov SCB_TAG jmp p_mesgout_onebyte;
/*
- * When target asks for a byte, drop ATN if it's the last one in
- * the message. Otherwise, keep going until the message is exhausted.
- * ATN must be dropped *at least* 90ns before we ack the last byte, so
- * the code is aranged to execute two instructions before the byte is
- * transferred to give a good margin of safety
- *
- * Keep an eye out for a phase change, in case the target issues
- * a MESSAGE REJECT.
+ * Interrupt the driver, and allow it to send a message
+ * if it asks.
*/
-p_mesgout_loop:
- test SSTAT1, REQINIT jz p_mesgout_loop;
- test SSTAT1, SCSIPERR jnz p_mesgout_loop;
- and LASTPHASE, PHASE_MASK, SCSISIGI;
- cmp LASTPHASE, P_MESGOUT jne p_mesgout_done;
-p_mesgout_testretry:
- test DINDEX,0xff jnz p_mesgout_dropatn;
- or SCSISIGO,ATNO,LASTPHASE;/* turn on ATN for the retry */
- jmp p_mesgout_start;
+p_mesgout_from_host:
+ cmp SINDEX, HOST_MSG jne p_mesgout_onebyte;
+ mvi INTSTAT,AWAITING_MSG;
+ /*
+ * Did the host detect a phase change?
+ */
+ cmp RETURN_1, MSGOUT_PHASEMIS je p_mesgout_done;
+
+p_mesgout_onebyte:
+ mvi CLRSINT1, CLRATNO;
+ mov SCSIDATL, SINDEX;
+
/*
* If the next bus phase after ATN drops is a message out, it means
* that the target is requesting that the last message(s) be resent.
*/
-p_mesgout_dropatn:
- cmp DINDEX,1 jne p_mesgout_outb; /* last byte? */
- mvi CLRSINT1,CLRATNO; /* drop ATN */
-p_mesgout_outb:
- dec DINDEX;
- mov SCSIDATL,SINDIR;
- jmp p_mesgout_loop;
+ call phase_lock;
+ cmp LASTPHASE, P_MESGOUT jne p_mesgout_done;
+ or SCSISIGO,ATNO,LASTPHASE;/* turn on ATN for the retry */
+ jmp p_mesgout;
p_mesgout_done:
mvi CLRSINT1,CLRATNO; /* Be sure to turn ATNO off */
- clr MSG_LEN; /* no active msg */
+ mov LAST_MSG, MSG_OUT;
+ cmp MSG_OUT, MSG_IDENTIFYFLAG jne . + 2;
+ and SCB_CONTROL, ~MK_MESSAGE;
+ mvi MSG_OUT, MSG_NOOP; /* No message left */
jmp ITloop;
/*
@@ -567,7 +637,6 @@ p_mesgout_done:
*/
p_mesgin:
mvi ACCUM call inb_first; /* read the 1st message byte */
- mov REJBYTE,A; /* save it for the driver */
test A,MSG_IDENTIFYFLAG jnz mesgin_identify;
cmp A,MSG_DISCONNECT je mesgin_disconnect;
@@ -597,8 +666,8 @@ mesgin_complete:
/*
* We got a "command complete" message, so put the SCB_TAG into the QOUTFIFO,
* and trigger a completion interrupt. Before doing so, check to see if there
- * is a residual or the status byte is something other than NO_ERROR (0). In
- * either of these conditions, we upload the SCB back to the host so it can
+ * is a residual or the status byte is something other than STATUS_GOOD (0).
+ * In either of these conditions, we upload the SCB back to the host so it can
* process this information. In the case of a non zero status byte, we
* additionally interrupt the kernel driver synchronously, allowing it to
* decide if sense should be retrieved. If the kernel driver wishes to request
@@ -616,60 +685,17 @@ mesgin_complete:
* First check for residuals
*/
test SCB_RESID_SGCNT,0xff jnz upload_scb;
- test SCB_TARGET_STATUS,0xff jz status_ok; /* Good Status? */
+ test SCB_TARGET_STATUS,0xff jz complete; /* Good Status? */
upload_scb:
mvi DMAPARAMS, FIFORESET;
mov SCB_TAG call dma_scb;
check_status:
- test SCB_TARGET_STATUS,0xff jz status_ok; /* Just a residual? */
+ test SCB_TARGET_STATUS,0xff jz complete; /* Just a residual? */
mvi INTSTAT,BAD_STATUS; /* let driver know */
- cmp RETURN_1, SEND_SENSE jne status_ok;
+ cmp RETURN_1, SEND_SENSE jne complete;
/* This SCB becomes the next to execute as it will retrieve sense */
- mov SCB_LINKED_NEXT, SCB_TAG;
- jmp dma_next_scb;
-
-status_ok:
-/* First, mark this target as free. */
- test SCB_CONTROL,TAG_ENB jnz complete; /*
- * Tagged commands
- * don't busy the
- * target.
- */
- mov SAVED_SCBPTR, SCBPTR;
- mov SAVED_LINKPTR, SCB_LINKED_NEXT;
- mov SCB_TCL call index_untagged_scb;
- mov DINDIR, SAVED_LINKPTR;
- mov SCBPTR, SAVED_SCBPTR;
-
-complete:
- /* Post the SCB and issue an interrupt */
-.if ( SCB_PAGING )
- /*
- * Spin loop until there is space
- * in the QOUTFIFO.
- */
- mov A, FIFODEPTH;
- cmp CMDOUTCNT, A je .;
- inc CMDOUTCNT;
-.endif
- mov QOUTFIFO,SCB_TAG;
- mvi INTSTAT,CMDCMPLT;
- test SCB_CONTROL, ABORT_SCB jz dma_next_scb;
- mvi INTSTAT, ABORT_CMDCMPLT;
-
-dma_next_scb:
- cmp SCB_LINKED_NEXT, SCB_LIST_NULL je add_to_free_list;
-.if !( SCB_PAGING )
- /* Only DMA on top of ourselves if we are the SCB to download */
- mov A, SCB_LINKED_NEXT;
- cmp SCB_TAG, A je dma_next_scb2;
- call add_scb_to_free_list;
- mov SCBPTR, A;
- jmp add_to_waiting_list;
-.endif
-dma_next_scb2:
mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
- mov SCB_LINKED_NEXT call dma_scb;
+ mov SCB_TAG call dma_scb;
add_to_waiting_list:
mov SCB_NEXT,WAITING_SCBH;
mov WAITING_SCBH, SCBPTR;
@@ -679,6 +705,28 @@ add_to_waiting_list:
*/
call start_selection;
jmp await_busfree;
+
+complete:
+ /* If we are untagged, clear our address up in host ram */
+ test SCB_CONTROL, TAG_ENB jnz complete_post;
+ mov A, SAVED_TCL;
+ mvi UNTAGGEDSCB_OFFSET call set_SCBID_host_addr_and_cnt;
+ mvi DFCNTRL, FIFORESET;
+ mvi DFDAT, SCB_LIST_NULL;
+ or DFCNTRL, HDMAEN|FIFOFLUSH;
+ call dma_finish;
+
+complete_post:
+ /* Post the SCB and issue an interrupt */
+ mov A, QOUTPOS;
+ mvi QOUTFIFO_OFFSET call set_SCBID_host_addr_and_cnt;
+ mvi DFCNTRL, FIFORESET;
+ mov DFDAT, SCB_TAG;
+ or DFCNTRL, HDMAEN|FIFOFLUSH;
+ call dma_finish;
+ inc QOUTPOS;
+ mvi INTSTAT,CMDCMPLT;
+
add_to_free_list:
call add_scb_to_free_list;
jmp await_busfree;
@@ -690,22 +738,8 @@ add_to_free_list:
* or simply to do nothing.
*/
mesgin_extended:
- mvi MSGIN_EXT_LEN call inb_next;
- mov A, MSGIN_EXT_LEN;
-mesgin_extended_loop:
- mov DINDEX call inb_next;
- dec A;
- cmp DINDEX, MSGIN_EXT_BYTES+3 jne mesgin_extended_loop_test;
- dec DINDEX; /* dump by repeatedly filling the last byte */
-mesgin_extended_loop_test:
- test A, 0xFF jnz mesgin_extended_loop;
-mesgin_extended_intr:
mvi INTSTAT,EXTENDED_MSG; /* let driver know */
- cmp RETURN_1,SEND_REJ je rej_mesgin;
- cmp RETURN_1,SEND_MSG jne mesgin_done;
-/* The kernel has setup a message to be sent */
- or SCSISIGO,ATNO,LASTPHASE; /* turn on ATNO */
- jmp mesgin_done;
+ jmp ITloop;
/*
* Is it a disconnect message? Set a flag in the SCB to remind us
@@ -713,9 +747,7 @@ mesgin_extended_intr:
*/
mesgin_disconnect:
or SCB_CONTROL,DISCONNECTED;
-.if ( SCB_PAGING )
call add_scb_to_disc_list;
-.endif
jmp await_busfree;
/*
@@ -764,24 +796,30 @@ mesgin_rdptrs:
* clearing the "disconnected" bit so we don't "find" it by accident later.
*/
mesgin_identify:
- test A,0x78 jnz rej_mesgin; /*!DiscPriv|!LUNTAR|!Reserved*/
+.if ( WIDE )
+ and A,0x0f; /* lun in lower four bits */
+.else
and A,0x07; /* lun in lower three bits */
+.endif
or SAVED_TCL,A; /* SAVED_TCL should be complete now */
- mov SAVED_TCL call index_untagged_scb;
- mov ARG_1, SINDIR;
+
+ call get_untagged_SCBID;
+ cmp ARG_1, SCB_LIST_NULL je snoop_tag;
.if ( SCB_PAGING )
- cmp ARG_1,SCB_LIST_NULL jne use_findSCB;
-.else
- cmp ARG_1,SCB_LIST_NULL je snoop_tag;
- /* Directly index the SCB */
- mov SCBPTR,ARG_1;
- test SCB_CONTROL,DISCONNECTED jz not_found;
- jmp setup_SCB;
+ test SEQ_FLAGS, SCBPTR_VALID jz use_retrieveSCB;
.endif
+ /*
+ * If the SCB was found in the disconnected list (as is
+ * always the case in non-paging scenarios), SCBPTR is already
+ * set to the correct SCB. So, simply setup the SCB and get
+ * on with things.
+ */
+ mov SCBPTR call rem_scb_from_disc_list;
+ jmp setup_SCB;
/*
* Here we "snoop" the bus looking for a SIMPLE QUEUE TAG message.
* If we get one, we use the tag returned to find the proper
- * SCB. With SCB paging, this requires using findSCB for both tagged
+ * SCB. With SCB paging, this requires using search for both tagged
* and non-tagged transactions since the SCB may exist in any slot.
* If we're not using SCB paging, we can use the tag as the direct
* index to the SCB.
@@ -789,44 +827,42 @@ mesgin_identify:
snoop_tag:
mov NONE,SCSIDATL; /* ACK Identify MSG */
snoop_tag_loop:
- test SSTAT1,REQINIT jz snoop_tag_loop;
- test SSTAT1, SCSIPERR jnz snoop_tag_loop;
- and LASTPHASE, PHASE_MASK, SCSISIGI;
+ call phase_lock;
cmp LASTPHASE, P_MESGIN jne not_found;
cmp SCSIBUSL,MSG_SIMPLE_Q_TAG jne not_found;
get_tag:
- or SEQ_FLAGS, TAGGED_SCB;
mvi ARG_1 call inb_next; /* tag value */
-/*
- * See if the tag is in range. The tag is < SCBCOUNT if we add
- * the complement of SCBCOUNT to the incomming tag and there is
- * no carry.
- */
- mov A,COMP_SCBCOUNT;
- add SINDEX,A,ARG_1;
- jc not_found;
.if ! ( SCB_PAGING )
index_by_tag:
mov SCBPTR,ARG_1;
- mov A, SAVED_TCL;
- cmp SCB_TCL,A jne not_found;
test SCB_CONTROL,TAG_ENB jz not_found;
- test SCB_CONTROL,DISCONNECTED jz not_found;
+ mov SCBPTR call rem_scb_from_disc_list;
.else
/*
* Ensure that the SCB the tag points to is for an SCB transaction
* to the reconnecting target.
*/
-use_findSCB:
- mov ALLZEROS call findSCB; /* Have to search */
- cmp SINDEX, SCB_LIST_NULL je not_found;
+use_retrieveSCB:
+ call retrieveSCB;
.endif
setup_SCB:
+ mov A, SAVED_TCL;
+ cmp SCB_TCL, A jne not_found_cleanup_scb;
+ test SCB_CONTROL,DISCONNECTED jz not_found_cleanup_scb;
and SCB_CONTROL,~DISCONNECTED;
or SEQ_FLAGS,IDENTIFY_SEEN; /* make note of IDENTIFY */
+ /* See if the host wants to send a message upon reconnection */
+ test SCB_CONTROL, MK_MESSAGE jz mesgin_done;
+ and SCB_CONTROL, ~MK_MESSAGE;
+ mvi HOST_MSG call mk_mesg;
jmp mesgin_done;
+not_found_cleanup_scb:
+ test SCB_CONTROL, DISCONNECTED jz . + 3;
+ call add_scb_to_disc_list;
+ jmp not_found;
+ call add_scb_to_free_list;
not_found:
mvi INTSTAT, NO_MATCH;
mvi MSG_BUS_DEV_RESET call mk_mesg;
@@ -851,23 +887,8 @@ mesgin_reject:
* if there is no active message already. SINDEX is returned intact.
*/
mk_mesg:
- mvi SEQCTL, PAUSEDIS|FASTMODE;
- test MSG_LEN,0xff jz mk_mesg1; /* Should always succeed */
-
- /*
- * Hmmm. For some reason the mesg buffer is in use.
- * Tell the driver. It should look at SINDEX to find
- * out what we wanted to use the buffer for and resolve
- * the conflict.
- */
- mvi SEQCTL,FASTMODE;
- mvi INTSTAT,MSG_BUFFER_BUSY;
-
-mk_mesg1:
or SCSISIGO,ATNO,LASTPHASE;/* turn on ATNO */
- mvi MSG_LEN,1; /* length = 1 */
- mov MSG_OUT,SINDEX; /* 1-byte message */
- mvi SEQCTL,FASTMODE ret;
+ mov MSG_OUT,SINDEX ret;
/*
* Functions to read data in Automatic PIO mode.
@@ -903,6 +924,17 @@ inb_first:
inb_last:
mov NONE,SCSIDATL ret; /*dummy read from latch to ACK*/
+.if ( TARGET_MODE )
+/*
+ * Send a byte to an initiator in Automatic PIO mode.
+ * SPIOEN must be on prior to calling this routine.
+ */
+target_outb:
+ mov SCSIDATL, SINDEX;
+ test SSTAT0, SPIORDY jz .;
+ ret;
+.endif
+
mesgin_phasemis:
/*
* We expected to receive another byte, but the target changed phase
@@ -957,60 +989,114 @@ return:
* message.
*/
assert:
- test SEQ_FLAGS,RESELECTED jz return; /* reselected? */
test SEQ_FLAGS,IDENTIFY_SEEN jnz return; /* seen IDENTIFY? */
mvi INTSTAT,NO_IDENT ret; /* no - tell the kernel */
-.if ( SCB_PAGING )
/*
* Locate a disconnected SCB either by SAVED_TCL (ARG_1 is SCB_LIST_NULL)
- * or by the SCBIDn ARG_1. The search begins at the SCB index passed in
- * via SINDEX. If the SCB cannot be found, SINDEX will be SCB_LIST_NULL,
- * otherwise, SCBPTR is set to the proper SCB.
+ * or by the SCBID ARG_1. The search begins at the SCB index passed in
+ * via SINDEX which is an SCB that must be on the disconnected list. If
+ * the SCB cannot be found, SINDEX will be SCB_LIST_NULL, otherwise, SCBPTR
+ * is set to the proper SCB.
*/
findSCB:
- mov SCBPTR,SINDEX; /* switch to next SCB */
+ mov SCBPTR,SINDEX; /* Initialize SCBPTR */
+ cmp ARG_1, SCB_LIST_NULL jne findSCB_by_SCBID;
+ mov A, SAVED_TCL;
+ mvi SCB_TCL jmp findSCB_loop; /* &SCB_TCL -> SINDEX */
+findSCB_by_SCBID:
mov A, ARG_1; /* Tag passed in ARG_1 */
- cmp SCB_TAG,A jne findSCB_loop;
- test SCB_CONTROL,DISCONNECTED jnz foundSCB;/*should be disconnected*/
+ mvi SCB_TAG jmp findSCB_loop; /* &SCB_TAG -> SINDEX */
+findSCB_next:
+ cmp SCB_NEXT, SCB_LIST_NULL je notFound;
+ mov SCBPTR,SCB_NEXT;
+ dec SINDEX; /* Last comparison moved us too far */
findSCB_loop:
- inc SINDEX;
- mov A,SCBCOUNT;
- cmp SINDEX,A jne findSCB;
+ cmp SINDIR, A jne findSCB_next;
+ mov SINDEX, SCBPTR ret;
+notFound:
+ mvi SINDEX, SCB_LIST_NULL ret;
+
/*
- * We didn't find it. If we're paging, pull an SCB and DMA down the
- * one we want. If we aren't paging or the SCB we dma down has the
- * abort flag set, return not found.
+ * Retrieve an SCB by SCBID first searching the disconnected list falling
+ * back to DMA'ing the SCB down from the host. This routine assumes that
+ * ARG_1 is the SCBID of interrest and that SINDEX is the position in the
+ * disconnected list to start the search from. If SINDEX is SCB_LIST_NULL,
+ * we go directly to the host for the SCB.
+ */
+retrieveSCB:
+ test SEQ_FLAGS, SCBPTR_VALID jz retrieve_from_host;
+ mov SCBPTR call findSCB; /* Continue the search */
+ cmp SINDEX, SCB_LIST_NULL je retrieve_from_host;
+
+/*
+ * This routine expects SINDEX to contain the index of the SCB to be
+ * removed and SCBPTR to be pointing to that SCB.
*/
- mov ALLZEROS call get_free_or_disc_scb;
- mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
- mov ARG_1 call dma_scb;
- test SCB_RESID_SGCNT, 0xff jz . + 2;
- or SCB_CONTROL, MUST_DMAUP_SCB;
- test SCB_CONTROL, ABORT_SCB jz return;
-find_error:
- mvi SINDEX, SCB_LIST_NULL ret;
-foundSCB:
- test SCB_CONTROL, ABORT_SCB jnz find_error;
rem_scb_from_disc_list:
/* Remove this SCB from the disconnection list */
cmp SCB_NEXT,SCB_LIST_NULL je unlink_prev;
- mov SAVED_LINKPTR, SCB_PREV;
+ mov DINDEX, SCB_PREV;
mov SCBPTR, SCB_NEXT;
- mov SCB_PREV, SAVED_LINKPTR;
+ mov SCB_PREV, DINDEX;
mov SCBPTR, SINDEX;
unlink_prev:
cmp SCB_PREV,SCB_LIST_NULL je rHead;/* At the head of the list */
- mov SAVED_LINKPTR, SCB_NEXT;
+ mov DINDEX, SCB_NEXT;
mov SCBPTR, SCB_PREV;
- mov SCB_NEXT, SAVED_LINKPTR;
+ mov SCB_NEXT, DINDEX;
mov SCBPTR, SINDEX ret;
rHead:
mov DISCONNECTED_SCBH,SCB_NEXT ret;
-.else
- ret;
-.endif
+
+retrieve_from_host:
+/*
+ * We didn't find it. Pull an SCB and DMA down the one we want.
+ * We should never get here in the non-paging case.
+ */
+ mov ALLZEROS call get_free_or_disc_scb;
+ mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
+ /* Jump instead of call as we want to return anyway */
+ mov ARG_1 jmp dma_scb;
+
+/*
+ * Determine whether a target is using tagged or non-tagged transactions
+ * by first looking for a matching transaction based on the TCL and if
+ * that fails, looking up this device in the host's untagged SCB array.
+ * The TCL to search for is assumed to be in SAVED_TCL. The value is
+ * returned in ARG_1 (SCB_LIST_NULL for tagged, SCBID for non-tagged).
+ * The SCBPTR_VALID bit is set in SEQ_FLAGS if we found the information
+ * in an SCB instead of having to go to the host.
+ */
+get_untagged_SCBID:
+ cmp DISCONNECTED_SCBH, SCB_LIST_NULL je get_SCBID_from_host;
+ mvi ARG_1, SCB_LIST_NULL;
+ mov DISCONNECTED_SCBH call findSCB;
+ cmp SINDEX, SCB_LIST_NULL je get_SCBID_from_host;
+ or SEQ_FLAGS, SCBPTR_VALID;/* Was in disconnected list */
+ test SCB_CONTROL, TAG_ENB jnz . + 2;
+ mov ARG_1, SCB_TAG ret;
+ mvi ARG_1, SCB_LIST_NULL ret;
+
+set_SCBID_host_addr_and_cnt:
+ mov DINDEX, SINDEX;
+ mvi SCBID_ADDR call set_1byte_haddr_and_clrcnt;
+ mvi HCNT[0], 1 ret;
+
+get_SCBID_from_host:
+ mov A, SAVED_TCL;
+ mvi UNTAGGEDSCB_OFFSET call set_SCBID_host_addr_and_cnt;
+ mvi DFCNTRL, HDMAEN|DIRECTION|FIFORESET;
+
+ call dma_finish;
+ mov ARG_1, DFDAT ret;
+
+phase_lock:
+ test SSTAT1, REQINIT jz phase_lock;
+ test SSTAT1, SCSIPERR jnz phase_lock;
+ and LASTPHASE, PHASE_MASK, SCSISIGI;
+ mov SCSISIGO, LASTPHASE ret;
set_stcnt_from_hcnt:
mov STCNT[0], HCNT[0];
@@ -1029,23 +1115,32 @@ bcopy_3:
mov DINDIR, SINDIR;
mov DINDIR, SINDIR ret;
+/*
+ * Setup haddr and count assuming that A is an
+ * index into an array of 32byte objects.
+ */
+set_32byte_haddr_and_clrcnt:
+ shr DINDEX, 3, A;
+ shl A, 5;
+set_1byte_haddr_and_clrcnt: /* DINDEX must be 0 upon call */
+ add HADDR[0], A, SINDIR;
+ mov A, DINDEX;
+ adc HADDR[1], A, SINDIR;
+ clr A;
+ adc HADDR[2], A, SINDIR;
+ adc HADDR[3], A, SINDIR;
+ /* Clear Count */
+ clr HCNT[1];
+ clr HCNT[2] ret;
+
dma_scb:
/*
* SCB index is in SINDEX. Determine the physical address in
* the host where this SCB is located and load HADDR with it.
*/
- shr DINDEX, 3, SINDEX;
- shl A, 5, SINDEX;
- add HADDR[0], A, HSCB_ADDR[0];
- mov A, DINDEX;
- adc HADDR[1], A, HSCB_ADDR[1];
- clr A;
- adc HADDR[2], A, HSCB_ADDR[2];
- adc HADDR[3], A, HSCB_ADDR[3];
- /* Setup Count */
+ mov A, SINDEX;
+ mvi HSCB_ADDR call set_32byte_haddr_and_clrcnt;
mvi HCNT[0], 28;
- clr HCNT[1];
- clr HCNT[2];
mov DFCNTRL, DMAPARAMS;
test DMAPARAMS, DIRECTION jnz dma_scb_fromhost;
/* Fill it with the SCB data */
@@ -1092,25 +1187,12 @@ dma_finish:
test DFCNTRL, HDMAEN jnz .;
ret;
-index_untagged_scb:
- mov DINDEX, SINDEX;
- shr DINDEX, 4;
- and DINDEX, 0x03; /* Bottom two bits of tid */
- add DINDEX, SCB_BUSYTARGETS;
- shr A, 6, SINDEX; /* Target ID divided by 4 */
- test SINDEX, SELBUSB jz index_untagged_scb2;
- add A, 2; /* Add 2 positions */
-index_untagged_scb2:
- mov SCBPTR, A; /*
- * Select the SCB with this
- * target's information.
- */
- mov SINDEX, DINDEX ret;
-
add_scb_to_free_list:
+.if ( SCB_PAGING )
mov SCB_NEXT, FREE_SCBH;
- mvi SCB_TAG, SCB_LIST_NULL;
- mov FREE_SCBH, SCBPTR ret;
+ mov FREE_SCBH, SCBPTR;
+.endif
+ mvi SCB_TAG, SCB_LIST_NULL ret;
.if ( SCB_PAGING )
get_free_or_disc_scb:
@@ -1120,16 +1202,6 @@ return_error:
mvi SINDEX, SCB_LIST_NULL ret;
dequeue_disc_scb:
mov SCBPTR, DISCONNECTED_SCBH;
-/*
- * If we have a residual, then we are in the middle of some I/O
- * and we have to send this SCB back up to the kernel so that the
- * saved data pointers and residual information isn't lost.
- */
- test SCB_CONTROL, MUST_DMAUP_SCB jz . + 3;
- and SCB_CONTROL, ~MUST_DMAUP_SCB;
- jmp dma_up_scb;
- test SCB_RESID_SGCNT,0xff jnz dma_up_scb;
- cmp SCB_LINKED_NEXT, SCB_LIST_NULL je unlink_disc_scb;
dma_up_scb:
mvi DMAPARAMS, FIFORESET;
mov SCB_TAG call dma_scb;
@@ -1139,6 +1211,7 @@ unlink_disc_scb:
dequeue_free_scb:
mov SCBPTR, FREE_SCBH;
mov FREE_SCBH, SCB_NEXT ret;
+.endif
add_scb_to_disc_list:
/*
@@ -1153,4 +1226,3 @@ add_scb_to_disc_list:
mov SCBPTR,SCB_NEXT;
mov SCB_PREV,DISCONNECTED_SCBH;
mov SCBPTR,DISCONNECTED_SCBH ret;
-.endif
diff --git a/drivers/scsi/aic7xxx/scsi_message.h b/drivers/scsi/aic7xxx/scsi_message.h
index 267a01591..16c401388 100644
--- a/drivers/scsi/aic7xxx/scsi_message.h
+++ b/drivers/scsi/aic7xxx/scsi_message.h
@@ -1,7 +1,3 @@
-/*
- * SCSI messages definitions.
- */
-
/* Messages (1 byte) */ /* I/T (M)andatory or (O)ptional */
#define MSG_CMDCOMPLETE 0x00 /* M/M */
#define MSG_EXTENDED 0x01 /* O/O */
@@ -30,6 +26,7 @@
/* Identify message */ /* M/M */
#define MSG_IDENTIFYFLAG 0x80
+#define MSG_IDENTIFY_DISCFLAG 0x40
#define MSG_IDENTIFY(lun, disc) (((disc) ? 0xc0 : MSG_IDENTIFYFLAG) | (lun))
#define MSG_ISIDENTIFY(m) ((m) & MSG_IDENTIFYFLAG)
@@ -39,3 +36,6 @@
#define MSG_EXT_WDTR 0x03
#define MSG_EXT_WDTR_LEN 0x02
+#define MSG_EXT_WDTR_BUS_8_BIT 0x00
+#define MSG_EXT_WDTR_BUS_16_BIT 0x01
+#define MSG_EXT_WDTR_BUS_32_BIT 0x02
diff --git a/drivers/scsi/aic7xxx/sequencer.h b/drivers/scsi/aic7xxx/sequencer.h
index dea901fe8..8dc0d22fc 100644
--- a/drivers/scsi/aic7xxx/sequencer.h
+++ b/drivers/scsi/aic7xxx/sequencer.h
@@ -36,49 +36,46 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: sequencer.h,v 1.1 1997/08/05 09:44:13 ralf Exp $
+ * $Id: sequencer.h,v 1.3 1997/09/27 19:37:31 gibbs Exp $
*/
-#if defined(__KERNEL__)
-typedef unsigned char u_int8_t;
-#endif
-
struct ins_format1 {
- u_int8_t immediate;
- u_int8_t source;
- u_int8_t destination;
- u_int8_t opcode_ret;
+ unsigned char immediate;
+ unsigned char source;
+ unsigned char destination;
+ unsigned char opcode_ret;
+#define DOWNLOAD_CONST_IMMEDIATE 0x80
};
struct ins_format2 {
- u_int8_t shift_control;
- u_int8_t source;
- u_int8_t destination;
- u_int8_t opcode_ret;
+ unsigned char shift_control;
+ unsigned char source;
+ unsigned char destination;
+ unsigned char opcode_ret;
#define RETURN_BIT 0x01
};
struct ins_format3 {
- u_int8_t immediate;
- u_int8_t source;
- u_int8_t address;
- u_int8_t opcode_addr;
+ unsigned char immediate;
+ unsigned char source;
+ unsigned char address;
+ unsigned char opcode_addr;
#define ADDR_HIGH_BIT 0x01
};
+#ifndef __KERNEL__
struct instruction {
union {
struct ins_format1 format1;
struct ins_format2 format2;
struct ins_format3 format3;
- u_int8_t bytes[4];
+ unsigned char bytes[4];
} format;
u_int srcline;
struct symbol *patch_label;
- struct {
- struct instruction *stqe_next; /* next element */
- } links;
+ STAILQ_ENTRY(instruction) links;
};
+#endif
#define AIC_OP_OR 0x0
#define AIC_OP_AND 0x1
diff --git a/drivers/scsi/aic7xxx_proc.c b/drivers/scsi/aic7xxx_proc.c
index 8ad2cfb03..c923cecec 100644
--- a/drivers/scsi/aic7xxx_proc.c
+++ b/drivers/scsi/aic7xxx_proc.c
@@ -53,9 +53,6 @@ proc_debug(const char *fmt, ...)
static int aic7xxx_buffer_size = 0;
static char *aic7xxx_buffer = NULL;
-static const char *bus_names[] = { "Single", "Twin", "Wide" };
-static const char *chip_names[] = { "AIC-777x", "AIC-785x", "AIC-786x",
- "AIC-787x", "AIC-788x" };
/*+F*************************************************************************
@@ -86,7 +83,6 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length,
{
struct Scsi_Host *HBAptr;
struct aic7xxx_host *p;
- int found = FALSE;
int size = 0;
unsigned char i;
#ifdef AIC7XXX_PROC_STATS
@@ -95,36 +91,11 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length,
#endif
HBAptr = NULL;
- for (i=0; i < NUMBER(aic7xxx_boards); i++)
- {
- if ((HBAptr = aic7xxx_boards[i]) != NULL)
- {
- if (HBAptr->host_no == hostno)
- {
- break;
- }
- while ((HBAptr->hostdata != NULL) && !found &&
- ((HBAptr = ((struct aic7xxx_host *) HBAptr->hostdata)->next) != NULL))
- {
- if (HBAptr->host_no == hostno)
- {
- found = TRUE;
- }
- }
-
- if (!found)
- {
- HBAptr = NULL;
- }
- else
- {
- break;
- }
- }
- }
+ for(p=first_aic7xxx; p->host->host_no != hostno; p=p->next)
+ ;
- if (HBAptr == NULL)
+ if (!p)
{
size += sprintf(buffer, "Can't find adapter for host number %d\n", hostno);
if (size > length)
@@ -137,6 +108,8 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length,
}
}
+ HBAptr = p->host;
+
if (inout == TRUE) /* Has data been written to the file? */
{
return (aic7xxx_set_info(buffer, length, HBAptr));
@@ -150,16 +123,20 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length,
* if proc_stats is defined, then we sweep the stats structure to see
* how many drives we will be printing out for and add 384 bytes per
* device with active stats.
+ *
+ * Hmmmm...that 1.5k seems to keep growing as items get added so they
+ * can be easily viewed for debugging purposes. So, we bumped that
+ * 1.5k to 4k so we can quit having to bump it all the time.
*/
- size = 1536;
+ size = 4096;
#ifdef AIC7XXX_PROC_STATS
for (target = 0; target < MAX_TARGETS; target++)
{
for (lun = 0; lun < MAX_LUNS; lun++)
{
if (p->stats[target][lun].xfers != 0)
- size += 384;
+ size += 512;
}
}
#endif
@@ -182,29 +159,20 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length,
size = 0;
size += sprintf(BLS, "Adaptec AIC7xxx driver version: ");
- size += sprintf(BLS, "%s/", rcs_version(AIC7XXX_C_VERSION));
- size += sprintf(BLS, "%s", rcs_version(AIC7XXX_H_VERSION));
-#if 0
- size += sprintf(BLS, "%s\n", rcs_version(AIC7XXX_SEQ_VER));
-#endif
+ size += sprintf(BLS, "%s/", AIC7XXX_C_VERSION);
+ size += sprintf(BLS, "%s", AIC7XXX_H_VERSION);
size += sprintf(BLS, "\n");
size += sprintf(BLS, "Compile Options:\n");
#ifdef AIC7XXX_RESET_DELAY
size += sprintf(BLS, " AIC7XXX_RESET_DELAY : %d\n", AIC7XXX_RESET_DELAY);
#endif
-#ifdef AIC7XXX_CMDS_PER_LUN
- size += sprintf(BLS, " AIC7XXX_CMDS_PER_LUN : %d\n", AIC7XXX_CMDS_PER_LUN);
-#endif
-#ifdef AIC7XXX_TAGGED_QUEUEING
- size += sprintf(BLS, " AIC7XXX_TAGGED_QUEUEING: Enabled\n");
-#else
- size += sprintf(BLS, " AIC7XXX_TAGGED_QUEUEING: Disabled\n");
-#endif
-#ifdef AIC7XXX_PAGE_ENABLE
- size += sprintf(BLS, " AIC7XXX_PAGE_ENABLE : Enabled\n");
-#else
- size += sprintf(BLS, " AIC7XXX_PAGE_ENABLE : Disabled\n");
-#endif
+ size += sprintf(BLS, " AIC7XXX_TAGGED_QUEUEING: Adapter Support Enabled\n");
+ size += sprintf(BLS, " Check below to see "
+ "which\n"
+ " devices use tagged "
+ "queueing\n");
+ size += sprintf(BLS, " AIC7XXX_PAGE_ENABLE : Enabled (This is no longer "
+ "an option)\n");
#ifdef AIC7XXX_PROC_STATS
size += sprintf(BLS, " AIC7XXX_PROC_STATS : Enabled\n");
#else
@@ -213,17 +181,54 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length,
size += sprintf(BLS, "\n");
size += sprintf(BLS, "Adapter Configuration:\n");
size += sprintf(BLS, " SCSI Adapter: %s\n",
- board_names[p->chip_type]);
- size += sprintf(BLS, " (%s chipset)\n",
- chip_names[p->chip_class]);
- size += sprintf(BLS, " Host Bus: %s\n", bus_names[p->bus_type]);
- size += sprintf(BLS, " Base IO: %#.4x\n", p->base);
- size += sprintf(BLS, " Base IO Memory: 0x%x\n", p->mbase);
+ board_names[p->board_name_index]);
+ if (p->flags & AHC_TWIN)
+ size += sprintf(BLS, " Twin Channel\n");
+ else
+ {
+ char *channel = "";
+ char *ultra = "";
+ char *wide = "Narrow ";
+ if (p->flags & AHC_MULTI_CHANNEL)
+ {
+ channel = " Channel A";
+ if (p->flags & (AHC_CHNLB|AHC_CHNLC))
+ channel = (p->flags & AHC_CHNLB) ? " Channel B" : " Channel C";
+ }
+ if (p->type & AHC_WIDE)
+ wide = "Wide ";
+ if (p->type & AHC_ULTRA)
+ ultra = "Ultra ";
+ size += sprintf(BLS, " %s%sController%s\n",
+ ultra, wide, channel);
+ }
+ if( !(p->maddr) )
+ {
+ size += sprintf(BLS, " Programmed I/O Base: %lx\n", p->base);
+ }
+ else
+ {
+ size += sprintf(BLS, " PCI MMAPed I/O Base: 0x%lx\n", p->mbase);
+ }
+ if( !(p->type & AHC_AIC78x0) )
+ {
+ size += sprintf(BLS, " BIOS Memory Address: 0x%08x\n", p->bios_address);
+ size += sprintf(BLS, " %s\n",
+ (p->flags & AHC_BIOS_ENABLED) ? "Enabled" : "Disabled");
+ }
+ else
+ {
+ size += sprintf(BLS, " Adaptec SCSI BIOS: %s\n",
+ (p->flags & AHC_BIOS_ENABLED) ? "Enabled" : "Disabled");
+ }
size += sprintf(BLS, " IRQ: %d\n", HBAptr->irq);
- size += sprintf(BLS, " SCBs: Used %d, HW %d, Page %d\n",
- p->scb_data->numscbs, p->scb_data->maxhscbs, p->scb_data->maxscbs);
- size += sprintf(BLS, " Interrupts: %d", p->isr_count);
- if (p->chip_class == AIC_777x)
+ size += sprintf(BLS, " SCBs: Active %d, Max Active %d,\n",
+ p->activescbs, p->max_activescbs);
+ size += sprintf(BLS, " Allocated %d, HW %d, "
+ "Page %d\n", p->scb_data->numscbs, p->scb_data->maxhscbs,
+ p->scb_data->maxscbs);
+ size += sprintf(BLS, " Interrupts: %ld", p->isr_count);
+ if (p->type & AHC_AIC7770)
{
size += sprintf(BLS, " %s\n",
(p->pause & IRQMS) ? "(Level Sensitive)" : "(Edge Triggered)");
@@ -232,16 +237,39 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length,
{
size += sprintf(BLS, "\n");
}
- size += sprintf(BLS, " Serial EEPROM: %s\n",
- (p->flags & HAVE_SEEPROM) ? "True" : "False");
+ size += sprintf(BLS, " BIOS Control Word: 0x%04x\n",
+ p->bios_control);
+ size += sprintf(BLS, " Adapter Control Word: 0x%04x\n",
+ p->adapter_control);
size += sprintf(BLS, " Extended Translation: %sabled\n",
- (p->flags & EXTENDED_TRANSLATION) ? "En" : "Dis");
+ (p->flags & AHC_EXTEND_TRANS_A) ? "En" : "Dis");
size += sprintf(BLS, " SCSI Bus Reset: %sabled\n",
aic7xxx_no_reset ? "Dis" : "En");
- size += sprintf(BLS, " Ultra SCSI: %sabled\n",
- (p->flags & ULTRA_ENABLED) ? "En" : "Dis");
- size += sprintf(BLS, "Disconnect Enable Flags: 0x%x\n", p->discenable);
-
+ size += sprintf(BLS, "Disconnect Enable Flags: 0x%04x\n", p->discenable);
+ if (p->type & AHC_ULTRA)
+ {
+ size += sprintf(BLS, " Ultra Enable Flags: 0x%04x\n", p->ultraenb);
+ }
+ size += sprintf(BLS, " Tag Queue Enable Flags: 0x%04x\n", p->tagenable);
+ size += sprintf(BLS, "Ordered Queue Tag Flags: 0x%04x\n", p->orderedtag);
+#ifdef AIC7XXX_CMDS_PER_LUN
+ size += sprintf(BLS, "Default Tag Queue Depth: %d\n", AIC7XXX_CMDS_PER_LUN);
+#else
+ size += sprintf(BLS, "Default Tag Queue Depth: %d\n", 8);
+#endif
+ size += sprintf(BLS, " Tagged Queue By Device array for aic7xxx host "
+ "instance %d:\n", p->instance);
+ size += sprintf(BLS, " {");
+ for(i=0; i < (MAX_TARGETS - 1); i++)
+ size += sprintf(BLS, "%d,",aic7xxx_tag_info[p->instance].tag_commands[i]);
+ size += sprintf(BLS, "%d}\n",aic7xxx_tag_info[p->instance].tag_commands[i]);
+ size += sprintf(BLS, " Actual queue depth per device for aic7xxx host "
+ "instance %d:\n", p->instance);
+ size += sprintf(BLS, " {");
+ for(i=0; i < (MAX_TARGETS - 1); i++)
+ size += sprintf(BLS, "%d,", p->dev_max_queue_depth[i]);
+ size += sprintf(BLS, "%d}\n", p->dev_max_queue_depth[i]);
+
#ifdef AIC7XXX_PROC_STATS
size += sprintf(BLS, "\n");
size += sprintf(BLS, "Statistics:\n");
@@ -254,15 +282,15 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length,
{
continue;
}
- if (p->bus_type == AIC_TWIN)
+ if (p->type & AHC_TWIN)
{
- size += sprintf(BLS, "CHAN#%c (TGT %d LUN %d):\n",
- 'A' + (target >> 3), (target & 0x7), lun);
+ size += sprintf(BLS, "(scsi%d:%d:%d:%d)\n",
+ p->host_no, (target >> 3), (target & 0x7), lun);
}
else
{
- size += sprintf(BLS, "CHAN#%c (TGT %d LUN %d):\n",
- 'A', target, lun);
+ size += sprintf(BLS, "(scsi%d:%d:%d:%d)\n",
+ p->host_no, 0, target, lun);
}
size += sprintf(BLS, "nxfers %ld (%ld read;%ld written)\n",
sp->xfers, sp->r_total, sp->w_total);
diff --git a/drivers/scsi/aic7xxx_reg.h b/drivers/scsi/aic7xxx_reg.h
index 855a20441..a0682fd3e 100644
--- a/drivers/scsi/aic7xxx_reg.h
+++ b/drivers/scsi/aic7xxx_reg.h
@@ -30,13 +30,6 @@
#define ACTNEGEN 0x02
#define STPWEN 0x01
-#define SCSISIGI 0x03
-#define ATNI 0x10
-#define SELI 0x08
-#define BSYI 0x04
-#define REQI 0x02
-#define ACKI 0x01
-
#define SCSISIGO 0x03
#define CDO 0x80
#define IOO 0x40
@@ -47,6 +40,13 @@
#define REQO 0x02
#define ACKO 0x01
+#define SCSISIGI 0x03
+#define ATNI 0x10
+#define SELI 0x08
+#define BSYI 0x04
+#define REQI 0x02
+#define ACKI 0x01
+
#define SCSIRATE 0x04
#define WIDEXFER 0x80
#define SXFR 0x70
@@ -147,6 +147,16 @@
#define SELID_MASK 0xf0
#define ONEBIT 0x08
+#define SPIOCAP 0x1b
+#define SOFT1 0x80
+#define SOFT0 0x40
+#define SOFTCMDEN 0x20
+#define HAS_BRDCTL 0x10
+#define SEEPROM 0x08
+#define EEPROM 0x04
+#define ROM 0x02
+#define SSPIOCPS 0x01
+
#define BRDCTL 0x1d
#define BRDDAT7 0x80
#define BRDDAT6 0x40
@@ -181,11 +191,9 @@
#define DISC_DSB 0x32
-#define MSG_LEN 0x34
-
-#define MSG_OUT 0x35
+#define MSG_OUT 0x34
-#define DMAPARAMS 0x3d
+#define DMAPARAMS 0x35
#define WIDEODD 0x40
#define SCSIEN 0x20
#define SDMAENACK 0x10
@@ -196,36 +204,21 @@
#define FIFOFLUSH 0x02
#define FIFORESET 0x01
-#define SCBCOUNT 0x3e
-
-#define COMP_SCBCOUNT 0x3f
-
-#define QCNTMASK 0x40
-
-#define SEQ_FLAGS 0x41
-#define RESELECTED 0x80
-#define IDENTIFY_SEEN 0x40
-#define TAGGED_SCB 0x20
+#define SEQ_FLAGS 0x36
+#define IDENTIFY_SEEN 0x80
+#define SCBPTR_VALID 0x20
#define DPHASE 0x10
-#define PAGESCBS 0x04
+#define AMTARGET 0x08
#define WIDE_BUS 0x02
#define TWIN_BUS 0x01
-#define SAVED_TCL 0x42
-
-#define SG_COUNT 0x43
+#define SAVED_TCL 0x37
-#define SG_NEXT 0x44
+#define SG_COUNT 0x38
-#define WAITING_SCBH 0x48
+#define SG_NEXT 0x39
-#define SAVED_LINKPTR 0x49
-
-#define SAVED_SCBPTR 0x4a
-
-#define REJBYTE 0x4b
-
-#define LASTPHASE 0x4c
+#define LASTPHASE 0x3d
#define P_MESGIN 0xe0
#define PHASE_MASK 0xe0
#define P_STATUS 0xc0
@@ -238,40 +231,46 @@
#define P_BUSFREE 0x01
#define P_DATAOUT 0x00
-#define MSGIN_EXT_LEN 0x4d
+#define WAITING_SCBH 0x3e
+
+#define DISCONNECTED_SCBH 0x3f
-#define MSGIN_EXT_OPCODE 0x4e
+#define FREE_SCBH 0x40
-#define MSGIN_EXT_BYTES 0x4f
+#define HSCB_ADDR 0x41
-#define DISCONNECTED_SCBH 0x52
+#define SCBID_ADDR 0x45
-#define FREE_SCBH 0x53
+#define TMODE_CMDADDR 0x49
-#define HSCB_ADDR 0x54
+#define KERNEL_QINPOS 0x4d
-#define CUR_SCBID 0x58
+#define QINPOS 0x4e
-#define ARG_1 0x59
-#define RETURN_1 0x59
+#define QOUTPOS 0x4f
+
+#define TMODE_CMDADDR_NEXT 0x50
+
+#define ARG_1 0x51
+#define RETURN_1 0x51
#define SEND_MSG 0x80
#define SEND_SENSE 0x40
#define SEND_REJ 0x20
+#define MSGOUT_PHASEMIS 0x10
-#define SCSICONF 0x5a
-
-#define CMDOUTCNT 0x5a
+#define LAST_MSG 0x52
-#define SCSICONF2 0x5b
+#define SCSICONF 0x5a
+#define TERM_ENB 0x80
#define RESET_SCSI 0x40
-
-#define FIFODEPTH 0x5b
+#define HWSCSIID 0x0f
+#define HSCSIID 0x07
#define HOSTCONF 0x5d
#define HA_274_BIOSCTRL 0x5f
-#define BIOSDISABLED 0x30
#define BIOSMODE 0x30
+#define BIOSDISABLED 0x30
#define CHANNEL_B_PRIMARY 0x08
#define SEQCTL 0x60
@@ -315,16 +314,16 @@
#define STACK 0x6f
+#define BCTL 0x84
+#define ACE 0x08
+#define ENABLE 0x01
+
#define DSCOMMAND 0x84
#define CACHETHEN 0x80
#define DPARCKEN 0x40
#define MPARCKEN 0x20
#define EXTREQLCK 0x10
-#define BCTL 0x84
-#define ACE 0x08
-#define ENABLE 0x01
-
#define BUSTIME 0x85
#define BOFF 0xf0
#define BON 0x0f
@@ -356,13 +355,13 @@
#define SEQINT_MASK 0xf1
#define DATA_OVERRUN 0xe1
#define MSGIN_PHASEMIS 0xd1
-#define MSG_BUFFER_BUSY 0xc1
+#define TRACEPOINT2 0xc1
+#define TRACEPOINT 0xb1
#define AWAITING_MSG 0xa1
-#define ABORT_CMDCMPLT 0x91
#define RESIDUAL 0x81
#define BAD_STATUS 0x71
#define REJECT_MSG 0x61
-#define NO_MATCH_BUSY 0x51
+#define ABORT_REQUESTED 0x51
#define EXTENDED_MSG 0x41
#define NO_MATCH 0x31
#define NO_IDENT 0x21
@@ -374,18 +373,22 @@
#define BAD_PHASE 0x01
#define SEQINT 0x01
-#define ERROR 0x92
-#define PARERR 0x08
-#define ILLOPCODE 0x04
-#define ILLSADDR 0x02
-#define ILLHADDR 0x01
-
#define CLRINT 0x92
+#define CLRPARERR 0x10
#define CLRBRKADRINT 0x08
#define CLRSCSIINT 0x04
#define CLRCMDINT 0x02
#define CLRSEQINT 0x01
+#define ERROR 0x92
+#define PCIERRSTAT 0x40
+#define MPARERR 0x20
+#define DPARERR 0x10
+#define SQPARERR 0x08
+#define ILLOPCODE 0x04
+#define ILLSADDR 0x02
+#define ILLHADDR 0x01
+
#define DFCNTRL 0x93
#define DFSTATUS 0x94
@@ -410,17 +413,15 @@
#define QOUTCNT 0x9e
-#define SCB_BASE 0xa0
-
#define SCB_CONTROL 0xa0
#define MK_MESSAGE 0x80
#define DISCENB 0x40
#define TAG_ENB 0x20
-#define MUST_DMAUP_SCB 0x10
-#define ABORT_SCB 0x08
#define DISCONNECTED 0x04
#define SCB_TAG_TYPE 0x03
+#define SCB_BASE 0xa0
+
#define SCB_TCL 0xa1
#define TID 0xf0
#define SELBUSB 0x08
@@ -440,8 +441,6 @@
#define SCB_DATACNT 0xb0
-#define SCB_LINKED_NEXT 0xb3
-
#define SCB_CMDPTR 0xb4
#define SCB_CMDLEN 0xb8
@@ -466,10 +465,24 @@
#define DI_2840 0x01
-#define MAX_OFFSET_16BIT 0x08
+#define CMD_GROUP_CODE_SHIFT 0x05
#define BUS_8_BIT 0x00
+#define QOUTFIFO_OFFSET 0x01
+#define CMD_GROUP2_BYTE_DELTA 0xfa
+#define MAX_OFFSET_8BIT 0x0f
+#define BUS_16_BIT 0x01
+#define QINFIFO_OFFSET 0x02
+#define CMD_GROUP5_BYTE_DELTA 0x0b
+#define MAX_OFFSET_16BIT 0x08
+#define UNTAGGEDSCB_OFFSET 0x00
#define SCB_LIST_NULL 0xff
#define SG_SIZEOF 0x08
-#define MAX_OFFSET_8BIT 0x0f
+#define CMD_GROUP4_BYTE_DELTA 0x04
+#define CMD_GROUP0_BYTE_DELTA 0xfc
+#define HOST_MSG 0xff
#define BUS_32_BIT 0x02
-#define BUS_16_BIT 0x01
+
+
+/* Downloaded Constant Definitions */
+#define TMODE_NUMCMDS 0x01
+#define QCNTMASK 0x00
diff --git a/drivers/scsi/aic7xxx_seq.h b/drivers/scsi/aic7xxx_seq.h
index 78359fb4e..2721f6bcd 100644
--- a/drivers/scsi/aic7xxx_seq.h
+++ b/drivers/scsi/aic7xxx_seq.h
@@ -1,54 +1,39 @@
/*
* DO NOT EDIT - This file is automatically generated.
*/
-static u_int8_t seqprog[] = {
+static unsigned char seqprog[] = {
0xff, 0x6a, 0x03, 0x02,
+ 0x32, 0x6a, 0x00, 0x00,
0x12, 0x6a, 0x00, 0x00,
- 0x00, 0x65, 0x6f, 0x16,
- 0x40, 0x0b, 0x3c, 0x1a,
- 0x20, 0x0b, 0x37, 0x1a,
- 0x40, 0x00, 0x03, 0x1a,
+ 0x00, 0x65, 0x92, 0x16,
+ 0xf7, 0x01, 0x01, 0x02,
+ 0xff, 0x4e, 0x64, 0x02,
+ 0xbf, 0x60, 0x60, 0x02,
+ 0x60, 0x0b, 0x37, 0x1a,
+ 0x40, 0x00, 0x05, 0x1a,
0x08, 0x1f, 0x1f, 0x04,
- 0x40, 0x0b, 0x3c, 0x1a,
- 0x20, 0x0b, 0x37, 0x1a,
- 0x40, 0x00, 0x03, 0x1a,
+ 0x60, 0x0b, 0x37, 0x1a,
+ 0x40, 0x00, 0x05, 0x1a,
0x08, 0x1f, 0x1f, 0x04,
- 0xff, 0x48, 0x2c, 0x18,
- 0xff, 0x40, 0x64, 0x02,
- 0x00, 0x9c, 0x03, 0x1e,
- 0x00, 0x6a, 0xad, 0x17,
- 0xff, 0x65, 0x03, 0x1c,
- 0xff, 0x9b, 0x58, 0x02,
- 0xff, 0x58, 0x90, 0x02,
- 0x0d, 0x6a, 0x3d, 0x00,
- 0x00, 0x58, 0x77, 0x17,
- 0x28, 0xa0, 0x2a, 0x1a,
- 0x50, 0x6a, 0x60, 0x00,
- 0xff, 0x90, 0x4a, 0x02,
- 0x00, 0xa1, 0xa1, 0x17,
- 0xff, 0x6c, 0x59, 0x02,
- 0xff, 0x59, 0x27, 0x1c,
- 0xff, 0x4a, 0x90, 0x02,
- 0x00, 0x65, 0xaa, 0x17,
- 0x00, 0x6a, 0x52, 0x17,
- 0xff, 0x65, 0x1f, 0x18,
- 0x51, 0x6a, 0x91, 0x00,
- 0xff, 0x58, 0xb3, 0x02,
- 0x00, 0x65, 0xbb, 0x17,
- 0x10, 0x6a, 0x60, 0x00,
- 0x00, 0x65, 0x03, 0x10,
- 0xff, 0x59, 0x90, 0x02,
- 0xff, 0x58, 0xb3, 0x02,
- 0x10, 0x6a, 0x60, 0x00,
- 0x00, 0x65, 0x03, 0x10,
- 0xff, 0x58, 0x6d, 0x02,
- 0xff, 0x4a, 0x90, 0x02,
- 0x10, 0x6a, 0x60, 0x00,
- 0xff, 0x48, 0xba, 0x02,
- 0xff, 0x90, 0x48, 0x02,
- 0xff, 0x48, 0x90, 0x02,
- 0x00, 0x65, 0x2f, 0x16,
- 0x00, 0x65, 0x03, 0x10,
+ 0xff, 0x3e, 0x1d, 0x18,
+ 0x40, 0x60, 0x60, 0x00,
+ 0x00, 0x4d, 0x06, 0x1c,
+ 0x01, 0x4e, 0x4e, 0x06,
+ 0xbf, 0x60, 0x60, 0x02,
+ 0x00, 0x6a, 0xd8, 0x17,
+ 0xff, 0x4e, 0x64, 0x06,
+ 0x02, 0x6a, 0x93, 0x17,
+ 0x0d, 0x6a, 0x93, 0x00,
+ 0x00, 0x65, 0xd1, 0x17,
+ 0xff, 0x99, 0x65, 0x02,
+ 0xff, 0x65, 0x90, 0x02,
+ 0x0d, 0x6a, 0x35, 0x00,
+ 0x00, 0x65, 0xb3, 0x17,
+ 0xff, 0x3e, 0xba, 0x02,
+ 0xff, 0x90, 0x3e, 0x02,
+ 0xff, 0x3e, 0x90, 0x02,
+ 0x00, 0x65, 0x20, 0x16,
+ 0x00, 0x65, 0x05, 0x10,
0xf7, 0x1f, 0x65, 0x02,
0x08, 0xa1, 0x64, 0x02,
0x00, 0x65, 0x65, 0x00,
@@ -57,316 +42,381 @@ static u_int8_t seqprog[] = {
0x0f, 0x05, 0x05, 0x02,
0x00, 0x05, 0x05, 0x00,
0x5a, 0x6a, 0x00, 0x01,
- 0xff, 0x6a, 0x34, 0x02,
- 0x20, 0x6a, 0x0b, 0x00,
- 0xf0, 0x19, 0x42, 0x02,
- 0x80, 0x41, 0x41, 0x00,
- 0x00, 0x65, 0x4c, 0x10,
- 0x12, 0x6a, 0x00, 0x00,
- 0x40, 0x6a, 0x0b, 0x00,
- 0xff, 0x48, 0x90, 0x02,
- 0xff, 0xba, 0x48, 0x02,
- 0xff, 0xa1, 0x42, 0x02,
- 0x07, 0xa1, 0x35, 0x02,
- 0x40, 0xa0, 0x64, 0x02,
- 0x00, 0x35, 0x35, 0x00,
- 0x80, 0x35, 0x35, 0x00,
- 0x01, 0x6a, 0x34, 0x00,
- 0x20, 0xa0, 0x4a, 0x1e,
- 0x23, 0xa0, 0x36, 0x02,
- 0xff, 0xb9, 0x37, 0x02,
- 0x02, 0x34, 0x34, 0x06,
- 0x80, 0xa0, 0x4c, 0x1e,
- 0xa1, 0x6a, 0x91, 0x00,
- 0x08, 0x6a, 0x0c, 0x00,
- 0x08, 0x11, 0x11, 0x00,
- 0x1a, 0x01, 0x01, 0x00,
+ 0x12, 0x65, 0x64, 0x00,
+ 0x00, 0x01, 0x01, 0x00,
0x31, 0x6a, 0x65, 0x00,
- 0x80, 0x42, 0x52, 0x1a,
+ 0x80, 0x37, 0x2d, 0x1a,
0xff, 0x65, 0x65, 0x06,
- 0xff, 0x42, 0x6e, 0x02,
+ 0xff, 0x37, 0x6e, 0x02,
0xff, 0x6e, 0x64, 0x02,
- 0x00, 0x6c, 0x56, 0x1e,
+ 0x00, 0x6c, 0x31, 0x1e,
0x20, 0x01, 0x01, 0x00,
- 0x4c, 0x42, 0x64, 0x0a,
- 0x08, 0x1f, 0x5a, 0x1e,
- 0x08, 0x42, 0x42, 0x00,
+ 0x4c, 0x37, 0x64, 0x0a,
+ 0x08, 0x1f, 0x35, 0x1e,
+ 0x08, 0x37, 0x37, 0x00,
0x08, 0x64, 0x64, 0x00,
0x20, 0x64, 0x65, 0x06,
- 0xff, 0x6c, 0x04, 0x02,
- 0x01, 0x0c, 0x5c, 0x1e,
- 0x04, 0x0c, 0x5c, 0x1a,
- 0xe0, 0x03, 0x64, 0x02,
- 0xff, 0x64, 0x4c, 0x02,
- 0xff, 0x64, 0x03, 0x02,
- 0x00, 0x6a, 0x74, 0x1c,
- 0x40, 0x64, 0x79, 0x1c,
- 0x80, 0x64, 0xa5, 0x1c,
- 0xa0, 0x64, 0xb0, 0x1c,
- 0xc0, 0x64, 0xad, 0x1c,
- 0xe0, 0x64, 0xc3, 0x1c,
+ 0xff, 0x6c, 0x04, 0x03,
+ 0x40, 0x0b, 0x78, 0x1a,
+ 0x80, 0x0b, 0x71, 0x1e,
+ 0xa4, 0x6a, 0x03, 0x00,
+ 0x40, 0x6a, 0x0b, 0x00,
+ 0x10, 0x03, 0x6f, 0x1e,
+ 0xff, 0x50, 0x64, 0x02,
+ 0x49, 0x6a, 0xa9, 0x17,
+ 0x01, 0x6a, 0x93, 0x00,
+ 0xff, 0x6a, 0x65, 0x02,
+ 0x08, 0x01, 0x01, 0x00,
+ 0x02, 0x0b, 0x41, 0x1e,
+ 0xf7, 0x01, 0x01, 0x02,
+ 0xff, 0x06, 0x66, 0x02,
+ 0xff, 0x66, 0x99, 0x02,
+ 0x01, 0x65, 0x65, 0x06,
+ 0x80, 0x66, 0x48, 0x1e,
+ 0xff, 0x66, 0x51, 0x02,
+ 0x10, 0x03, 0x40, 0x1a,
+ 0xfc, 0x65, 0x64, 0x06,
+ 0x00, 0x65, 0x4c, 0x12,
+ 0xff, 0x6a, 0x99, 0x00,
+ 0x01, 0x64, 0x8c, 0x06,
+ 0x84, 0x6a, 0x03, 0x00,
+ 0x08, 0x01, 0x01, 0x00,
+ 0x02, 0x0b, 0x4f, 0x1e,
+ 0xff, 0x06, 0x64, 0x02,
+ 0xff, 0x64, 0x99, 0x02,
+ 0xff, 0x6a, 0x65, 0x02,
+ 0x5b, 0x64, 0x64, 0x0a,
+ 0x00, 0x62, 0x62, 0x06,
+ 0xfc, 0x65, 0x65, 0x06,
+ 0xff, 0x6a, 0x6a, 0x02,
+ 0xfa, 0x65, 0x65, 0x06,
+ 0xff, 0x6a, 0x6a, 0x02,
+ 0x04, 0x65, 0x65, 0x06,
+ 0x0b, 0x65, 0x65, 0x06,
+ 0xff, 0x65, 0x64, 0x02,
+ 0x00, 0x8c, 0x8c, 0x06,
+ 0x02, 0x0b, 0x5d, 0x1e,
+ 0x01, 0x65, 0x60, 0x18,
+ 0xf7, 0x01, 0x01, 0x02,
+ 0xff, 0x06, 0x99, 0x02,
+ 0xff, 0x65, 0x65, 0x06,
+ 0xff, 0x65, 0x5d, 0x1a,
+ 0x0a, 0x93, 0x93, 0x00,
+ 0x00, 0x65, 0xd1, 0x17,
+ 0x40, 0x51, 0x69, 0x1e,
+ 0xe4, 0x6a, 0x03, 0x00,
+ 0x08, 0x01, 0x01, 0x00,
+ 0x04, 0x6a, 0x5c, 0x17,
+ 0x01, 0x50, 0x50, 0x06,
+ 0x01, 0x50, 0x6c, 0x98,
+ 0xff, 0x6a, 0x50, 0x02,
+ 0xff, 0x6a, 0x9d, 0x00,
+ 0x02, 0x6a, 0x91, 0x00,
+ 0x40, 0x51, 0x6f, 0x1a,
+ 0xff, 0x6a, 0x03, 0x02,
+ 0x00, 0x65, 0x05, 0x10,
+ 0x20, 0x6a, 0x0b, 0x00,
+ 0xf0, 0x19, 0x37, 0x02,
+ 0x08, 0x6a, 0x0c, 0x00,
+ 0x08, 0x11, 0x11, 0x00,
+ 0x08, 0x6a, 0x28, 0x16,
+ 0x08, 0x6a, 0x34, 0x00,
+ 0x00, 0x65, 0x82, 0x10,
+ 0x12, 0x6a, 0x00, 0x00,
+ 0x40, 0x6a, 0x0b, 0x00,
+ 0xff, 0x3e, 0x90, 0x02,
+ 0xff, 0xba, 0x3e, 0x02,
+ 0xff, 0xa1, 0x37, 0x02,
+ 0x08, 0x6a, 0x0c, 0x00,
+ 0x08, 0x11, 0x11, 0x00,
+ 0x08, 0x6a, 0x28, 0x16,
+ 0x80, 0x6a, 0x34, 0x00,
+ 0x80, 0x36, 0x36, 0x00,
+ 0x00, 0x65, 0x9b, 0x17,
+ 0xff, 0x3d, 0x64, 0x02,
+ 0xbf, 0x64, 0x9a, 0x1e,
+ 0x80, 0x64, 0xc9, 0x1c,
+ 0xa0, 0x64, 0xd4, 0x1c,
+ 0xc0, 0x64, 0xd1, 0x1c,
+ 0xe0, 0x64, 0xf5, 0x1c,
0x01, 0x6a, 0x91, 0x00,
- 0x00, 0x65, 0x5c, 0x10,
+ 0x00, 0x65, 0x82, 0x10,
0xf7, 0x11, 0x11, 0x02,
- 0x00, 0x65, 0x6f, 0x16,
+ 0x00, 0x65, 0x92, 0x16,
0xff, 0x06, 0x6a, 0x02,
- 0x09, 0x0c, 0x6c, 0x1e,
- 0x08, 0x0c, 0x03, 0x1a,
+ 0xf7, 0x01, 0x01, 0x02,
+ 0x09, 0x0c, 0x8f, 0x1e,
+ 0x08, 0x0c, 0x05, 0x1a,
0x01, 0x6a, 0x91, 0x00,
0xff, 0x6a, 0x93, 0x02,
0xff, 0x6a, 0x04, 0x02,
0xdf, 0x01, 0x01, 0x02,
- 0x01, 0x6a, 0x4c, 0x00,
- 0x0f, 0x41, 0x41, 0x03,
- 0x7d, 0x6a, 0x3d, 0x00,
- 0x00, 0x65, 0x7a, 0x10,
+ 0x01, 0x6a, 0x3d, 0x00,
+ 0x03, 0x36, 0x36, 0x03,
0x08, 0x6a, 0x66, 0x00,
- 0xa9, 0x6a, 0x74, 0x17,
- 0x00, 0x65, 0x82, 0x10,
- 0x79, 0x6a, 0x3d, 0x00,
- 0x00, 0x65, 0x4f, 0x17,
- 0x10, 0x41, 0x76, 0x1a,
+ 0xa9, 0x6a, 0xa6, 0x17,
+ 0x00, 0x65, 0xa5, 0x10,
+ 0x79, 0x6a, 0x35, 0x00,
+ 0x40, 0x3d, 0x9d, 0x1a,
+ 0x04, 0x35, 0x35, 0x00,
+ 0x00, 0x65, 0x6c, 0x17,
+ 0x10, 0x36, 0x97, 0x1a,
0x88, 0x6a, 0x66, 0x00,
- 0xac, 0x6a, 0x70, 0x17,
- 0x00, 0x65, 0x6d, 0x17,
- 0xff, 0xa3, 0x43, 0x02,
- 0x44, 0x6a, 0x66, 0x00,
- 0xa4, 0x6a, 0x73, 0x17,
- 0xff, 0x43, 0x88, 0x1a,
+ 0xac, 0x6a, 0xa2, 0x17,
+ 0x00, 0x65, 0x9f, 0x17,
+ 0xff, 0xa3, 0x38, 0x02,
+ 0x39, 0x6a, 0x66, 0x00,
+ 0xa4, 0x6a, 0xa5, 0x17,
+ 0xff, 0x38, 0xac, 0x1a,
0x80, 0x02, 0x02, 0x00,
0xff, 0x6a, 0x8c, 0x00,
0xff, 0x6a, 0x8d, 0x00,
0xff, 0x6a, 0x8e, 0x00,
- 0x00, 0x65, 0x6d, 0x17,
- 0x01, 0x43, 0x8a, 0x18,
- 0xbf, 0x3d, 0x3d, 0x02,
- 0x00, 0x3d, 0x44, 0x17,
- 0x80, 0x02, 0xa2, 0x1a,
- 0xff, 0x65, 0x9c, 0x1e,
- 0xff, 0x43, 0x43, 0x06,
- 0xff, 0x43, 0x9c, 0x1e,
+ 0x00, 0x65, 0x9f, 0x17,
+ 0xe7, 0x35, 0x35, 0x02,
+ 0x01, 0x38, 0xae, 0x18,
+ 0xbf, 0x35, 0x35, 0x02,
+ 0x00, 0x35, 0x61, 0x17,
+ 0x80, 0x02, 0xc6, 0x1a,
+ 0xff, 0x65, 0xc0, 0x1e,
+ 0xff, 0x38, 0x38, 0x06,
+ 0xff, 0x38, 0xc0, 0x1e,
0xff, 0x6a, 0x64, 0x02,
- 0x08, 0x44, 0x44, 0x06,
- 0x00, 0x45, 0x45, 0x08,
+ 0x08, 0x39, 0x39, 0x06,
+ 0x00, 0x3a, 0x3a, 0x08,
0x88, 0x6a, 0x66, 0x00,
- 0x44, 0x6a, 0x73, 0x17,
+ 0x39, 0x6a, 0xa5, 0x17,
0x08, 0x6a, 0x8c, 0x00,
0xff, 0x6a, 0x8d, 0x02,
0xff, 0x6a, 0x8e, 0x02,
0x0d, 0x93, 0x93, 0x00,
- 0x00, 0x65, 0x9d, 0x17,
- 0x88, 0x6a, 0x95, 0x17,
- 0x00, 0x65, 0x6d, 0x17,
- 0x10, 0x0c, 0x82, 0x1e,
+ 0x00, 0x65, 0xd1, 0x17,
+ 0x88, 0x6a, 0xc9, 0x17,
+ 0x00, 0x65, 0x9f, 0x17,
+ 0x10, 0x0c, 0xa5, 0x1e,
0xff, 0x08, 0xa9, 0x02,
0xff, 0x09, 0xaa, 0x02,
0xff, 0x0a, 0xab, 0x02,
- 0xff, 0x43, 0xa8, 0x02,
- 0x10, 0x41, 0x41, 0x00,
- 0x00, 0x65, 0x5c, 0x10,
+ 0xff, 0x38, 0xa8, 0x02,
+ 0x10, 0x36, 0x36, 0x00,
+ 0x00, 0x65, 0x82, 0x10,
0x7f, 0x02, 0x02, 0x02,
0xe1, 0x6a, 0x91, 0x00,
- 0x00, 0x65, 0x5c, 0x10,
- 0x00, 0x65, 0x4f, 0x17,
+ 0x00, 0x65, 0x82, 0x10,
+ 0x00, 0x65, 0x6c, 0x17,
0x88, 0x6a, 0x66, 0x00,
- 0xb4, 0x6a, 0x72, 0x17,
+ 0xb4, 0x6a, 0xa4, 0x17,
0xff, 0x6a, 0x8d, 0x02,
0xff, 0x6a, 0x8e, 0x02,
- 0x00, 0x65, 0x6d, 0x17,
- 0x3d, 0x6a, 0x44, 0x17,
- 0x00, 0x65, 0x5c, 0x10,
- 0x00, 0x65, 0x4f, 0x17,
+ 0x00, 0x65, 0x9f, 0x17,
+ 0x3d, 0x6a, 0x61, 0x17,
+ 0x00, 0x65, 0x82, 0x10,
+ 0x00, 0x65, 0x6c, 0x17,
0xff, 0x06, 0xa2, 0x02,
- 0x00, 0x65, 0x5c, 0x10,
- 0xff, 0x34, 0xb2, 0x1a,
- 0x08, 0x6a, 0x32, 0x17,
- 0x35, 0x6a, 0x65, 0x00,
- 0xff, 0x34, 0x66, 0x02,
- 0x01, 0x0c, 0xb4, 0x1e,
- 0x04, 0x0c, 0xb4, 0x1a,
- 0xe0, 0x03, 0x4c, 0x02,
- 0xa0, 0x4c, 0xc0, 0x18,
- 0xff, 0x66, 0xbb, 0x1a,
- 0x10, 0x4c, 0x03, 0x00,
- 0x00, 0x65, 0xb2, 0x10,
- 0x01, 0x66, 0xbd, 0x18,
+ 0x00, 0x65, 0x82, 0x10,
+ 0xff, 0x34, 0x65, 0x02,
+ 0x80, 0x65, 0xe6, 0x18,
+ 0x0f, 0xa1, 0x65, 0x02,
+ 0x07, 0xa1, 0x65, 0x02,
+ 0x40, 0xa0, 0x64, 0x02,
+ 0x00, 0x65, 0x65, 0x00,
+ 0x80, 0x65, 0x65, 0x00,
+ 0x80, 0xa0, 0xde, 0x1e,
+ 0xff, 0x65, 0x06, 0x02,
+ 0x00, 0x65, 0xe7, 0x10,
+ 0x20, 0xa0, 0xe9, 0x1e,
+ 0xff, 0x65, 0x06, 0x02,
+ 0x00, 0x65, 0x9b, 0x17,
+ 0xa0, 0x3d, 0xef, 0x18,
+ 0x23, 0xa0, 0x06, 0x02,
+ 0x00, 0x65, 0x9b, 0x17,
+ 0xa0, 0x3d, 0xef, 0x18,
+ 0x00, 0xb9, 0xe9, 0x10,
+ 0xff, 0x65, 0xe9, 0x18,
+ 0xa1, 0x6a, 0x91, 0x00,
+ 0x10, 0x51, 0xef, 0x1c,
0x40, 0x6a, 0x0c, 0x00,
- 0xff, 0x66, 0x66, 0x06,
- 0xff, 0x6c, 0x06, 0x02,
- 0x00, 0x65, 0xb4, 0x10,
+ 0xff, 0x65, 0x06, 0x02,
+ 0x00, 0x65, 0x9b, 0x17,
+ 0xa0, 0x3d, 0xef, 0x18,
+ 0x10, 0x3d, 0x03, 0x00,
+ 0x00, 0x65, 0xd4, 0x10,
0x40, 0x6a, 0x0c, 0x00,
- 0xff, 0x6a, 0x34, 0x02,
- 0x00, 0x65, 0x5c, 0x10,
- 0x64, 0x6a, 0x3f, 0x17,
- 0xff, 0x64, 0x4b, 0x02,
- 0x80, 0x64, 0x0e, 0x1b,
- 0x04, 0x64, 0x01, 0x1d,
- 0x02, 0x64, 0x04, 0x1d,
- 0x00, 0x6a, 0xd1, 0x1c,
- 0x03, 0x64, 0x0c, 0x1d,
- 0x01, 0x64, 0xf5, 0x1c,
- 0x07, 0x64, 0x30, 0x1d,
- 0x08, 0x64, 0xcf, 0x1c,
+ 0xff, 0x34, 0x52, 0x02,
+ 0x80, 0x34, 0xf3, 0x18,
+ 0x7f, 0xa0, 0xa0, 0x02,
+ 0x08, 0x6a, 0x34, 0x00,
+ 0x00, 0x65, 0x82, 0x10,
+ 0x64, 0x6a, 0x59, 0x17,
+ 0x80, 0x64, 0x2f, 0x1b,
+ 0x04, 0x64, 0x22, 0x1d,
+ 0x02, 0x64, 0x25, 0x1d,
+ 0x00, 0x6a, 0x02, 0x1d,
+ 0x03, 0x64, 0x2d, 0x1d,
+ 0x01, 0x64, 0x20, 0x1d,
+ 0x07, 0x64, 0x50, 0x1d,
+ 0x08, 0x64, 0x00, 0x1d,
0x11, 0x6a, 0x91, 0x00,
- 0x07, 0x6a, 0x32, 0x17,
+ 0x07, 0x6a, 0x52, 0x17,
0xff, 0x06, 0x6a, 0x02,
- 0x00, 0x65, 0x5c, 0x10,
- 0xff, 0xa8, 0xd3, 0x1a,
- 0xff, 0xa2, 0xda, 0x1e,
- 0x01, 0x6a, 0x3d, 0x00,
- 0x00, 0xb9, 0x77, 0x17,
- 0xff, 0xa2, 0xda, 0x1e,
+ 0x00, 0x65, 0x82, 0x10,
+ 0xff, 0xa8, 0x04, 0x1b,
+ 0xff, 0xa2, 0x0f, 0x1f,
+ 0x01, 0x6a, 0x35, 0x00,
+ 0x00, 0xb9, 0xb3, 0x17,
+ 0xff, 0xa2, 0x0f, 0x1f,
0x71, 0x6a, 0x91, 0x00,
- 0x40, 0x59, 0xda, 0x18,
- 0xff, 0xb9, 0xb3, 0x02,
- 0x00, 0x65, 0xe7, 0x10,
- 0x20, 0xa0, 0xe0, 0x1a,
- 0xff, 0x90, 0x4a, 0x02,
- 0xff, 0xb3, 0x49, 0x02,
- 0x00, 0xa1, 0xa1, 0x17,
- 0xff, 0x49, 0x6d, 0x02,
- 0xff, 0x4a, 0x90, 0x02,
- 0xff, 0x5b, 0x64, 0x02,
- 0x00, 0x5a, 0xe1, 0x1c,
- 0x01, 0x5a, 0x5a, 0x06,
- 0xff, 0xb9, 0x9d, 0x02,
+ 0x40, 0x51, 0x0f, 0x19,
+ 0x0d, 0x6a, 0x35, 0x00,
+ 0x00, 0xb9, 0xb3, 0x17,
+ 0xff, 0x3e, 0xba, 0x02,
+ 0xff, 0x90, 0x3e, 0x02,
+ 0x00, 0x65, 0x20, 0x16,
+ 0x00, 0x65, 0x8b, 0x10,
+ 0x20, 0xa0, 0x16, 0x1b,
+ 0xff, 0x37, 0x64, 0x02,
+ 0x00, 0x6a, 0x93, 0x17,
+ 0x01, 0x6a, 0x93, 0x00,
+ 0xff, 0x6a, 0x99, 0x00,
+ 0x0a, 0x93, 0x93, 0x00,
+ 0x00, 0x65, 0xd1, 0x17,
+ 0xff, 0x4f, 0x64, 0x02,
+ 0x01, 0x6a, 0x93, 0x17,
+ 0x01, 0x6a, 0x93, 0x00,
+ 0xff, 0xb9, 0x99, 0x02,
+ 0x0a, 0x93, 0x93, 0x00,
+ 0x00, 0x65, 0xd1, 0x17,
+ 0x01, 0x4f, 0x4f, 0x06,
0x02, 0x6a, 0x91, 0x00,
- 0x08, 0xa0, 0xe7, 0x1e,
- 0x91, 0x6a, 0x91, 0x00,
- 0xff, 0xb3, 0xf3, 0x1c,
- 0xff, 0xb3, 0x64, 0x02,
- 0x00, 0xb9, 0xed, 0x1c,
- 0x00, 0x65, 0xaa, 0x17,
- 0xff, 0x64, 0x90, 0x02,
- 0x00, 0x65, 0xef, 0x10,
- 0x0d, 0x6a, 0x3d, 0x00,
- 0x00, 0xb3, 0x77, 0x17,
- 0xff, 0x48, 0xba, 0x02,
- 0xff, 0x90, 0x48, 0x02,
- 0x00, 0x65, 0x2f, 0x16,
- 0x00, 0x65, 0x69, 0x10,
- 0x00, 0x65, 0xaa, 0x17,
- 0x00, 0x65, 0x69, 0x10,
- 0x4d, 0x6a, 0x3a, 0x17,
- 0xff, 0x4d, 0x64, 0x02,
- 0x00, 0x66, 0x3a, 0x17,
- 0xff, 0x64, 0x64, 0x06,
- 0x52, 0x66, 0xfb, 0x18,
- 0xff, 0x66, 0x66, 0x06,
- 0xff, 0x64, 0xf7, 0x1a,
+ 0x00, 0x65, 0xd5, 0x17,
+ 0x00, 0x65, 0x8b, 0x10,
0x41, 0x6a, 0x91, 0x00,
- 0x20, 0x59, 0xcd, 0x1c,
- 0x80, 0x59, 0xcf, 0x18,
- 0x10, 0x4c, 0x03, 0x00,
- 0x00, 0x65, 0xcf, 0x10,
+ 0x00, 0x65, 0x82, 0x10,
0x04, 0xa0, 0xa0, 0x00,
- 0x00, 0x65, 0xbb, 0x17,
- 0x00, 0x65, 0x69, 0x10,
- 0x10, 0x41, 0xcf, 0x1e,
- 0xff, 0x43, 0xa3, 0x02,
+ 0x00, 0x65, 0xe1, 0x17,
+ 0x00, 0x65, 0x8b, 0x10,
+ 0x10, 0x36, 0x00, 0x1f,
+ 0xff, 0x38, 0xa3, 0x02,
0xa4, 0x6a, 0x66, 0x00,
- 0x44, 0x6a, 0x73, 0x17,
+ 0x39, 0x6a, 0xa5, 0x17,
0xac, 0x6a, 0x66, 0x00,
- 0x14, 0x6a, 0x73, 0x17,
- 0xa9, 0x6a, 0x74, 0x17,
- 0x00, 0x65, 0xcf, 0x10,
- 0xef, 0x41, 0x41, 0x02,
- 0x00, 0x65, 0xcf, 0x10,
- 0x78, 0x64, 0xcd, 0x1a,
+ 0x14, 0x6a, 0xa5, 0x17,
+ 0xa9, 0x6a, 0xa6, 0x17,
+ 0x00, 0x65, 0x00, 0x11,
+ 0xef, 0x36, 0x36, 0x02,
+ 0x00, 0x65, 0x00, 0x11,
+ 0x0f, 0x64, 0x64, 0x02,
0x07, 0x64, 0x64, 0x02,
- 0x00, 0x42, 0x42, 0x00,
- 0x00, 0x42, 0xa1, 0x17,
- 0xff, 0x6c, 0x59, 0x02,
- 0xff, 0x59, 0x28, 0x19,
- 0xff, 0x59, 0x18, 0x1d,
- 0xff, 0x59, 0x90, 0x02,
- 0x04, 0xa0, 0x2d, 0x1f,
- 0x00, 0x65, 0x2a, 0x11,
+ 0x00, 0x37, 0x37, 0x00,
+ 0x00, 0x65, 0x8b, 0x17,
+ 0xff, 0x51, 0x37, 0x1d,
+ 0x20, 0x36, 0x3f, 0x1f,
+ 0x00, 0x90, 0x7d, 0x17,
+ 0x00, 0x65, 0x40, 0x11,
0xff, 0x06, 0x6a, 0x02,
- 0x01, 0x0c, 0x19, 0x1f,
- 0x04, 0x0c, 0x19, 0x1b,
- 0xe0, 0x03, 0x4c, 0x02,
- 0xe0, 0x4c, 0x2d, 0x19,
- 0x20, 0x12, 0x2d, 0x19,
- 0x20, 0x41, 0x41, 0x00,
- 0x59, 0x6a, 0x3a, 0x17,
- 0xff, 0x3f, 0x64, 0x02,
- 0x00, 0x59, 0x65, 0x06,
- 0x00, 0x65, 0x2d, 0x13,
- 0xff, 0x59, 0x90, 0x02,
- 0xff, 0x42, 0x64, 0x02,
- 0x00, 0xa1, 0x2d, 0x19,
- 0x20, 0xa0, 0x2d, 0x1f,
- 0x04, 0xa0, 0x2d, 0x1f,
- 0x00, 0x6a, 0x52, 0x17,
- 0xff, 0x65, 0x2d, 0x1d,
+ 0x00, 0x65, 0x9b, 0x17,
+ 0xe0, 0x3d, 0x4d, 0x19,
+ 0x20, 0x12, 0x4d, 0x19,
+ 0x51, 0x6a, 0x54, 0x17,
+ 0xff, 0x51, 0x90, 0x02,
+ 0x20, 0xa0, 0x4d, 0x1f,
+ 0x00, 0x90, 0x7d, 0x17,
+ 0x00, 0x65, 0x7a, 0x17,
+ 0xff, 0x37, 0x64, 0x02,
+ 0x00, 0xa1, 0x49, 0x19,
+ 0x04, 0xa0, 0x49, 0x1f,
0xfb, 0xa0, 0xa0, 0x02,
- 0x40, 0x41, 0x41, 0x00,
- 0x00, 0x65, 0xcf, 0x10,
+ 0x80, 0x36, 0x36, 0x00,
+ 0x80, 0xa0, 0x00, 0x1f,
+ 0x7f, 0xa0, 0xa0, 0x02,
+ 0xff, 0x6a, 0x52, 0x17,
+ 0x00, 0x65, 0x00, 0x11,
+ 0x04, 0xa0, 0x4c, 0x1f,
+ 0x00, 0x65, 0xe1, 0x17,
+ 0x00, 0x65, 0x4d, 0x11,
+ 0x00, 0x65, 0xd5, 0x17,
0x31, 0x6a, 0x91, 0x00,
- 0x0c, 0x6a, 0x32, 0x17,
- 0x00, 0x65, 0xcf, 0x10,
+ 0x0c, 0x6a, 0x52, 0x17,
+ 0x00, 0x65, 0x00, 0x11,
0x61, 0x6a, 0x91, 0x00,
- 0x00, 0x65, 0xcf, 0x10,
- 0x50, 0x6a, 0x60, 0x00,
- 0xff, 0x34, 0x36, 0x1f,
- 0x10, 0x6a, 0x60, 0x00,
- 0xc1, 0x6a, 0x91, 0x00,
- 0x10, 0x4c, 0x03, 0x00,
- 0x01, 0x6a, 0x34, 0x00,
- 0xff, 0x65, 0x35, 0x02,
- 0x10, 0x6a, 0x60, 0x01,
+ 0x00, 0x65, 0x00, 0x11,
+ 0x10, 0x3d, 0x03, 0x00,
+ 0xff, 0x65, 0x34, 0x03,
0xff, 0x06, 0x6a, 0x02,
- 0x01, 0x0c, 0x3b, 0x1f,
- 0x04, 0x0c, 0x3b, 0x1b,
- 0xe0, 0x03, 0x4c, 0x02,
- 0xe0, 0x4c, 0x42, 0x19,
+ 0x01, 0x0c, 0x55, 0x1f,
+ 0x04, 0x0c, 0x55, 0x1b,
+ 0xe0, 0x03, 0x3d, 0x02,
+ 0xe0, 0x3d, 0x5f, 0x19,
0xff, 0x65, 0x66, 0x02,
0xff, 0x12, 0x6d, 0x03,
0xff, 0x06, 0x6a, 0x03,
+ 0xff, 0x65, 0x06, 0x02,
+ 0x02, 0x0b, 0x5d, 0x1f,
+ 0xff, 0x6a, 0x6a, 0x03,
0xd1, 0x6a, 0x91, 0x00,
- 0x00, 0x65, 0x5c, 0x10,
+ 0x00, 0x65, 0x82, 0x10,
0xff, 0x65, 0x93, 0x02,
- 0x01, 0x0b, 0x4c, 0x1b,
- 0x10, 0x0c, 0x45, 0x1f,
- 0x04, 0x0b, 0x49, 0x1b,
+ 0x01, 0x0b, 0x69, 0x1b,
+ 0x10, 0x0c, 0x62, 0x1f,
+ 0x04, 0x0b, 0x66, 0x1b,
0xff, 0x6a, 0x65, 0x02,
- 0x04, 0x93, 0x4b, 0x1b,
- 0x01, 0x94, 0x4a, 0x1f,
- 0x10, 0x94, 0x4b, 0x1b,
+ 0x04, 0x93, 0x68, 0x1b,
+ 0x01, 0x94, 0x67, 0x1f,
+ 0x10, 0x94, 0x68, 0x1b,
0xc7, 0x93, 0x93, 0x02,
- 0x38, 0x93, 0x4d, 0x1b,
+ 0x38, 0x93, 0x6a, 0x1b,
0xff, 0x6a, 0x6a, 0x03,
- 0x80, 0x41, 0x4e, 0x1f,
- 0x40, 0x41, 0x4e, 0x1b,
+ 0x80, 0x36, 0x6b, 0x1b,
0x21, 0x6a, 0x91, 0x01,
0xff, 0x65, 0x90, 0x02,
- 0xff, 0x59, 0x64, 0x02,
- 0x00, 0xb9, 0x56, 0x19,
- 0x04, 0xa0, 0x60, 0x1b,
- 0x01, 0x65, 0x65, 0x06,
- 0xff, 0x3e, 0x64, 0x02,
- 0x00, 0x65, 0x52, 0x19,
- 0x00, 0x6a, 0xad, 0x17,
- 0x0d, 0x6a, 0x3d, 0x00,
- 0x00, 0x59, 0x77, 0x17,
- 0xff, 0xa8, 0x5e, 0x1f,
- 0x10, 0xa0, 0xa0, 0x00,
- 0x08, 0xa0, 0x4e, 0x1f,
+ 0xff, 0x51, 0x72, 0x19,
+ 0xff, 0x37, 0x64, 0x02,
+ 0xa1, 0x6a, 0x77, 0x11,
+ 0xff, 0x51, 0x64, 0x02,
+ 0xb9, 0x6a, 0x77, 0x11,
+ 0xff, 0xba, 0x79, 0x1d,
+ 0xff, 0xba, 0x90, 0x02,
+ 0xff, 0x65, 0x65, 0x06,
+ 0x00, 0x6c, 0x74, 0x19,
+ 0xff, 0x90, 0x65, 0x03,
0xff, 0x6a, 0x65, 0x01,
- 0x08, 0xa0, 0x5f, 0x1b,
- 0xff, 0xba, 0x66, 0x1d,
- 0xff, 0xbb, 0x49, 0x02,
+ 0x20, 0x36, 0x88, 0x1f,
+ 0x00, 0x90, 0x6e, 0x17,
+ 0xff, 0x65, 0x88, 0x1d,
+ 0xff, 0xba, 0x82, 0x1d,
+ 0xff, 0xbb, 0x66, 0x02,
0xff, 0xba, 0x90, 0x02,
- 0xff, 0x49, 0xbb, 0x02,
+ 0xff, 0x66, 0xbb, 0x02,
0xff, 0x65, 0x90, 0x02,
- 0xff, 0xbb, 0x6b, 0x1d,
- 0xff, 0xba, 0x49, 0x02,
+ 0xff, 0xbb, 0x87, 0x1d,
+ 0xff, 0xba, 0x66, 0x02,
0xff, 0xbb, 0x90, 0x02,
- 0xff, 0x49, 0xba, 0x02,
+ 0xff, 0x66, 0xba, 0x02,
0xff, 0x65, 0x90, 0x03,
- 0xff, 0xba, 0x52, 0x03,
- 0xff, 0x6a, 0x6a, 0x03,
+ 0xff, 0xba, 0x3f, 0x03,
+ 0x00, 0x6a, 0xd8, 0x17,
+ 0x0d, 0x6a, 0x35, 0x00,
+ 0x00, 0x51, 0xb3, 0x11,
+ 0xff, 0x3f, 0x96, 0x1d,
+ 0xff, 0x6a, 0x51, 0x00,
+ 0x00, 0x3f, 0x6e, 0x17,
+ 0xff, 0x65, 0x96, 0x1d,
+ 0x20, 0x36, 0x36, 0x00,
+ 0x20, 0xa0, 0x92, 0x1b,
+ 0xff, 0xb9, 0x51, 0x03,
+ 0xff, 0x6a, 0x51, 0x01,
+ 0xff, 0x65, 0x66, 0x02,
+ 0x45, 0x6a, 0xab, 0x17,
+ 0x01, 0x6a, 0x8c, 0x01,
+ 0xff, 0x37, 0x64, 0x02,
+ 0x00, 0x6a, 0x93, 0x17,
+ 0x0d, 0x6a, 0x93, 0x00,
+ 0x00, 0x65, 0xd1, 0x17,
+ 0xff, 0x99, 0x51, 0x03,
+ 0x01, 0x0c, 0x9b, 0x1f,
+ 0x04, 0x0c, 0x9b, 0x1b,
+ 0xe0, 0x03, 0x3d, 0x02,
+ 0xff, 0x3d, 0x03, 0x03,
0xff, 0x8c, 0x08, 0x02,
0xff, 0x8d, 0x09, 0x02,
0xff, 0x8e, 0x0a, 0x03,
@@ -377,19 +427,21 @@ static u_int8_t seqprog[] = {
0xff, 0x6c, 0x6d, 0x02,
0xff, 0x6c, 0x6d, 0x02,
0xff, 0x6c, 0x6d, 0x03,
- 0x3d, 0x65, 0x66, 0x0a,
- 0x55, 0x65, 0x64, 0x0a,
- 0x00, 0x54, 0x88, 0x06,
+ 0x3d, 0x64, 0x66, 0x0a,
+ 0x55, 0x64, 0x64, 0x0a,
+ 0x00, 0x6c, 0x88, 0x06,
0xff, 0x66, 0x64, 0x02,
- 0x00, 0x55, 0x89, 0x08,
+ 0x00, 0x6c, 0x89, 0x08,
0xff, 0x6a, 0x64, 0x02,
- 0x00, 0x56, 0x8a, 0x08,
- 0x00, 0x57, 0x8b, 0x08,
- 0x1c, 0x6a, 0x8c, 0x00,
+ 0x00, 0x6c, 0x8a, 0x08,
+ 0x00, 0x6c, 0x8b, 0x08,
0xff, 0x6a, 0x8d, 0x02,
- 0xff, 0x6a, 0x8e, 0x02,
- 0xff, 0x3d, 0x93, 0x02,
- 0x04, 0x3d, 0x8f, 0x1b,
+ 0xff, 0x6a, 0x8e, 0x03,
+ 0xff, 0x65, 0x64, 0x02,
+ 0x41, 0x6a, 0xa9, 0x17,
+ 0x1c, 0x6a, 0x8c, 0x00,
+ 0xff, 0x35, 0x93, 0x02,
+ 0x04, 0x35, 0xc3, 0x1b,
0xa0, 0x6a, 0x65, 0x00,
0x1c, 0x65, 0x64, 0x06,
0xff, 0x6c, 0x99, 0x02,
@@ -399,14 +451,14 @@ static u_int8_t seqprog[] = {
0xff, 0x6c, 0x99, 0x02,
0xff, 0x6c, 0x99, 0x02,
0xff, 0x6c, 0x99, 0x02,
- 0x00, 0x65, 0x86, 0x19,
+ 0x00, 0x65, 0xba, 0x19,
0x0a, 0x93, 0x93, 0x00,
- 0x00, 0x65, 0x9d, 0x17,
- 0x04, 0x3d, 0x4e, 0x1f,
- 0xa0, 0x6a, 0x95, 0x17,
- 0x00, 0x65, 0x96, 0x17,
- 0x00, 0x65, 0x96, 0x17,
- 0x00, 0x65, 0x96, 0x11,
+ 0x00, 0x65, 0xd1, 0x17,
+ 0x04, 0x35, 0x6b, 0x1f,
+ 0xa0, 0x6a, 0xc9, 0x17,
+ 0x00, 0x65, 0xca, 0x17,
+ 0x00, 0x65, 0xca, 0x17,
+ 0x00, 0x65, 0xca, 0x11,
0xff, 0x65, 0x66, 0x02,
0xff, 0x99, 0x6d, 0x02,
0xff, 0x99, 0x6d, 0x02,
@@ -415,69 +467,58 @@ static u_int8_t seqprog[] = {
0xff, 0x99, 0x6d, 0x02,
0xff, 0x99, 0x6d, 0x02,
0xff, 0x99, 0x6d, 0x03,
- 0x08, 0x94, 0x9d, 0x1f,
+ 0x08, 0x94, 0xd1, 0x1f,
0xf7, 0x93, 0x93, 0x02,
- 0x08, 0x93, 0x9f, 0x1b,
+ 0x08, 0x93, 0xd3, 0x1b,
0xff, 0x6a, 0x6a, 0x03,
- 0xff, 0x65, 0x66, 0x02,
- 0x4c, 0x66, 0x66, 0x0a,
- 0x03, 0x66, 0x66, 0x02,
- 0xbc, 0x66, 0x66, 0x06,
- 0x6a, 0x65, 0x64, 0x0a,
- 0x08, 0x65, 0xa8, 0x1f,
- 0x02, 0x64, 0x64, 0x06,
- 0xff, 0x64, 0x90, 0x02,
- 0xff, 0x66, 0x65, 0x03,
- 0xff, 0x53, 0xba, 0x02,
- 0xff, 0x6a, 0xb9, 0x00,
- 0xff, 0x90, 0x53, 0x03,
- 0xff, 0x53, 0xb9, 0x19,
- 0xff, 0x52, 0xb0, 0x19,
+ 0xff, 0x40, 0xba, 0x02,
+ 0xff, 0x90, 0x40, 0x02,
+ 0xff, 0x6a, 0xb9, 0x01,
+ 0xff, 0x40, 0xdf, 0x19,
+ 0xff, 0x3f, 0xdb, 0x19,
0xff, 0x6a, 0x65, 0x01,
- 0xff, 0x52, 0x90, 0x02,
- 0x10, 0xa0, 0xb4, 0x1f,
- 0xef, 0xa0, 0xa0, 0x02,
- 0x00, 0x65, 0xb6, 0x11,
- 0xff, 0xa8, 0xb6, 0x1b,
- 0xff, 0xb3, 0xb8, 0x1d,
- 0x01, 0x6a, 0x3d, 0x00,
- 0x00, 0xb9, 0x77, 0x17,
- 0x00, 0x90, 0x61, 0x11,
- 0xff, 0x53, 0x90, 0x02,
- 0xff, 0xba, 0x53, 0x03,
+ 0xff, 0x3f, 0x90, 0x02,
+ 0x01, 0x6a, 0x35, 0x00,
+ 0x00, 0xb9, 0xb3, 0x17,
+ 0x00, 0x90, 0x7d, 0x11,
+ 0xff, 0x40, 0x90, 0x02,
+ 0xff, 0xba, 0x40, 0x03,
0xff, 0x6a, 0xbb, 0x00,
- 0xff, 0x52, 0xba, 0x02,
- 0xff, 0x90, 0x52, 0x02,
- 0xff, 0xba, 0x4e, 0x1d,
+ 0xff, 0x3f, 0xba, 0x02,
+ 0xff, 0x90, 0x3f, 0x02,
+ 0xff, 0xba, 0x6b, 0x1d,
0xff, 0xba, 0x90, 0x02,
- 0xff, 0x52, 0xbb, 0x02,
- 0xff, 0x52, 0x90, 0x03,
+ 0xff, 0x3f, 0xbb, 0x02,
+ 0xff, 0x3f, 0x90, 0x03,
};
-#define ULTRA 0x8
-#define SCB_PAGING 0x4
-#define TWIN_CHANNEL 0x2
+#define WIDE 0x20
+#define ULTRA 0x10
+#define SCB_PAGING 0x8
+#define TWIN_CHANNEL 0x4
+#define TARGET_MODE 0x2
struct patch {
int options;
int negative;
int begin;
int end;
} patches[] = {
- { 0x00000002, 0, 0x006, 0x00b },
- { 0x00000004, 0, 0x00e, 0x010 },
- { 0x00000004, 1, 0x011, 0x012 },
- { 0x00000004, 0, 0x01a, 0x023 },
- { 0x00000004, 1, 0x023, 0x027 },
- { 0x00000002, 0, 0x02f, 0x033 },
- { 0x00000008, 0, 0x04f, 0x056 },
- { 0x00000004, 0, 0x0e0, 0x0e3 },
- { 0x00000004, 1, 0x0e8, 0x0ed },
- { 0x00000004, 0, 0x102, 0x103 },
- { 0x00000004, 0, 0x113, 0x114 },
- { 0x00000004, 1, 0x114, 0x118 },
- { 0x00000004, 1, 0x123, 0x128 },
- { 0x00000004, 0, 0x128, 0x12a },
- { 0x00000004, 0, 0x152, 0x16c },
- { 0x00000004, 1, 0x16c, 0x16d },
- { 0x00000004, 0, 0x1ad, 0x1c2 },
+ { 0x00000002, 0, 0x001, 0x002 },
+ { 0x00000002, 1, 0x002, 0x003 },
+ { 0x00000004, 0, 0x009, 0x00d },
+ { 0x00000008, 0, 0x012, 0x013 },
+ { 0x00000008, 1, 0x018, 0x019 },
+ { 0x00000004, 0, 0x020, 0x024 },
+ { 0x00000010, 0, 0x02a, 0x031 },
+ { 0x00000002, 0, 0x038, 0x071 },
+ { 0x00000020, 0, 0x0d6, 0x0d7 },
+ { 0x00000020, 1, 0x0d7, 0x0d8 },
+ { 0x00000020, 0, 0x12f, 0x130 },
+ { 0x00000020, 1, 0x130, 0x131 },
+ { 0x00000008, 0, 0x134, 0x135 },
+ { 0x00000008, 1, 0x13c, 0x13f },
+ { 0x00000008, 0, 0x13f, 0x140 },
+ { 0x00000002, 0, 0x15c, 0x15f },
+ { 0x00000008, 0, 0x1d5, 0x1d7 },
+ { 0x00000008, 0, 0x1d8, 0x1e1 },
{ 0x00000000, 0, 0x000, 0x000 }
};
diff --git a/drivers/scsi/dtc.c b/drivers/scsi/dtc.c
index f45c133d7..fbfb39306 100644
--- a/drivers/scsi/dtc.c
+++ b/drivers/scsi/dtc.c
@@ -263,7 +263,7 @@ __initfunc(int dtc_detect(Scsi_Host_Template * tpnt)) {
/* With interrupts enabled, it will sometimes hang when doing heavy
* reads. So better not enable them until I finger it out. */
if (instance->irq != IRQ_NONE)
- if (request_irq(instance->irq, dtc_intr, SA_INTERRUPT, "dtc")) {
+ if (request_irq(instance->irq, do_dtc_intr, SA_INTERRUPT, "dtc")) {
printk("scsi%d : IRQ%d not free, interrupts disabled\n",
instance->host_no, instance->irq);
instance->irq = IRQ_NONE;
diff --git a/drivers/scsi/dtc.h b/drivers/scsi/dtc.h
index c0e15f6ea..9acdf4a04 100644
--- a/drivers/scsi/dtc.h
+++ b/drivers/scsi/dtc.h
@@ -112,6 +112,7 @@ int dtc_proc_info (char *buffer, char **start, off_t offset,
#endif
#define NCR5380_intr dtc_intr
+#define do_NCR5380_intr do_dtc_intr
#define NCR5380_queue_command dtc_queue_command
#define NCR5380_abort dtc_abort
#define NCR5380_reset dtc_reset
diff --git a/drivers/scsi/eata.c b/drivers/scsi/eata.c
index aeda681c1..ffd1e00e1 100644
--- a/drivers/scsi/eata.c
+++ b/drivers/scsi/eata.c
@@ -1,6 +1,29 @@
/*
* 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).
+ *
+ * 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.
+ *
+ * 17 Mar 1998 rev. 4.01 for linux 2.0.33 and 2.1.88
+ * 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.
@@ -14,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
@@ -23,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:
@@ -89,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
@@ -103,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
@@ -127,7 +150,7 @@
* This driver is based on the CAM (Common Access Method Committee)
* EATA (Enhanced AT Bus Attachment) rev. 2.0A, using DMA protocol.
*
- * Copyright (C) 1994-1997 Dario Ballabio (dario@milano.europe.dg.com)
+ * Copyright (C) 1994-1998 Dario Ballabio (dario@milano.europe.dg.com)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that redistributions of source
@@ -157,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
@@ -170,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
@@ -190,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
@@ -199,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.
@@ -245,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:
@@ -261,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.
* ----------------------------------------------------------------------------
@@ -272,11 +295,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");
@@ -286,6 +312,7 @@ MODULE_PARM(max_queue_depth, "i");
MODULE_PARM(tag_mode, "i");
MODULE_AUTHOR("Dario Ballabio");
#endif
+
#endif
#include <linux/string.h>
@@ -296,6 +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"
@@ -306,9 +338,12 @@ MODULE_AUTHOR("Dario Ballabio");
#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
@@ -330,28 +365,26 @@ struct proc_dir_entry proc_scsi_eata2x = {
#undef DEBUG_LINKED_COMMANDS
#undef DEBUG_DETECT
+#undef DEBUG_PCI_DETECT
#undef DEBUG_INTERRUPT
-#undef DEBUG_STATISTICS
#undef DEBUG_RESET
-#undef DEBUG_SMP
#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)
#define MAX_CHANNEL 4
#define MAX_LUN 32
#define MAX_TARGET 32
-#define MAX_IRQ 16
#define MAX_MAILBOXES 64
#define MAX_SGLIST 64
-#define MAX_LARGE_SGLIST 252
+#define MAX_LARGE_SGLIST 122
#define MAX_INTERNAL_RETRIES 64
#define MAX_CMD_PER_LUN 2
#define MAX_TAGGED_CMD_PER_LUN (MAX_MAILBOXES - MAX_CMD_PER_LUN)
-#define SKIP UINT_MAX
+#define SKIP ULONG_MAX
#define FALSE 0
#define TRUE 1
#define FREE 0
@@ -415,15 +448,15 @@ struct eata_info {
ulong data_len; /* Number of valid bytes after this field */
ulong sign; /* ASCII "EATA" signature */
unchar :4, /* unused low nibble */
- version:4; /* EATA version, should be 0x1 */
+ version:4; /* EATA version, should be 0x1 */
unchar ocsena:1, /* Overlap Command Support Enabled */
- tarsup:1, /* Target Mode Supported */
+ tarsup:1, /* Target Mode Supported */
trnxfr:1, /* Truncate Transfer Cmd NOT Necessary */
morsup:1, /* More Supported */
- dmasup:1, /* DMA Supported */
- drqvld:1, /* DRQ Index (DRQX) is valid */
- ata:1, /* This is an ATA device */
- haaval:1; /* Host Adapter Address Valid */
+ dmasup:1, /* DMA Supported */
+ drqvld:1, /* DRQ Index (DRQX) is valid */
+ ata:1, /* This is an ATA device */
+ haaval:1; /* Host Adapter Address Valid */
ushort cp_pad_len; /* Number of pad bytes after cp_len */
unchar host_addr[4]; /* Host Adapter SCSI ID for channels 3, 2, 1, 0 */
ulong cp_len; /* Number of valid bytes in cp */
@@ -432,19 +465,19 @@ struct eata_info {
ushort unused;
ushort scatt_size; /* Max number of entries in scatter/gather table */
unchar irq:4, /* Interrupt Request assigned to this controller */
- irq_tr:1, /* 0 for edge triggered, 1 for level triggered */
- second:1, /* 1 if this is a secondary (not primary) controller */
- drqx:2; /* DRQ Index (0=DMA0, 1=DMA7, 2=DMA6, 3=DMA5) */
+ irq_tr:1, /* 0 for edge triggered, 1 for level triggered */
+ second:1, /* 1 if this is a secondary (not primary) controller */
+ drqx:2; /* DRQ Index (0=DMA0, 1=DMA7, 2=DMA6, 3=DMA5) */
unchar sync; /* 1 if scsi target id 7...0 is running sync scsi */
/* Structure extension defined in EATA 2.0B */
unchar isaena:1, /* ISA i/o addressing is disabled/enabled */
- forcaddr:1, /* Port address has been forced */
+ forcaddr:1, /* Port address has been forced */
large_sg:1, /* 1 if large SG lists are supported */
res1:1,
- :4;
+ :4;
unchar max_id:5, /* Max SCSI target ID number */
- max_chan:3; /* Max SCSI channel number on this board */
+ max_chan:3; /* Max SCSI channel number on this board */
/* Structure extension defined in EATA 2.0C */
unchar max_lun; /* Max SCSI LUN number */
@@ -463,21 +496,21 @@ struct eata_info {
struct eata_config {
ushort len; /* Number of bytes following this field */
unchar edis:1, /* Disable EATA interface after config command */
- ocena:1, /* Overlapped Commands Enabled */
- mdpena:1, /* Transfer all Modified Data Pointer Messages */
- tarena:1, /* Target Mode Enabled for this controller */
- :4;
+ ocena:1, /* Overlapped Commands Enabled */
+ mdpena:1, /* Transfer all Modified Data Pointer Messages */
+ tarena:1, /* Target Mode Enabled for this controller */
+ :4;
unchar cpad[511];
};
/* Returned status packet structure */
struct mssp {
unchar adapter_status:7, /* State related to current command */
- eoc:1; /* End Of Command (1 = command completed) */
+ eoc:1; /* End Of Command (1 = command completed) */
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];
};
@@ -489,13 +522,13 @@ struct sg_list {
/* MailBox SCSI Command Packet */
struct mscp {
unchar sreset:1, /* SCSI Bus Reset Signal should be asserted */
- init:1, /* Re-initialize controller and self test */
- 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 */
- dout:1, /* Direction of Transfer is Out (Host to Target) */
- din:1; /* Direction of Transfer is In (Target to Host) */
+ init:1, /* Re-initialize controller and self test */
+ 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 */
+ 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 */
unchar unused[3];
unchar fwnest:1, /* Send command to a component of an Array Group */
@@ -507,16 +540,17 @@ struct mscp {
unchar target:5, /* SCSI target ID */
channel:3; /* SCSI channel number */
unchar lun:5, /* SCSI logical unit number */
- luntar:1, /* This cp is for Target (not LUN) */
- dispri:1, /* Disconnect Privilege granted */
- one:1; /* 1 */
+ luntar:1, /* This cp is for Target (not LUN) */
+ dispri:1, /* Disconnect Privilege granted */
+ one:1; /* 1 */
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;
};
@@ -526,7 +560,6 @@ struct hostdata {
unsigned int cp_stat[MAX_MAILBOXES]; /* FREE, IN_USE, LOCKED, IN_RESET */
unsigned int last_cp_used; /* Index of last mailbox used */
unsigned int iocount; /* Total i/o done for this board */
- unsigned int multicount; /* Total ... in second ihdlr loop */
int board_number; /* Number of this board */
char board_name[16]; /* Name of this board */
char board_id[256]; /* data from INQUIRY on this board */
@@ -537,14 +570,17 @@ 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];
static const char *driver_name = "EATA";
-static unsigned int irqlist[MAX_IRQ], calls[MAX_IRQ];
+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 int 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,
@@ -559,11 +595,11 @@ static unsigned int 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
};
@@ -576,7 +612,7 @@ static unsigned int 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 eata2x_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;
@@ -603,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);
@@ -665,7 +701,7 @@ static void select_queue_depths(struct Scsi_Host *host, Scsi_Device *devlist) {
return;
}
-static inline int wait_on_busy(unsigned int iobase, unsigned int loop) {
+static inline int wait_on_busy(unsigned long iobase, unsigned int loop) {
while (inb(iobase + REG_AUX_STATUS) & ABSY_ASSERTED) {
udelay(1L);
@@ -675,7 +711,7 @@ static inline int wait_on_busy(unsigned int iobase, unsigned int loop) {
return FALSE;
}
-static inline int do_dma(unsigned int iobase, unsigned int addr, unchar cmd) {
+static inline int do_dma(unsigned long iobase, unsigned int addr, unchar cmd) {
if (wait_on_busy(iobase, (addr ? MAXLOOP * 100 : MAXLOOP))) return TRUE;
@@ -690,7 +726,7 @@ static inline int do_dma(unsigned int iobase, unsigned int addr, unchar cmd) {
return FALSE;
}
-static inline int read_pio(unsigned int iobase, ushort *start, ushort *end) {
+static inline int read_pio(unsigned long iobase, ushort *start, ushort *end) {
unsigned int loop = MAXLOOP;
ushort *p;
@@ -698,7 +734,7 @@ static inline int read_pio(unsigned int iobase, ushort *start, ushort *end) {
while (!(inb(iobase + REG_STATUS) & DRQ_ASSERTED)) {
udelay(1L);
- if (--loop == 0) return TRUE;
+ if (--loop == 0) return TRUE;
}
loop = MAXLOOP;
@@ -708,10 +744,48 @@ static inline int read_pio(unsigned int iobase, ushort *start, ushort *end) {
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 int port_base, unsigned int j, Scsi_Host_Template *tpnt)) {
+ (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;
@@ -723,22 +797,22 @@ __initfunc (static inline int port_detect \
sprintf(name, "%s%d", driver_name, j);
if(check_region(port_base, REGION_SIZE)) {
- printk("%s: address 0x%03x in use, skipping probe.\n", name, port_base);
+ printk("%s: address 0x%03lx in use, skipping probe.\n", name, port_base);
return FALSE;
}
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",
- name, DEV2H(info.data_len));
+ printk("%s: config structure size (%ld bytes) too short, detaching.\n",
+ name, DEV2H(info.data_len));
return FALSE;
}
else if (DEV2H(info.data_len) == EATA_2_0A_SIZE)
@@ -774,7 +848,7 @@ __initfunc (static inline int port_detect \
}
if (!info.haaval || info.ata) {
- printk("%s: address 0x%03x, unusable %s board (%d%d), detaching.\n",
+ printk("%s: address 0x%03lx, unusable %s board (%d%d), detaching.\n",
name, port_base, bus_type, info.haaval, info.ata);
return FALSE;
}
@@ -782,7 +856,7 @@ __initfunc (static inline int port_detect \
if (info.drqvld) {
if (subversion == ESA)
- printk("%s: warning, weird %s board using DMA.\n", name, bus_type);
+ printk("%s: warning, weird %s board using DMA.\n", name, bus_type);
subversion = ISA;
dma_channel = dma_channel_table[3 - info.drqx];
@@ -790,7 +864,7 @@ __initfunc (static inline int port_detect \
else {
if (subversion == ISA)
- printk("%s: warning, weird %s board not using DMA.\n", name, bus_type);
+ printk("%s: warning, weird %s board not using DMA.\n", name, bus_type);
subversion = ESA;
dma_channel = NO_DMA;
@@ -803,19 +877,25 @@ __initfunc (static inline int port_detect \
if (subversion == ESA && !info.irq_tr)
printk("%s: warning, LEVEL triggering is suggested for IRQ %u.\n",
- name, irq);
+ name, irq);
- /* Board detected, allocate its IRQ if not already done */
- if ((irq >= MAX_IRQ) || (!irqlist[irq] && request_irq(irq,
- eata2x_interrupt_handler, SA_INTERRUPT, driver_name, NULL))) {
+ 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, 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);
return FALSE;
}
if (subversion == ISA && request_dma(dma_channel, driver_name)) {
printk("%s: unable to allocate DMA channel %u, detaching.\n",
- name, dma_channel);
- free_irq(irq, NULL);
+ name, dma_channel);
+ free_irq(irq, &sha[j]);
return FALSE;
}
@@ -840,7 +920,7 @@ __initfunc (static inline int port_detect \
if (sh[j] == NULL) {
printk("%s: unable to register host, detaching.\n", name);
- if (!irqlist[irq]) free_irq(irq, NULL);
+ free_irq(irq, &sha[j]);
if (subversion == ISA) free_dma(dma_channel);
@@ -865,7 +945,6 @@ __initfunc (static inline int port_detect \
HD(j)->subversion = subversion;
HD(j)->protocol_rev = protocol_rev;
HD(j)->board_number = j;
- irqlist[irq]++;
if (HD(j)->subversion == ESA)
sh[j]->unchecked_isa_dma = FALSE;
@@ -889,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;
}
@@ -917,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;
@@ -937,10 +1016,11 @@ __initfunc (static inline int port_detect \
}
else tag_type = 'n';
- printk("%s: 2.0%c, %s 0x%03x, IRQ %u, %s, SG %d, MB %d, tc:%c, lc:%c, "\
- "mq:%d.\n", BN(j), HD(j)->protocol_rev, bus_type, sh[j]->io_port,
- sh[j]->irq, dma_name, sh[j]->sg_tablesize, sh[j]->can_queue,
- tag_type, YESNO(linked_comm), max_queue_depth);
+ printk("%s: 2.0%c, %s 0x%03lx, IRQ %u, %s, SG %d, MB %d, tc:%c, lc:%c, "\
+ "mq:%d.\n", BN(j), HD(j)->protocol_rev, bus_type,
+ (unsigned long)sh[j]->io_port, sh[j]->irq, dma_name,
+ sh[j]->sg_tablesize, sh[j]->can_queue, tag_type, YESNO(linked_comm),
+ max_queue_depth);
if (sh[j]->max_id > 8 || sh[j]->max_lun > 8)
printk("%s: wide SCSI support enabled, max_id %u, max_lun %u.\n",
@@ -964,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
@@ -979,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;
}
@@ -1008,9 +1088,37 @@ __initfunc (static void add_pci_ports(void)) {
#if defined(CONFIG_PCI)
+ 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;
- unsigned int addr, k;
if (!pcibios_present()) return;
@@ -1022,7 +1130,7 @@ __initfunc (static void add_pci_ports(void)) {
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
@@ -1031,10 +1139,13 @@ __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;
}
-#endif
+
+#endif /* end old style PCI code */
+
+#endif /* end CONFIG_PCI */
return;
}
@@ -1056,11 +1167,6 @@ __initfunc (int eata2x_detect(Scsi_Host_Template *tpnt)) {
}
#endif
- for (k = 0; k < MAX_IRQ; k++) {
- irqlist[k] = 0;
- calls[k] = 0;
- }
-
for (k = 0; k < MAX_BOARDS + 1; k++) sh[k] = NULL;
if (!setup_done) add_pci_ports();
@@ -1072,9 +1178,10 @@ __initfunc (int eata2x_detect(Scsi_Host_Template *tpnt)) {
if (j < MAX_BOARDS && port_detect(io_port[k], j, tpnt)) j++;
}
- if (j > 0)
- printk("EATA/DMA 2.0x: Copyright (C) 1994-1997 Dario Ballabio.\n");
+ if (j > 0)
+ printk("EATA/DMA 2.0x: Copyright (C) 1994-1998 Dario Ballabio.\n");
+ num_boards = j;
restore_flags(flags);
return j;
}
@@ -1102,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
};
@@ -1120,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;
@@ -1138,26 +1245,26 @@ int eata2x_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
if (i >= sh[j]->can_queue) i = 0;
if (HD(j)->cp_stat[i] == FREE) {
- HD(j)->last_cp_used = i;
- break;
- }
+ HD(j)->last_cp_used = i;
+ break;
+ }
}
if (k == sh[j]->can_queue) {
printk("%s: qcomm, no free mailbox, resetting.\n", BN(j));
- if (HD(j)->in_reset)
- printk("%s: qcomm, already in reset.\n", BN(j));
+ 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)
- panic("%s: qcomm, SCSI_RESET_SUCCESS.\n", BN(j));
+ == 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);
- return 0;
+ done(SCpnt);
+ return 1;
}
/* Set pointer to control packet structure */
@@ -1166,33 +1273,32 @@ 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;
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);
for (k = 0; k < ARRAY_SIZE(data_out_cmds); k++)
if (SCpnt->cmnd[0] == data_out_cmds[k]) {
- cpp->dout = TRUE;
- break;
- }
+ cpp->dout = TRUE;
+ break;
+ }
if ((cpp->din = !cpp->dout))
for (k = 0; k < ARRAY_SIZE(data_none_cmds); k++)
if (SCpnt->cmnd[0] == data_none_cmds[k]) {
- cpp->din = FALSE;
- break;
- }
+ cpp->din = FALSE;
+ break;
+ }
cpp->reqsen = TRUE;
cpp->dispri = TRUE;
@@ -1202,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] ||
@@ -1246,14 +1352,14 @@ 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);
- return 0;
+ done(SCpnt);
+ return 1;
}
HD(j)->cp_stat[i] = IN_USE;
@@ -1272,14 +1378,14 @@ int eata2x_abort(Scsi_Cmnd *SCarg) {
if (SCarg->host_scribble == NULL
|| SCarg->serial_number != SCarg->serial_number_at_timeout) {
printk("%s: abort, target %d.%d:%d, pid %ld inactive.\n",
- BN(j), SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid);
+ BN(j), SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid);
restore_flags(flags);
return SCSI_ABORT_NOT_RUNNING;
}
i = *(unsigned int *)SCarg->host_scribble;
- printk("%s: abort, mbox %d, target %d.%d:%d, pid %ld.\n",
- BN(j), i, SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid);
+ 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)
panic("%s: abort, invalid SCarg->host_scribble.\n", BN(j));
@@ -1300,8 +1406,8 @@ int eata2x_abort(Scsi_Cmnd *SCarg) {
printk("%s: abort, mbox %d is in use.\n", BN(j), i);
if (SCarg != HD(j)->cp[i].SCpnt)
- panic("%s: abort, mbox %d, SCarg %p, cp SCpnt %p.\n",
- BN(j), i, SCarg, HD(j)->cp[i].SCpnt);
+ panic("%s: abort, mbox %d, SCarg %p, cp SCpnt %p.\n",
+ BN(j), i, SCarg, HD(j)->cp[i].SCpnt);
if (inb(sh[j]->io_port + REG_AUX_STATUS) & IRQ_ASSERTED)
printk("%s: abort, mbox %d, interrupt pending.\n", BN(j), i);
@@ -1327,7 +1433,7 @@ int eata2x_abort(Scsi_Cmnd *SCarg) {
SCarg->host_scribble = NULL;
HD(j)->cp_stat[i] = FREE;
printk("%s, abort, mbox %d ready, DID_ABORT, pid %ld done.\n",
- BN(j), i, SCarg->pid);
+ BN(j), i, SCarg->pid);
SCarg->scsi_done(SCarg);
restore_flags(flags);
return SCSI_ABORT_SUCCESS;
@@ -1346,8 +1452,8 @@ 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",
- BN(j), SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid,
+ 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);
if (SCarg->host_scribble == NULL)
@@ -1384,13 +1490,13 @@ int eata2x_reset(Scsi_Cmnd *SCarg, unsigned int reset_flags) {
if (HD(j)->cp_stat[i] == FREE) continue;
if (HD(j)->cp_stat[i] == LOCKED) {
- HD(j)->cp_stat[i] = FREE;
- printk("%s: reset, locked mbox %d forced free.\n", BN(j), i);
- continue;
- }
+ HD(j)->cp_stat[i] = FREE;
+ printk("%s: reset, locked mbox %d forced free.\n", BN(j), i);
+ continue;
+ }
if (!(SCpnt = HD(j)->cp[i].SCpnt))
- panic("%s: reset, mbox %d, SCpnt == NULL.\n", BN(j), i);
+ panic("%s: reset, mbox %d, SCpnt == NULL.\n", BN(j), i);
if (HD(j)->cp_stat[i] == READY || HD(j)->cp_stat[i] == ABORTING) {
HD(j)->cp_stat[i] = ABORTING;
@@ -1405,13 +1511,13 @@ 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);
+ panic("%s: reset, mbox %d, garbled SCpnt.\n", BN(j), i);
- if (*(unsigned int *)SCpnt->host_scribble != i)
- panic("%s: reset, mbox %d, index mismatch.\n", BN(j), i);
+ if (*(unsigned int *)SCpnt->host_scribble != i)
+ panic("%s: reset, mbox %d, index mismatch.\n", BN(j), i);
- if (SCpnt->scsi_done == NULL)
- panic("%s: reset, mbox %d, SCpnt->scsi_done == NULL.\n", BN(j), i);
+ if (SCpnt->scsi_done == NULL)
+ panic("%s: reset, mbox %d, SCpnt->scsi_done == NULL.\n", BN(j), i);
if (SCpnt == SCarg) arg_done = TRUE;
}
@@ -1446,7 +1552,7 @@ int eata2x_reset(Scsi_Cmnd *SCarg, unsigned int reset_flags) {
HD(j)->cp_stat[i] = LOCKED;
printk("%s, reset, mbox %d locked, DID_RESET, pid %ld done.\n",
- BN(j), i, SCpnt->pid);
+ BN(j), i, SCpnt->pid);
}
else if (HD(j)->cp_stat[i] == ABORTING) {
@@ -1458,7 +1564,7 @@ int eata2x_reset(Scsi_Cmnd *SCarg, unsigned int reset_flags) {
HD(j)->cp_stat[i] = FREE;
printk("%s, reset, mbox %d aborting, DID_RESET, pid %ld done.\n",
- BN(j), i, SCpnt->pid);
+ BN(j), i, SCpnt->pid);
}
else
@@ -1493,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;
}
@@ -1510,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;
@@ -1519,6 +1625,7 @@ static inline void reorder(unsigned int j, unsigned long cursec,
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;
@@ -1529,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;
@@ -1543,12 +1650,13 @@ static inline void reorder(unsigned int j, unsigned long cursec,
if (SCpnt->request.sector > maxsec) maxsec = SCpnt->request.sector;
sl[n] = SCpnt->request.sector;
+ ioseek += SCpnt->request.nr_sectors;
if (!n) continue;
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];
@@ -1564,6 +1672,8 @@ static inline void reorder(unsigned int j, unsigned long cursec,
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++) {
@@ -1571,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;
}
@@ -1580,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; }
@@ -1597,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,
@@ -1622,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;
@@ -1640,232 +1751,228 @@ static void flush_dev(Scsi_Device *dev, unsigned long cursec, unsigned int j,
}
-static void eata2x_interrupt_handler(int irq, void *dev_id,
- struct pt_regs *regs) {
+static inline void ihdlr(int irq, unsigned int j) {
Scsi_Cmnd *SCpnt;
- unsigned long flags;
- unsigned int i, j, k, c, status, tstatus, loops, total_loops = 0, reg;
- struct mssp *spp;
+ unsigned int i, k, c, status, tstatus, reg;
+ struct mssp *dspp, *spp;
struct mscp *cpp;
- save_flags(flags);
- cli();
+ if (sh[j]->irq != irq)
+ panic("%s: ihdlr, irq %d, sh[j]->irq %d.\n", BN(j), irq, sh[j]->irq);
- if (!irqlist[irq]) {
- printk("%s, ihdlr, irq %d, unexpected interrupt.\n", driver_name, irq);
- restore_flags(flags);
+ /* Check if this board need to be serviced */
+ if (!(inb(sh[j]->io_port + REG_AUX_STATUS) & 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 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;
}
- if (do_trace) printk("%s: ihdlr, enter, irq %d, calls %d.\n",
- driver_name, irq, calls[irq]);
-
- /* Service all the boards configured on this irq */
- for (j = 0; sh[j] != NULL; j++) {
-
- if (sh[j]->irq != irq) continue;
-
- loops = 0;
-
- /* Loop until all interrupts for a board are serviced */
- while (inb(sh[j]->io_port + REG_AUX_STATUS) & IRQ_ASSERTED) {
- total_loops++;
- loops++;
-
- if (do_trace) printk("%s: ihdlr, start service, count %d.\n",
- BN(j), HD(j)->iocount);
-
- /* Read the status register to clear the interrupt indication */
- reg = inb(sh[j]->io_port + REG_STATUS);
-
- /* Service all mailboxes of this board */
- for (i = 0; i < sh[j]->can_queue; i++) {
- spp = &HD(j)->sp[i];
-
- /* Check if this mailbox has completed the operation */
- if (spp->eoc == FALSE) continue;
-
- spp->eoc = FALSE;
-
- if (HD(j)->cp_stat[i] == IGNORE) {
- HD(j)->cp_stat[i] = FREE;
- continue;
- }
- 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);
- continue;
- }
- else if (HD(j)->cp_stat[i] == FREE) {
- printk("%s: ihdlr, mbox %d is free, count %d.\n",
- BN(j), i, HD(j)->iocount);
- continue;
- }
- 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);
-
- HD(j)->cp_stat[i] = FREE;
- cpp = &HD(j)->cp[i];
- SCpnt = spp->SCpnt;
-
- if (SCpnt == NULL)
- panic("%s: ihdlr, mbox %d, SCpnt == NULL.\n", BN(j), i);
-
- if (SCpnt != cpp->SCpnt)
- panic("%s: ihdlr, mbox %d, sp SCpnt %p, cp SCpnt %p.\n",
- BN(j), i, SCpnt, cpp->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 (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:
- status = DID_ERROR << 16;
- break;
- }
-
- SCpnt->result = status | spp->target_status;
- HD(j)->iocount++;
-
- if (loops > 1) HD(j)->multicount++;
+ 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);
+
+ /* 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;
+
+ 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;
+ 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]);
+
+ HD(j)->cp_stat[i] = FREE;
+ 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 (*(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))
+ 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:
+ 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))
-#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);
-
- /* Set the command state to inactive */
- SCpnt->host_scribble = NULL;
-
- restore_flags(flags);
- SCpnt->scsi_done(SCpnt);
- cli();
-
- } /* Mailbox loop */
-
- } /* Multiple command loop */
-
- } /* Boards loop */
-
- calls[irq]++;
-
-#if defined (DEBUG_SMP)
- if (total_loops == 0)
- printk("%s: ihdlr, irq %d, no command completed, calls %d.\n",
- driver_name, irq, calls[irq]);
+ 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);
- if (do_trace) printk("%s: ihdlr, exit, irq %d, calls %d.\n",
- driver_name, irq, calls[irq]);
+ /* Set the command state to inactive */
+ SCpnt->host_scribble = NULL;
-#if defined (DEBUG_STATISTICS)
- if ((calls[irq] % 100000) == 10000)
- for (j = 0; sh[j] != NULL; j++)
- printk("%s: ihdlr, calls %d, count %d, multi %d.\n", BN(j),
- calls[(sh[j]->irq)], HD(j)->iocount, HD(j)->multicount);
-#endif
+ SCpnt->scsi_done(SCpnt);
+
+ if (do_trace) printk("%s: ihdlr, exit, irq %d, count %d.\n", BN(j), irq,
+ HD(j)->iocount);
- restore_flags(flags);
return;
}
+static void do_interrupt_handler(int irq, void *shap, struct pt_regs *regs) {
+
+ 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, j);
+ spin_unlock_irqrestore(&io_request_lock, flags);
+ }
+#else
+ ihdlr(irq, j);
+#endif
+
+}
+
int eata2x_release(struct Scsi_Host *shpnt) {
unsigned long flags;
unsigned int i, j;
@@ -1874,14 +1981,14 @@ 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);
- if (! --irqlist[sh[j]->irq]) free_irq(sh[j]->irq, NULL);
+ free_irq(sh[j]->irq, &sha[j]);
if (sh[j]->dma_channel != NO_DMA) free_dma(sh[j]->dma_channel);
diff --git a/drivers/scsi/eata.h b/drivers/scsi/eata.h
index 0a01d00b0..2eb04f657 100644
--- a/drivers/scsi/eata.h
+++ b/drivers/scsi/eata.h
@@ -1,10 +1,11 @@
/*
- * eata.h - used by the low-level driver for EATA/DMA SCSI host adapters.
+ * eata.h - used by the low-level driver for EATA/DMA SCSI host adapters.
*/
#ifndef _EATA_H
#define _EATA_H
#include <scsi/scsicam.h>
+#include <linux/version.h>
int eata2x_detect(Scsi_Host_Template *);
int eata2x_release(struct Scsi_Host *);
@@ -12,19 +13,41 @@ int eata2x_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
int eata2x_abort(Scsi_Cmnd *);
int eata2x_reset(Scsi_Cmnd *, unsigned int);
-#define EATA_VERSION "3.11.00"
-
-
-#define EATA { \
- name: "EATA/DMA 2.0x rev. " EATA_VERSION " ", \
- detect: eata2x_detect, \
- release: eata2x_release, \
- queuecommand: eata2x_queuecommand, \
- abort: eata2x_abort, \
- reset: eata2x_reset, \
- bios_param: scsicam_bios_param, \
- this_id: 7, /* this_id, reset by detect */ \
- unchecked_isa_dma: 1, /* unchecked isa dma, reset by detect */\
- use_clustering: ENABLE_CLUSTERING \
- }
+#define EATA_VERSION "4.20.00"
+
+#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,88)
+
+#define EATA { \
+ name: "EATA/DMA 2.0x rev. " EATA_VERSION " ", \
+ detect: eata2x_detect, \
+ release: eata2x_release, \
+ queuecommand: eata2x_queuecommand, \
+ abort: eata2x_abort, \
+ reset: eata2x_reset, \
+ bios_param: scsicam_bios_param, \
+ this_id: 7, \
+ unchecked_isa_dma: 1, \
+ use_clustering: ENABLE_CLUSTERING, \
+ use_new_eh_code: 1 /* Enable new error code */ \
+ }
+
+#else /* Use old scsi code */
+
+#define EATA { \
+ name: "EATA/DMA 2.0x rev. " EATA_VERSION " ", \
+ detect: eata2x_detect, \
+ release: eata2x_release, \
+ queuecommand: eata2x_queuecommand, \
+ abort: eata2x_abort, \
+ reset: eata2x_reset, \
+ bios_param: scsicam_bios_param, \
+ this_id: 7, \
+ unchecked_isa_dma: 1, \
+ use_clustering: ENABLE_CLUSTERING \
+ }
+
+#endif
+
#endif
diff --git a/drivers/scsi/eata_dma.c b/drivers/scsi/eata_dma.c
index 104664463..68c195c7e 100644
--- a/drivers/scsi/eata_dma.c
+++ b/drivers/scsi/eata_dma.c
@@ -79,6 +79,7 @@
#include <asm/io.h>
#include <asm/dma.h>
#include <asm/pgtable.h>
+#include <asm/spinlock.h>
#include <linux/blk.h>
#include "scsi.h"
#include "sd.h"
@@ -237,6 +238,16 @@ inline void eata_latency_out(struct eata_ccb *cp, Scsi_Cmnd *cmd)
}
}
+void eata_int_handler(int, void *, struct pt_regs *);
+
+void do_eata_int_handler(int irq, void *dev_id, struct pt_regs * regs)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&io_request_lock, flags);
+ eata_int_handler(irq, dev_id, regs);
+ spin_unlock_irqrestore(&io_request_lock, flags);
+}
void eata_int_handler(int irq, void *dev_id, struct pt_regs * regs)
{
@@ -1409,7 +1420,7 @@ void find_PCI(struct get_conf *buf, Scsi_Host_Template * tpnt)
u32 error, i, x;
u8 pal1, pal2, pal3;
- if (pcibios_present()) {
+ if (pci_present()) {
for (i = 0; i <= MAXPCI; ++i, ++pci_index) {
if (pcibios_find_device(PCI_VENDOR_ID_DPT, PCI_DEVICE_ID_DPT,
pci_index, &pci_bus, &pci_device_fn))
@@ -1538,7 +1549,7 @@ int eata_detect(Scsi_Host_Template * tpnt)
for (i = 0; i <= MAXIRQ; i++) { /* Now that we know what we have, we */
if (reg_IRQ[i] >= 1){ /* exchange the interrupt handler which */
free_irq(i, NULL); /* we used for probing with the real one */
- request_irq(i, (void *)(eata_int_handler), SA_INTERRUPT|SA_SHIRQ,
+ request_irq(i, (void *)(do_eata_int_handler), SA_INTERRUPT|SA_SHIRQ,
"eata_dma", NULL);
}
}
diff --git a/drivers/scsi/eata_pio.c b/drivers/scsi/eata_pio.c
index 90dc81f3c..57de91f5b 100644
--- a/drivers/scsi/eata_pio.c
+++ b/drivers/scsi/eata_pio.c
@@ -56,6 +56,8 @@
#include <linux/stat.h>
#include <linux/config.h> /* for CONFIG_PCI */
+#include <linux/blk.h>
+#include <asm/spinlock.h>
struct proc_dir_entry proc_scsi_eata_pio = {
PROC_SCSI_EATA_PIO, 9, "eata_pio",
@@ -109,6 +111,17 @@ void IncStat(Scsi_Pointer *SCp, uint Increment)
}
}
+void eata_pio_int_handler(int irq, void *dev_id, struct pt_regs * regs);
+
+void do_eata_pio_int_handler(int irq, void *dev_id, struct pt_regs * regs)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&io_request_lock, flags);
+ eata_pio_int_handler(irq, dev_id, regs);
+ spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
void eata_pio_int_handler(int irq, void *dev_id, struct pt_regs * regs)
{
uint eata_stat = 0xfffff;
@@ -697,7 +710,7 @@ int register_pio_HBA(long base, struct get_conf *gc, Scsi_Host_Template * tpnt)
}
if (!reg_IRQ[gc->IRQ]) { /* Interrupt already registered ? */
- if (!request_irq(gc->IRQ, eata_pio_int_handler, SA_INTERRUPT,
+ if (!request_irq(gc->IRQ, do_eata_pio_int_handler, SA_INTERRUPT,
"EATA-PIO", NULL)){
reg_IRQ[gc->IRQ]++;
if (!gc->IRQ_TR)
@@ -880,7 +893,7 @@ void find_pio_PCI(struct get_conf *buf, Scsi_Host_Template * tpnt)
u16 rev_device;
u32 error, i, x;
- if (pcibios_present()) {
+ if (pci_present()) {
for (i = 0; i <= MAXPCI; ++i, ++pci_index) {
if (pcibios_find_device(PCI_VENDOR_ID_DPT, PCI_DEVICE_ID_DPT,
pci_index, &pci_bus, &pci_device_fn))
@@ -983,7 +996,7 @@ int eata_pio_detect(Scsi_Host_Template * tpnt)
for (i = 0; i <= MAXIRQ; i++)
if (reg_IRQ[i])
- request_irq(i, eata_pio_int_handler, SA_INTERRUPT, "EATA-PIO", NULL);
+ request_irq(i, do_eata_pio_int_handler, SA_INTERRUPT, "EATA-PIO", NULL);
HBA_ptr = first_HBA;
diff --git a/drivers/scsi/esp.c b/drivers/scsi/esp.c
index 596e7b33f..d6059c153 100644
--- a/drivers/scsi/esp.c
+++ b/drivers/scsi/esp.c
@@ -39,6 +39,7 @@
#include <asm/idprom.h>
#endif
+#include <asm/spinlock.h>
#include <asm/system.h>
#include <asm/ptrace.h>
#include <asm/pgtable.h>
@@ -90,6 +91,7 @@ struct Sparc_ESP *espchain = 0;
int nesps = 0, esps_in_use = 0, esps_running = 0;
void esp_intr(int irq, void *dev_id, struct pt_regs *pregs);
+static void do_esp_intr(int irq, void *dev_id, struct pt_regs *pregs);
/* Debugging routines */
struct esp_cmdstrings {
@@ -3607,6 +3609,15 @@ esp_handle_done:
return;
}
+static void do_esp_intr(int irq, void *dev_id, struct pt_regs *pregs)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&io_request_lock, flags);
+ esp_intr(irq, dev_id, pregs);
+ spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
#ifndef __sparc_v9__
#ifndef __SMP__
diff --git a/drivers/scsi/fdomain.c b/drivers/scsi/fdomain.c
index 2f59d69f3..f07c5c05d 100644
--- a/drivers/scsi/fdomain.c
+++ b/drivers/scsi/fdomain.c
@@ -4,7 +4,7 @@
* Author: Rickard E. Faith, faith@cs.unc.edu
* Copyright 1992, 1993, 1994, 1995, 1996 Rickard E. Faith
*
- * $Id: fdomain.c,v 5.45 1996/10/02 15:13:06 root Exp $
+ * Version 5.46 (23-04-1998)
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -106,6 +106,7 @@
1.3.85 5.41 4 Apr 1996
2.0.12 5.44 8 Aug 1996 Use ID 7 for all PCI cards
2.1.1 5.45 2 Oct 1996 Update ROM accesses for 2.1.x
+ 2.1.97 5.46 23 Apr 1998 Rewritten PCI detection routines [mj]
@@ -203,6 +204,8 @@
Thanks to Tom Cavin (tec@usa1.com) for preliminary command-line option
patches.
+
+ New PCI detection code written by Martin Mares <mj@atrey.karlin.mff.cuni.cz>
All of the alpha testers deserve much thanks.
@@ -262,11 +265,11 @@
#include "hosts.h"
#include "fdomain.h"
#include <asm/system.h>
+#include <asm/spinlock.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/ioport.h>
#include <linux/proc_fs.h>
-#include <linux/bios32.h>
#include <linux/pci.h>
#include <linux/stat.h>
@@ -398,7 +401,7 @@ static int Write_SCSI_Data_port;
static int FIFO_Size = 0x2000; /* 8k FIFO for
pre-tmc18c30 chips */
-extern void fdomain_16x0_intr( int irq, void *dev_id,
+extern void do_fdomain_16x0_intr( int irq, void *dev_id,
struct pt_regs * regs );
static unsigned long addresses[] = {
@@ -749,168 +752,63 @@ static int fdomain_isa_detect( int *irq, int *iobase )
return 1; /* success */
}
-static int fdomain_pci_nobios_detect( int *irq, int *iobase )
-{
- int i;
- int flag = 0;
-
- /* The proper way of doing this is to use ask the PCI bus for the device
- IRQ and interrupt level. But we can't do that if PCI BIOS32 support
- isn't compiled into the kernel, or if a PCI BIOS32 isn't present.
-
- Instead, we scan down a bunch of addresses (Future Domain tech
- support says we will probably find the address before we get to
- 0xf800). This works fine on some systems -- other systems may have
- to scan more addresses. If you have to modify this section for your
- installation, please send mail to faith@cs.unc.edu. */
-
- for (i = 0xfff8; i > 0xe000; i -= 8) {
- if (check_region( i, 0x10 )) {
-#if DEBUG_DETECT
- printk( " (%x inuse)," , i );
-#endif
- continue;
- }
- if ((flag = fdomain_is_valid_port( i ))) break;
- }
-
- if (!flag) return 0; /* iobase not found */
-
- *irq = fdomain_get_irq( i );
- *iobase = i;
-
- return 1; /* success */
-}
-
/* PCI detection function: int fdomain_pci_bios_detect(int* irq, int*
iobase) This function gets the Interrupt Level and I/O base address from
- the PCI configuration registers. The I/O base address is masked with
- 0xfff8 since on my card the address read from the PCI config registers
- is off by one from the actual I/O base address necessary for accessing
- the status and control registers on the card (PCI config register gives
- 0xf801, actual address is 0xf800). This is likely a bug in the FD
- config code that writes to the PCI registers, however using a mask
- should be safe since I think the scan done by the card to determine the
- I/O base is done in increments of 8 (i.e., 0xf800, 0xf808, ...), at
- least the old scan code we used to use to get the I/O base did... Also,
- the device ID from the PCI config registers is 0x0 and should be 0x60e9
- as it is in the status registers (offset 5 from I/O base). If this is
- changed in future hardware/BIOS changes it will need to be fixed in this
- detection function. Comments, bug reports, etc... on this function
- should be sent to mckinley@msupa.pa.msu.edu - James T. McKinley. */
+ the PCI configuration registers. */
#ifdef CONFIG_PCI
static int fdomain_pci_bios_detect( int *irq, int *iobase )
{
- int error;
- unsigned char pci_bus, pci_dev_fn; /* PCI bus & device function */
- unsigned char pci_irq; /* PCI interrupt line */
- unsigned int pci_base; /* PCI I/O base address */
- unsigned short pci_vendor, pci_device; /* PCI vendor & device IDs */
-
- /* If the PCI BIOS doesn't exist, use the old-style detection routines.
- Otherwise, get the I/O base address and interrupt from the PCI config
- registers. */
-
- if (!pcibios_present()) return fdomain_pci_nobios_detect( irq, iobase );
+ unsigned int pci_irq; /* PCI interrupt line */
+ unsigned long pci_base; /* PCI I/O base address */
+ struct pci_dev *pdev = NULL;
+
+ if (!pci_present()) return 0;
#if DEBUG_DETECT
/* Tell how to print a list of the known PCI devices from bios32 and
list vendor and device IDs being used if in debug mode. */
- printk( "\nINFO: cat /proc/pci to see list of PCI devices from bios32\n" );
+ printk( "\nINFO: use lspci -v to see list of PCI devices\n" );
printk( "\nTMC-3260 detect:"
" Using PCI Vendor ID: 0x%x, PCI Device ID: 0x%x\n",
PCI_VENDOR_ID_FD,
PCI_DEVICE_ID_FD_36C70 );
#endif
- /* We will have to change this if more than 1 PCI bus is present and the
- FD scsi host is not on the first bus (i.e., a PCI to PCI bridge,
- which is not supported by bios32 right now anyway). This should
- probably be done by a call to pcibios_find_device but I can't get it
- to work... Also the device ID reported from the PCI config registers
- does not match the device ID quoted in the tech manual or available
- from offset 5 from the I/O base address. It should be 0x60E9, but it
- is 0x0 if read from the PCI config registers. I guess the FD folks
- neglected to write it to the PCI registers... This loop is necessary
- to get the device function (at least until someone can get
- pcibios_find_device to work, I cannot but 53c7,8xx.c uses it...). */
-
- pci_bus = 0;
-
- for (pci_dev_fn = 0x0; pci_dev_fn < 0xff; pci_dev_fn++) {
- pcibios_read_config_word( pci_bus,
- pci_dev_fn,
- PCI_VENDOR_ID,
- &pci_vendor );
-
- if (pci_vendor == PCI_VENDOR_ID_FD) {
- pcibios_read_config_word( pci_bus,
- pci_dev_fn,
- PCI_DEVICE_ID,
- &pci_device );
-
- if (pci_device == PCI_DEVICE_ID_FD_36C70) {
- /* Break out once we have the correct device. If other FD
- PCI devices are added to this driver we will need to add
- an or of the other PCI_DEVICE_ID_FD_XXXXX's here. */
- break;
- } else {
- /* If we can't find an FD scsi card we give up. */
- return 0;
- }
- }
- }
+ if ((pdev = pci_find_device(PCI_VENDOR_ID_FD, PCI_DEVICE_ID_FD_36C70, pdev)) == NULL)
+ return 0;
#if DEBUG_DETECT
printk( "Future Domain 36C70 : at PCI bus %u, device %u, function %u\n",
- pci_bus,
- (pci_dev_fn & 0xf8) >> 3,
- pci_dev_fn & 7 );
+ pdev->bus->number,
+ PCI_SLOT(pdev->devfn),
+ PCI_FUNC(pdev->devfn));
#endif
/* We now have the appropriate device function for the FD board so we
just read the PCI config info from the registers. */
- if ((error = pcibios_read_config_dword( pci_bus,
- pci_dev_fn,
- PCI_BASE_ADDRESS_0,
- &pci_base ))
- || (error = pcibios_read_config_byte( pci_bus,
- pci_dev_fn,
- PCI_INTERRUPT_LINE,
- &pci_irq ))) {
- printk ( "PCI ERROR: Future Domain 36C70 not initializing"
- " due to error reading configuration space\n" );
- return 0;
- } else {
+ pci_base = pdev->base_address[0];
+ pci_irq = pdev->irq;
#if DEBUG_DETECT
printk( "TMC-3260 PCI: IRQ = %u, I/O base = 0x%lx\n",
pci_irq, pci_base );
#endif
- /* Now we have the I/O base address and interrupt from the PCI
- configuration registers. Unfortunately it seems that the I/O base
- address is off by one on my card so I mask it with 0xfff8. This
- must be some kind of goof in the FD code that does the autoconfig
- and writes to the PCI registers (or maybe I just don't understand
- something). If they fix it in later versions of the card or BIOS
- we may have to adjust the address based on the signature or
- something... */
+ /* Now we have the I/O base address and interrupt from the PCI
+ configuration registers. */
- *irq = pci_irq;
- *iobase = (pci_base & 0xfff8);
+ *irq = pci_irq;
+ *iobase = (pci_base & PCI_BASE_ADDRESS_IO_MASK);
#if DEBUG_DETECT
- printk( "TMC-3260 fix: Masking I/O base address with 0xff00.\n" );
- printk( "TMC-3260: IRQ = %d, I/O base = 0x%x\n", *irq, *iobase );
+ printk( "TMC-3260 fix: Masking I/O base address with 0xff00.\n" );
+ printk( "TMC-3260: IRQ = %d, I/O base = 0x%x\n", *irq, *iobase );
#endif
- if (!fdomain_is_valid_port( *iobase )) return 0;
- return 1;
- }
- return 0;
+ if (!fdomain_is_valid_port( *iobase )) return 0;
+ return 1;
}
#endif
@@ -978,7 +876,8 @@ int fdomain_16x0_detect( Scsi_Host_Template *tpnt )
#ifdef CONFIG_PCI
flag = fdomain_pci_bios_detect( &interrupt_level, &port_base );
#else
- flag = fdomain_pci_nobios_detect( &interrupt_level, &port_base );
+ printk(KERN_ERR "No PCI support in this kernel, giving up.\n");
+ flag = 0;
#endif
}
@@ -988,7 +887,6 @@ int fdomain_16x0_detect( Scsi_Host_Template *tpnt )
#endif
#ifdef CONFIG_PCI
printk( "\nTMC-3260 36C70 PCI scsi chip detection failed.\n" );
- printk( "Send mail to mckinley@msupa.pa.msu.edu.\n" );
#endif
return 0; /* Cannot find valid set of ports */
}
@@ -1051,7 +949,7 @@ int fdomain_16x0_detect( Scsi_Host_Template *tpnt )
/* Register the IRQ with the kernel */
retcode = request_irq( interrupt_level,
- fdomain_16x0_intr, SA_INTERRUPT, "fdomain", NULL);
+ do_fdomain_16x0_intr, SA_INTERRUPT, "fdomain", NULL);
if (retcode < 0) {
if (retcode == -EINVAL) {
@@ -1713,6 +1611,15 @@ void fdomain_16x0_intr( int irq, void *dev_id, struct pt_regs * regs )
return;
}
+void do_fdomain_16x0_intr( int irq, void *dev_id, struct pt_regs * regs )
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&io_request_lock, flags);
+ fdomain_16x0_intr(irq, dev_id, regs);
+ spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
int fdomain_16x0_queue( Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
{
if (in_command) {
diff --git a/drivers/scsi/g_NCR5380.c b/drivers/scsi/g_NCR5380.c
index 006c98d8f..9a667410a 100644
--- a/drivers/scsi/g_NCR5380.c
+++ b/drivers/scsi/g_NCR5380.c
@@ -251,7 +251,7 @@ __initfunc(int generic_NCR5380_detect(Scsi_Host_Template * tpnt)) {
instance->irq = NCR5380_probe_irq(instance, 0xffff);
if (instance->irq != IRQ_NONE)
- if (request_irq(instance->irq, generic_NCR5380_intr, SA_INTERRUPT, "NCR5380", NULL)) {
+ if (request_irq(instance->irq, do_generic_NCR5380_intr, SA_INTERRUPT, "NCR5380", NULL)) {
printk("scsi%d : IRQ%d not free, interrupts disabled\n",
instance->host_no, instance->irq);
instance->irq = IRQ_NONE;
diff --git a/drivers/scsi/g_NCR5380.h b/drivers/scsi/g_NCR5380.h
index 000449277..e0c34d9f8 100644
--- a/drivers/scsi/g_NCR5380.h
+++ b/drivers/scsi/g_NCR5380.h
@@ -155,6 +155,7 @@ int generic_NCR5380_proc_info(char* buffer, char** start, off_t offset, int leng
NCR5380_map_name = (NCR5380_map_type)((instance)->NCR5380_instance_name)
#define NCR5380_intr generic_NCR5380_intr
+#define do_NCR5380_intr do_generic_NCR5380_intr
#define NCR5380_queue_command generic_NCR5380_queue_command
#define NCR5380_abort generic_NCR5380_abort
#define NCR5380_reset generic_NCR5380_reset
diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c
index 77a9abacd..550ed7df8 100644
--- a/drivers/scsi/gdth.c
+++ b/drivers/scsi/gdth.c
@@ -23,6 +23,19 @@
* Tested with Linux 1.2.13, ..., 2.1.61 *
* *
* $Log: gdth.c,v $
+ * Revision 1.3 1998/02/25 23:52:32 ecd
+ * Final round of PCI device driver patches by Martin Mares.
+ *
+ * I could not verify each and every change to the drivers locally,
+ * please consult linux/Documentation/pci.txt to understand changes
+ * made in case patching should be necessary.
+ *
+ * Revision 1.2 1997/11/12 23:58:51 davem
+ * Merge to 2.1.63 to get the Ingo P5 bugfix.
+ * I did not touch the sound changes at all, Alan
+ * please look into that stuff as it is your
+ * territory.
+ *
* Revision 1.10 1997/10/31 12:29:57 achim
* Read heads/sectors from host drive
*
@@ -60,7 +73,7 @@
* Initial revision
*
*
- * $Id: gdth.c,v 1.10 1997/10/31 12:29:57 achim Exp $
+ * $Id: gdth.c,v 1.4 1998/04/15 14:35:26 mj Exp $
************************************************************************/
#ifdef MODULE
@@ -71,7 +84,6 @@
#include <linux/kernel.h>
#include <linux/head.h>
#include <linux/types.h>
-#include <linux/bios32.h>
#include <linux/pci.h>
#include <linux/string.h>
#include <linux/ioport.h>
@@ -83,11 +95,14 @@
#include <linux/timer.h>
#if LINUX_VERSION_CODE >= 0x020100
#include <linux/reboot.h>
+#else
+#include <linux/bios32.h>
#endif
#include <asm/dma.h>
#include <asm/system.h>
#include <asm/io.h>
+#include <asm/spinlock.h>
#if LINUX_VERSION_CODE >= 0x010300
#include <linux/blk.h>
@@ -102,6 +117,7 @@
#if LINUX_VERSION_CODE >= 0x010346
static void gdth_interrupt(int irq,void *dev_id,struct pt_regs *regs);
+static void do_gdth_interrupt(int irq,void *dev_id,struct pt_regs *regs);
#else
static void gdth_interrupt(int irq,struct pt_regs *regs);
#endif
@@ -440,7 +456,7 @@ static int gdth_search_pci(ushort device_id,ushort index,gdth_pci_str *pcistr)
TRACE(("gdth_search_pci() device_id %d, index %d\n",
device_id,index));
- if (!pcibios_present())
+ if (!pci_present())
return 0;
if (pcibios_find_device(PCI_VENDOR_ID_VORTEX,device_id,index,
@@ -448,6 +464,21 @@ static int gdth_search_pci(ushort device_id,ushort index,gdth_pci_str *pcistr)
return 0;
/* GDT PCI controller found, now read resources from config space */
+#if LINUX_VERSION_CODE >= 0x20155
+ {
+ struct pci_dev *pdev = pci_find_slot(pcistr->bus, pcistr->device_fn);
+ base0 = pdev->base_address[0];
+ base1 = pdev->base_address[1];
+ base2 = pdev->base_address[2];
+ if ((error = pcibios_read_config_dword(pcistr->bus,pcistr->device_fn,
+ PCI_ROM_ADDRESS,
+ (int *) &pcistr->bios))) {
+ printk("GDT-PCI: error %d reading configuration space", error);
+ return -1;
+ }
+ pcistr->irq = pdev->irq;
+ }
+#else
#if LINUX_VERSION_CODE >= 0x010300
#define GDTH_BASEP (int *)
#else
@@ -467,10 +498,10 @@ static int gdth_search_pci(ushort device_id,ushort index,gdth_pci_str *pcistr)
GDTH_BASEP&pcistr->bios)) ||
(error = pcibios_read_config_byte(pcistr->bus,pcistr->device_fn,
PCI_INTERRUPT_LINE,&pcistr->irq))) {
- printk("GDT-PCI: error %s reading configuration space",
- pcibios_strerror(error));
+ printk("GDT-PCI: error %d reading configuration space", error);
return -1;
}
+#endif
pcistr->device_id = device_id;
if (device_id <= PCI_DEVICE_ID_VORTEX_GDT6000B || /* GDT6000 or GDT6000B */
@@ -2124,6 +2155,15 @@ static void gdth_clear_events()
/* SCSI interface functions */
#if LINUX_VERSION_CODE >= 0x010346
+static void do_gdth_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&io_request_lock, flags);
+ gdth_interrupt(irq, dev_id, regs);
+ spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
static void gdth_interrupt(int irq,void *dev_id,struct pt_regs *regs)
#else
static void gdth_interrupt(int irq,struct pt_regs *regs)
@@ -2728,7 +2768,7 @@ int gdth_detect(Scsi_Host_Template *shtp)
save_flags(flags);
cli();
#if LINUX_VERSION_CODE >= 0x010346
- if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth",NULL))
+ if (request_irq(ha->irq,do_gdth_interrupt,SA_INTERRUPT,"gdth",NULL))
#else
if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth"))
#endif
@@ -2837,7 +2877,7 @@ int gdth_detect(Scsi_Host_Template *shtp)
save_flags(flags);
cli();
#if LINUX_VERSION_CODE >= 0x010346
- if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth",NULL))
+ if (request_irq(ha->irq,do_gdth_interrupt,SA_INTERRUPT,"gdth",NULL))
#else
if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth"))
#endif
@@ -2943,7 +2983,7 @@ int gdth_detect(Scsi_Host_Template *shtp)
save_flags(flags);
cli();
#if LINUX_VERSION_CODE >= 0x010346
- if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth",NULL))
+ if (request_irq(ha->irq,do_gdth_interrupt,SA_INTERRUPT,"gdth",NULL))
#else
if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth"))
#endif
diff --git a/drivers/scsi/gvp11.c b/drivers/scsi/gvp11.c
index b1fa60b11..0d8e89c74 100644
--- a/drivers/scsi/gvp11.c
+++ b/drivers/scsi/gvp11.c
@@ -12,6 +12,7 @@
#include <asm/amigahw.h>
#include <linux/zorro.h>
#include <asm/irq.h>
+#include <asm/spinlock.h>
#include "scsi.h"
#include "hosts.h"
@@ -51,6 +52,15 @@ static void gvp11_intr (int irq, void *dummy, struct pt_regs *fp)
}
}
+static void do_gvp11_intr (int irq, void *dummy, struct pt_regs *fp)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&io_request_lock, flags);
+ gvp11_intr(irq, dummy, fp);
+ spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
static int gvp11_xfer_mask = 0;
void gvp11_setup (char *str, int *ints)
@@ -361,7 +371,7 @@ __initfunc(int gvp11_detect(Scsi_Host_Template *tpnt))
if (num_gvp11++ == 0) {
first_instance = instance;
gvp11_template = instance->hostt;
- request_irq(IRQ_AMIGA_PORTS, gvp11_intr, 0,
+ request_irq(IRQ_AMIGA_PORTS, do_gvp11_intr, 0,
"GVP11 SCSI", gvp11_intr);
}
DMA(instance)->CNTR = GVP11_DMAC_INT_ENABLE;
diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
index e9ea1be59..078a875e6 100644
--- a/drivers/scsi/hosts.c
+++ b/drivers/scsi/hosts.c
@@ -213,6 +213,10 @@
#include "psi240i.h"
#endif
+#ifdef CONFIG_SCSI_PLUTO
+#include "pluto.h"
+#endif
+
#ifdef CONFIG_SCSI_DEBUG
#include "scsi_debug.h"
#endif
@@ -390,6 +394,9 @@ static Scsi_Host_Template builtin_scsi_hosts[] =
#ifdef CONFIG_SCSI_MAC53C94
SCSI_MAC53C94,
#endif
+#ifdef CONFIG_SCSI_PLUTO
+ PLUTO,
+#endif
#ifdef CONFIG_SCSI_SGIWD93
SGIWD93_SCSI,
#endif
diff --git a/drivers/scsi/hosts.h b/drivers/scsi/hosts.h
index f41438eea..b53d5f214 100644
--- a/drivers/scsi/hosts.h
+++ b/drivers/scsi/hosts.h
@@ -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
@@ -108,6 +109,11 @@ typedef struct SHT
const char *(* info)(struct Scsi_Host *);
/*
+ * ioctl interface
+ */
+ int (*ioctl)(Scsi_Device *dev, int cmd, void *arg);
+
+ /*
* The command function takes a target, a command (this is a SCSI
* command formatted as per the SCSI spec, nothing strange), a
* data buffer pointer, and data buffer length pointer. The return
@@ -264,6 +270,11 @@ typedef struct SHT
*/
unsigned use_new_eh_code:1;
+ /*
+ * True for emulated SCSI host adapters (e.g. ATAPI)
+ */
+ unsigned emulated:1;
+
} Scsi_Host_Template;
/*
@@ -332,7 +343,7 @@ struct Scsi_Host
/* These parameters should be set by the detect routine */
unsigned char *base;
- unsigned int io_port;
+ unsigned long io_port;
unsigned char n_io_port;
unsigned char irq;
unsigned char dma_channel;
@@ -374,7 +385,7 @@ struct Scsi_Host
/*
* We should ensure that this is aligned, both for better performance
* and also because some compilers (m68k) don't automatically force
- * alignment to a 4-byte boundary.
+ * alignment to a long boundary.
*/
unsigned long hostdata[0] /* Used for storage of host specific stuff */
__attribute__ ((aligned (sizeof(unsigned long))));
@@ -456,8 +467,15 @@ extern void scsi_unregister_module(int, void *);
* we need to leave extra room in some of the data structures. Doing a
* realloc to enlarge the structures would be riddled with race conditions,
* so until a better solution is discovered, we use this crude approach
+ *
+ * Even bigger hack for SparcSTORAGE arrays. Those are at least 6 disks, but
+ * usually up to 30 disks, so everyone would need to change this. -jj
*/
-#define SD_EXTRA_DEVS 2
+#ifdef CONFIG_SCSI_PLUTO_MODULE
+#define SD_EXTRA_DEVS 40
+#else
+#define SD_EXTRA_DEVS 4
+#endif
#define ST_EXTRA_DEVS 2
#define SR_EXTRA_DEVS 2
#define SG_EXTRA_DEVS (SD_EXTRA_DEVS + SR_EXTRA_DEVS + ST_EXTRA_DEVS)
diff --git a/drivers/scsi/ibmmca.c b/drivers/scsi/ibmmca.c
index 60be3c619..034b219cc 100644
--- a/drivers/scsi/ibmmca.c
+++ b/drivers/scsi/ibmmca.c
@@ -298,6 +298,7 @@
#include <linux/stat.h>
#include <linux/mca.h>
#include <asm/system.h>
+#include <asm/spinlock.h>
#include <asm/io.h>
#include "sd.h"
#include "scsi.h"
@@ -834,6 +835,7 @@ static struct Scsi_Host *hosts[IM_MAX_HOSTS+1] = { NULL };
/*local functions in forward declaration */
static void interrupt_handler (int irq, void *dev_id, struct pt_regs *regs);
+static void do_interrupt_handler (int irq, void *dev_id, struct pt_regs *regs);
static void issue_cmd (struct Scsi_Host *shpnt, unsigned long cmd_reg,
unsigned char attn_reg);
static void internal_done (Scsi_Cmnd * cmd);
@@ -856,6 +858,17 @@ static int ldn_access_total_read_write(struct Scsi_Host *shpnt);
/*--------------------------------------------------------------------*/
+
+static void
+do_interrupt_handler (int irq, void *dev_id, struct pt_regs *regs)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&io_request_lock, flags);
+ interrupt_handler(irq, dev_id, regs);
+ spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
static void
interrupt_handler (int irq, void *dev_id, struct pt_regs *regs)
{
@@ -1526,7 +1539,7 @@ ibmmca_detect (Scsi_Host_Template * template)
return 0;
/* get interrupt request level */
- if (request_irq (IM_IRQ, interrupt_handler, SA_SHIRQ, "ibmmca", hosts))
+ if (request_irq (IM_IRQ, do_interrupt_handler, SA_SHIRQ, "ibmmca", hosts))
{
printk("IBM MCA SCSI: Unable to get IRQ %d.\n", IM_IRQ);
return 0;
diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c
index 0bfa8d876..d81cb5187 100644
--- a/drivers/scsi/ide-scsi.c
+++ b/drivers/scsi/ide-scsi.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/scsi/ide-scsi.c Version 0.5 Jan 2, 1998
+ * linux/drivers/scsi/ide-scsi.c Version 0.6 Jan 27, 1998
*
* Copyright (C) 1996 - 1998 Gadi Oxman <gadio@netvision.net.il>
*/
@@ -20,9 +20,12 @@
* Use variable timeout for each command.
* Ver 0.5 Jan 2 98 Fix previous PD/CD support.
* Allow disabling of SCSI-6 to SCSI-10 transformation.
+ * Ver 0.6 Jan 27 98 Allow disabling of SCSI command translation layer
+ * for access through /dev/sg.
+ * Fix MODE_SENSE_6/MODE_SELECT_6/INQUIRY translation.
*/
-#define IDESCSI_VERSION "0.5"
+#define IDESCSI_VERSION "0.6"
#include <linux/module.h>
#include <linux/types.h>
@@ -37,6 +40,7 @@
#include <asm/io.h>
#include <asm/bitops.h>
+#include <asm/uaccess.h>
#include "../block/ide.h"
@@ -44,6 +48,7 @@
#include "hosts.h"
#include "sd.h"
#include "ide-scsi.h"
+#include <scsi/sg.h>
#define IDESCSI_DEBUG_LOG 0
@@ -68,12 +73,25 @@ typedef struct idescsi_pc_s {
*/
#define PC_DMA_IN_PROGRESS 0 /* 1 while DMA in progress */
#define PC_WRITING 1 /* Data direction */
+#define PC_TRANSFORM 2 /* transform SCSI commands */
+
+/*
+ * SCSI command transformation layer
+ */
+#define IDESCSI_TRANSFORM 0 /* Enable/Disable transformation */
+#define IDESCSI_SG_TRANSFORM 1 /* /dev/sg transformation */
+
+/*
+ * Log flags
+ */
+#define IDESCSI_LOG_CMD 0 /* Log SCSI commands */
typedef struct {
ide_drive_t *drive;
idescsi_pc_t *pc; /* Current packet command */
unsigned int flags; /* Status/Action flags */
- int transform; /* Transform SCSI-6 commands */
+ int transform; /* SCSI cmd translation layer */
+ int log; /* log flags */
} idescsi_scsi_t;
/*
@@ -153,11 +171,10 @@ static void idescsi_output_buffers (ide_drive_t *drive, idescsi_pc_t *pc, unsign
*/
static inline void idescsi_transform_pc1 (ide_drive_t *drive, idescsi_pc_t *pc)
{
- idescsi_scsi_t *scsi = drive->driver_data;
- u8 *c = pc->c, *buf = pc->buffer, *sc = pc->scsi_cmd->cmnd;
- int i;
+ u8 *c = pc->c, *scsi_buf = pc->buffer, *sc = pc->scsi_cmd->cmnd;
+ char *atapi_buf;
- if (!scsi->transform)
+ if (!test_bit(PC_TRANSFORM, &pc->flags))
return;
if (drive->media == ide_cdrom) {
if (c[0] == READ_6 || c[0] == WRITE_6) {
@@ -165,35 +182,54 @@ static inline void idescsi_transform_pc1 (ide_drive_t *drive, idescsi_pc_t *pc)
c[3] = c[1] & 0x1f; c[2] = 0; c[1] &= 0xe0;
c[0] += (READ_10 - READ_6);
}
- if (c[0] == MODE_SENSE || (c[0] == MODE_SELECT && buf[3] == 8)) {
- pc->request_transfer -= 4;
+ if (c[0] == MODE_SENSE || c[0] == MODE_SELECT) {
+ if (!scsi_buf)
+ return;
+ if ((atapi_buf = kmalloc(pc->buffer_size + 4, GFP_ATOMIC)) == NULL)
+ return;
+ memset(atapi_buf, 0, pc->buffer_size + 4);
memset (c, 0, 12);
- c[0] = sc[0] | 0x40; c[2] = sc[2]; c[8] = sc[4] - 4;
- if (c[0] == MODE_SENSE_10) return;
- for (i = 0; i <= 7; i++) buf[i] = 0;
- for (i = 8; i < pc->buffer_size - 4; i++) buf[i] = buf[i + 4];
+ c[0] = sc[0] | 0x40; c[1] = sc[1]; c[2] = sc[2];
+ c[8] = sc[4] + 4; c[9] = sc[5];
+ if (sc[4] + 4 > 255)
+ c[7] = sc[4] + 4 - 255;
+ if (c[0] == MODE_SELECT_10) {
+ atapi_buf[1] = scsi_buf[0]; /* Mode data length */
+ atapi_buf[2] = scsi_buf[1]; /* Medium type */
+ atapi_buf[3] = scsi_buf[2]; /* Device specific parameter */
+ atapi_buf[7] = scsi_buf[3]; /* Block descriptor length */
+ memcpy(atapi_buf + 8, scsi_buf + 4, pc->buffer_size - 4);
+ }
+ pc->buffer = atapi_buf;
+ pc->request_transfer += 4;
+ pc->buffer_size += 4;
}
}
}
static inline void idescsi_transform_pc2 (ide_drive_t *drive, idescsi_pc_t *pc)
{
- idescsi_scsi_t *scsi = drive->driver_data;
- u8 *buf = pc->buffer;
- int i;
+ u8 *atapi_buf = pc->buffer;
+ u8 *sc = pc->scsi_cmd->cmnd;
+ u8 *scsi_buf = pc->scsi_cmd->request_buffer;
- if (!scsi->transform)
+ if (!test_bit(PC_TRANSFORM, &pc->flags))
return;
if (drive->media == ide_cdrom) {
- if (pc->c[0] == MODE_SENSE_10 && pc->scsi_cmd->cmnd[0] == MODE_SENSE) {
- buf[0] = buf[1]; buf[1] = buf[2];
- buf[2] = 0; buf[3] = 8;
- for (i = pc->buffer_size - 1; i >= 12; i--) buf[i] = buf[i - 4];
- for (i = 11; i >= 4; i--) buf[i] = 0;
+ if (pc->c[0] == MODE_SENSE_10 && sc[0] == MODE_SENSE) {
+ scsi_buf[0] = atapi_buf[1]; /* Mode data length */
+ scsi_buf[1] = atapi_buf[2]; /* Medium type */
+ scsi_buf[2] = atapi_buf[3]; /* Device specific parameter */
+ scsi_buf[3] = atapi_buf[7]; /* Block descriptor length */
+ memcpy(scsi_buf + 4, atapi_buf + 8, pc->request_transfer - 8);
+ }
+ if (pc->c[0] == INQUIRY) {
+ scsi_buf[2] |= 2; /* ansi_revision */
+ scsi_buf[3] = (scsi_buf[3] & 0xf0) | 2; /* response data format */
}
- if (pc->c[0] == INQUIRY)
- buf[2] |= 2;
}
+ if (atapi_buf && atapi_buf != scsi_buf)
+ kfree(atapi_buf);
}
static inline void idescsi_free_bh (struct buffer_head *bh)
@@ -207,12 +243,24 @@ static inline void idescsi_free_bh (struct buffer_head *bh)
}
}
+static void hexdump(u8 *x, int len)
+{
+ int i;
+
+ printk("[ ");
+ for (i = 0; i < len; i++)
+ printk("%x ", x[i]);
+ printk("]\n");
+}
+
static void idescsi_end_request (byte uptodate, ide_hwgroup_t *hwgroup)
{
ide_drive_t *drive = hwgroup->drive;
idescsi_scsi_t *scsi = drive->driver_data;
struct request *rq = hwgroup->rq;
idescsi_pc_t *pc = (idescsi_pc_t *) rq->buffer;
+ int log = test_bit(IDESCSI_LOG_CMD, &scsi->log);
+ u8 *scsi_buf = pc->scsi_cmd->request_buffer;
if (rq->cmd != IDESCSI_PC_RQ) {
ide_end_request (uptodate, hwgroup);
@@ -220,21 +268,23 @@ static void idescsi_end_request (byte uptodate, ide_hwgroup_t *hwgroup)
}
ide_end_drive_cmd (drive, 0, 0);
if (rq->errors >= ERROR_MAX) {
-#if IDESCSI_DEBUG_LOG
- printk ("ide-scsi: %s: I/O error for %lu\n", drive->name, pc->scsi_cmd->serial_number);
-#endif /* IDESCSI_DEBUG_LOG */
pc->scsi_cmd->result = DID_ERROR << 16;
+ if (log)
+ printk ("ide-scsi: %s: I/O error for %lu\n", drive->name, pc->scsi_cmd->serial_number);
} else if (rq->errors) {
-#if IDESCSI_DEBUG_LOG
- printk ("ide-scsi: %s: check condition for %lu\n", drive->name, pc->scsi_cmd->serial_number);
-#endif /* IDESCSI_DEBUG_LOG */
pc->scsi_cmd->result = (CHECK_CONDITION << 1) | (DID_OK << 16);
+ if (log)
+ printk ("ide-scsi: %s: check condition for %lu\n", drive->name, pc->scsi_cmd->serial_number);
} else {
-#if IDESCSI_DEBUG_LOG
- printk ("ide-scsi: %s: success for %lu\n", drive->name, pc->scsi_cmd->serial_number);
-#endif /* IDESCSI_DEBUG_LOG */
pc->scsi_cmd->result = DID_OK << 16;
idescsi_transform_pc2 (drive, pc);
+ if (log) {
+ printk ("ide-scsi: %s: suc %lu", drive->name, pc->scsi_cmd->serial_number);
+ if (!test_bit(PC_WRITING, &pc->flags) && pc->actually_transferred && pc->actually_transferred <= 1024 && pc->buffer) {
+ printk(", rst = ");
+ hexdump(scsi_buf, IDE_MIN(16, pc->scsi_cmd->request_bufflen));
+ } else printk("\n");
+ }
}
pc->done(pc->scsi_cmd);
idescsi_free_bh (rq->bh);
@@ -274,9 +324,8 @@ static void idescsi_pc_intr (ide_drive_t *drive)
status = GET_STAT(); /* Clear the interrupt */
if ((status & DRQ_STAT) == 0) { /* No more interrupts */
-#if IDESCSI_DEBUG_LOG
- printk (KERN_INFO "Packet command completed, %d bytes transferred\n", pc->actually_transferred);
-#endif /* IDESCSI_DEBUG_LOG */
+ if (test_bit(IDESCSI_LOG_CMD, &scsi->log))
+ printk (KERN_INFO "Packet command completed, %d bytes transferred\n", pc->actually_transferred);
ide_sti();
if (status & ERR_STAT)
rq->errors++;
@@ -306,11 +355,13 @@ static void idescsi_pc_intr (ide_drive_t *drive)
}
}
if (ireason & IDESCSI_IREASON_IO) {
+ clear_bit(PC_WRITING, &pc->flags);
if (pc->sg)
idescsi_input_buffers (drive, pc, bcount);
else
atapi_input_bytes (drive,pc->current_position,bcount);
} else {
+ set_bit(PC_WRITING, &pc->flags);
if (pc->sg)
idescsi_output_buffers (drive, pc, bcount);
else
@@ -421,7 +472,8 @@ static void idescsi_add_settings(ide_drive_t *drive)
ide_add_setting(drive, "bios_cyl", SETTING_RW, -1, -1, TYPE_SHORT, 0, 1023, 1, 1, &drive->bios_cyl, NULL);
ide_add_setting(drive, "bios_head", SETTING_RW, -1, -1, TYPE_BYTE, 0, 255, 1, 1, &drive->bios_head, NULL);
ide_add_setting(drive, "bios_sect", SETTING_RW, -1, -1, TYPE_BYTE, 0, 63, 1, 1, &drive->bios_sect, NULL);
- ide_add_setting(drive, "transform", SETTING_RW, -1, -1, TYPE_INT, 0, 1, 1, 1, &scsi->transform, NULL);
+ ide_add_setting(drive, "transform", SETTING_RW, -1, -1, TYPE_INT, 0, 3, 1, 1, &scsi->transform, NULL);
+ ide_add_setting(drive, "log", SETTING_RW, -1, -1, TYPE_INT, 0, 1, 1, 1, &scsi->log, NULL);
}
/*
@@ -437,7 +489,11 @@ static void idescsi_setup (ide_drive_t *drive, idescsi_scsi_t *scsi, int id)
scsi->drive = drive;
if (drive->id && (drive->id->config & 0x0060) == 0x20)
set_bit (IDESCSI_DRQ_INTERRUPT, &scsi->flags);
- scsi->transform = 1;
+ set_bit(IDESCSI_TRANSFORM, &scsi->transform);
+ clear_bit(IDESCSI_SG_TRANSFORM, &scsi->transform);
+#if IDESCSI_DEBUG_LOG
+ set_bit(IDESCSI_LOG_CMD, &scsi->log);
+#endif /* IDESCSI_DEBUG_LOG */
idescsi_add_settings(drive);
}
@@ -554,6 +610,19 @@ const char *idescsi_info (struct Scsi_Host *host)
return "SCSI host adapter emulation for IDE ATAPI devices";
}
+int idescsi_ioctl (Scsi_Device *dev, int cmd, void *arg)
+{
+ ide_drive_t *drive = idescsi_drives[dev->id];
+ idescsi_scsi_t *scsi = drive->driver_data;
+
+ if (cmd == SG_SET_TRANSFORM) {
+ set_bit(IDESCSI_SG_TRANSFORM, &scsi->transform);
+ return 0;
+ } else if (cmd == SG_GET_TRANSFORM)
+ return put_user(test_bit(IDESCSI_SG_TRANSFORM, &scsi->transform), (int *) arg);
+ return -EINVAL;
+}
+
static inline struct buffer_head *idescsi_kmalloc_bh (int count)
{
struct buffer_head *bh, *bhp, *first_bh;
@@ -624,20 +693,27 @@ static inline struct buffer_head *idescsi_dma_bh (ide_drive_t *drive, idescsi_pc
return first_bh;
}
+static inline int should_transform(ide_drive_t *drive, Scsi_Cmnd *cmd)
+{
+ idescsi_scsi_t *scsi = drive->driver_data;
+
+ if (MAJOR(cmd->request.rq_dev) == SCSI_GENERIC_MAJOR)
+ return test_bit(IDESCSI_SG_TRANSFORM, &scsi->transform);
+ return test_bit(IDESCSI_TRANSFORM, &scsi->transform);
+}
+
int idescsi_queue (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
{
ide_drive_t *drive = idescsi_drives[cmd->target];
+ idescsi_scsi_t *scsi;
struct request *rq = NULL;
idescsi_pc_t *pc = NULL;
-#if IDESCSI_DEBUG_LOG
- printk ("idescsi_queue called, serial = %lu, cmd[0] = %x, id = %d\n", cmd->serial_number, cmd->cmnd[0], cmd->target);
-#endif /* IDESCSI_DEBUG_LOG */
-
if (!drive) {
printk (KERN_ERR "ide-scsi: drive id %d not present\n", cmd->target);
goto abort;
}
+ scsi = drive->driver_data;
pc = kmalloc (sizeof (idescsi_pc_t), GFP_ATOMIC);
rq = kmalloc (sizeof (struct request), GFP_ATOMIC);
if (rq == NULL || pc == NULL) {
@@ -661,8 +737,20 @@ int idescsi_queue (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
pc->scsi_cmd = cmd;
pc->done = done;
pc->timeout = jiffies + cmd->timeout_per_command;
+
+ if (should_transform(drive, cmd))
+ set_bit(PC_TRANSFORM, &pc->flags);
idescsi_transform_pc1 (drive, pc);
+ if (test_bit(IDESCSI_LOG_CMD, &scsi->log)) {
+ printk ("ide-scsi: %s: que %lu, cmd = ", drive->name, cmd->serial_number);
+ hexdump(cmd->cmnd, cmd->cmd_len);
+ if (memcmp(pc->c, cmd->cmnd, cmd->cmd_len)) {
+ printk ("ide-scsi: %s: que %lu, tsl = ", drive->name, cmd->serial_number);
+ hexdump(pc->c, 12);
+ }
+ }
+
ide_init_drive_cmd (rq);
rq->buffer = (char *) pc;
rq->bh = idescsi_dma_bh (drive, pc);
diff --git a/drivers/scsi/ide-scsi.h b/drivers/scsi/ide-scsi.h
index 360850d75..84fab9263 100644
--- a/drivers/scsi/ide-scsi.h
+++ b/drivers/scsi/ide-scsi.h
@@ -10,6 +10,7 @@
extern int idescsi_detect (Scsi_Host_Template *host_template);
extern int idescsi_release (struct Scsi_Host *host);
extern const char *idescsi_info (struct Scsi_Host *host);
+extern int idescsi_ioctl (Scsi_Device *dev, int cmd, void *arg);
extern int idescsi_queue (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *));
extern int idescsi_abort (Scsi_Cmnd *cmd);
extern int idescsi_reset (Scsi_Cmnd *cmd, unsigned int resetflags);
@@ -20,6 +21,7 @@ extern int idescsi_bios (Disk *disk, kdev_t dev, int *parm);
detect: idescsi_detect, /* detect */ \
release: idescsi_release, /* release */ \
info: idescsi_info, /* info */ \
+ ioctl: idescsi_ioctl, /* ioctl */ \
queuecommand: idescsi_queue, /* queuecommand */ \
abort: idescsi_abort, /* abort */ \
reset: idescsi_reset, /* reset */ \
@@ -28,7 +30,8 @@ extern int idescsi_bios (Disk *disk, kdev_t dev, int *parm);
this_id: -1, /* this_id */ \
sg_tablesize: 256, /* sg_tablesize */ \
cmd_per_lun: 5, /* cmd_per_lun */ \
- use_clustering: DISABLE_CLUSTERING /* clustering */ \
+ use_clustering: DISABLE_CLUSTERING, /* clustering */ \
+ emulated: 1 /* emulated */ \
}
#endif /* IDESCSI_H */
diff --git a/drivers/scsi/in2000.c b/drivers/scsi/in2000.c
index d493fa167..7e11430d4 100644
--- a/drivers/scsi/in2000.c
+++ b/drivers/scsi/in2000.c
@@ -117,14 +117,15 @@
#include <linux/blk.h>
#include <linux/stat.h>
+#include <asm/spinlock.h>
#include "scsi.h"
#include "sd.h"
#include "hosts.h"
-#define IN2000_VERSION "1.31"
-#define IN2000_DATE "06/July/1997"
+#define IN2000_VERSION "1.32"
+#define IN2000_DATE "28/March/1998"
/*
* Note - the following defines have been moved to 'in2000.h':
@@ -1638,7 +1639,14 @@ DB(DB_INTR,printk("} "))
}
+static void do_in2000_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&io_request_lock, flags);
+ in2000_intr(irq, dev_id, regs);
+ spin_unlock_irqrestore(&io_request_lock, flags);
+}
#define RESET_CARD 0
#define RESET_CARD_AND_BUS 1
@@ -2031,18 +2039,12 @@ char buf[32];
continue;
}
-/* Let's expect only known legal hardware version here. There
- * can't be THAT many of them, and it's easy to add new ones
- * as we hear about them.
+/* Let's assume any hardware version will work, although the driver
+ * has only been tested on 0x21, 0x22, 0x25, 0x26, and 0x27. We'll
+ * print out the rev number for reference later, but accept them all.
*/
hrev = inb(base + IO_HARDWARE);
- if ((hrev != 0x27) && (hrev != 0x26) && (hrev != 0x25)) {
- printk("The IN-2000 SCSI card at IOport 0x%03x ",base);
- printk("has unknown version %02x hardware - ",hrev);
- printk("Sorry, cancelling detection.\n");
- continue;
- }
/* Bit 2 tells us if interrupts are disabled */
if (switches & SW_DISINT) {
@@ -2070,7 +2072,7 @@ char buf[32];
write1_io(0,IO_FIFO_READ); /* start fifo out in read mode */
write1_io(0,IO_INTR_MASK); /* allow all ints */
x = int_tab[(switches & (SW_INT0 | SW_INT1)) >> SW_INT_SHIFT];
- if (request_irq(x, in2000_intr, SA_INTERRUPT, "in2000", NULL)) {
+ if (request_irq(x, do_in2000_intr, SA_INTERRUPT, "in2000", NULL)) {
printk("in2000_detect: Unable to allocate IRQ.\n");
detect_count--;
continue;
diff --git a/drivers/scsi/in2000.h b/drivers/scsi/in2000.h
index 557ca60e8..9e011a7e6 100644
--- a/drivers/scsi/in2000.h
+++ b/drivers/scsi/in2000.h
@@ -2,7 +2,7 @@
* in2000.h - Linux device driver definitions for the
* Always IN2000 ISA SCSI card.
*
- * IMPORTANT: This file is for version 1.31 - 06/Jul/1997
+ * IMPORTANT: This file is for version 1.32 - 28/Mar/1998
*
* Copyright (c) 1996 John Shifflett, GeoLog Consulting
* john@geolog.com
@@ -404,8 +404,8 @@ int in2000_reset(Scsi_Cmnd *, unsigned int);
this_id: IN2000_HOST_ID, /* host-adapter scsi id */ \
sg_tablesize: IN2000_SG, /* scatter-gather table size */ \
cmd_per_lun: IN2000_CPL, /* commands per lun */ \
- use_clustering: DISABLE_CLUSTERING, \
- use_new_eh_code: 0 /* Enable new error code */ \
+ use_clustering: DISABLE_CLUSTERING, /* ENABLE_CLUSTERING may speed things up */ \
+ use_new_eh_code: 0 /* new error code - not using it yet */ \
}
diff --git a/drivers/scsi/jazz_esp.c b/drivers/scsi/jazz_esp.c
index 2669e718a..9065ef3d3 100644
--- a/drivers/scsi/jazz_esp.c
+++ b/drivers/scsi/jazz_esp.c
@@ -119,7 +119,8 @@ int jazz_esp_detect(Scsi_Host_Template *tpnt)
esp->esp_command_dvma = vdma_alloc(PHYSADDR(cmd_buffer), sizeof (cmd_buffer));
esp->irq = JAZZ_SCSI_IRQ;
- request_irq(JAZZ_SCSI_IRQ, esp_intr, SA_INTERRUPT, "JAZZ SCSI", esp_intr);
+ request_irq(JAZZ_SCSI_IRQ, do_esp_intr, SA_INTERRUPT, "JAZZ SCSI",
+ NULL);
/*
* FIXME, look if the scsi id is availabe from NVRAM
diff --git a/drivers/scsi/mac53c94.c b/drivers/scsi/mac53c94.c
index e7d1470ae..a779a3b2b 100644
--- a/drivers/scsi/mac53c94.c
+++ b/drivers/scsi/mac53c94.c
@@ -19,6 +19,7 @@
#include <asm/io.h>
#include <asm/prom.h>
#include <asm/system.h>
+#include <asm/spinlock.h>
#include "scsi.h"
#include "hosts.h"
@@ -57,6 +58,7 @@ static struct fsc_state *all_53c94s;
static void mac53c94_init(struct fsc_state *);
static void mac53c94_start(struct fsc_state *);
static void mac53c94_interrupt(int, void *, struct pt_regs *);
+static void do_mac53c94_interrupt(int, void *, struct pt_regs *);
static void cmd_done(struct fsc_state *, int result);
static void set_dma_cmds(struct fsc_state *, Scsi_Cmnd *);
static int data_goes_out(Scsi_Cmnd *);
@@ -117,7 +119,7 @@ mac53c94_detect(Scsi_Host_Template *tp)
*prev_statep = state;
prev_statep = &state->next;
- if (request_irq(state->intr, mac53c94_interrupt, 0,
+ if (request_irq(state->intr, do_mac53c94_interrupt, 0,
"53C94", state)) {
printk(KERN_ERR "mac53C94: can't get irq %d\n", state->intr);
}
@@ -271,6 +273,16 @@ mac53c94_start(struct fsc_state *state)
}
static void
+do_mac53c94_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&io_request_lock, flags);
+ mac53c94_interrupt(irq, dev_id, ptregs);
+ spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
+static void
mac53c94_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
{
struct fsc_state *state = (struct fsc_state *) dev_id;
diff --git a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c
index 501aff777..1f134d797 100644
--- a/drivers/scsi/mesh.c
+++ b/drivers/scsi/mesh.c
@@ -23,6 +23,7 @@
#include <asm/io.h>
#include <asm/prom.h>
#include <asm/system.h>
+#include <asm/spinlock.h>
#include "scsi.h"
#include "hosts.h"
@@ -138,6 +139,7 @@ static void phase_mismatch(struct mesh_state *);
static void reselected(struct mesh_state *);
static void handle_reset(struct mesh_state *);
static void mesh_interrupt(int, void *, struct pt_regs *);
+static void do_mesh_interrupt(int, void *, struct pt_regs *);
static void handle_msgin(struct mesh_state *);
static void mesh_done(struct mesh_state *);
static void mesh_completed(struct mesh_state *, Scsi_Cmnd *);
@@ -207,7 +209,7 @@ mesh_detect(Scsi_Host_Template *tp)
*prev_statep = ms;
prev_statep = &ms->next;
- if (request_irq(ms->meshintr, mesh_interrupt, 0, "MESH", ms)) {
+ if (request_irq(ms->meshintr, do_mesh_interrupt, 0, "MESH", ms)) {
printk(KERN_ERR "MESH: can't get irq %d\n", ms->meshintr);
}
@@ -976,6 +978,16 @@ handle_reset(struct mesh_state *ms)
}
static void
+do_mesh_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&io_request_lock, flags);
+ mesh_interrupt(irq, dev_id, ptregs);
+ spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
+static void
mesh_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
{
struct mesh_state *ms = (struct mesh_state *) dev_id;
diff --git a/drivers/scsi/mvme16x.c b/drivers/scsi/mvme16x.c
index c3ab67906..a0cc07494 100644
--- a/drivers/scsi/mvme16x.c
+++ b/drivers/scsi/mvme16x.c
@@ -8,7 +8,6 @@
#include <linux/blk.h>
#include <linux/sched.h>
#include <linux/version.h>
-#include <linux/config.h>
#include <linux/zorro.h>
#include <asm/page.h>
diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c
index 7956db9d1..577f97b4c 100644
--- a/drivers/scsi/ncr53c8xx.c
+++ b/drivers/scsi/ncr53c8xx.c
@@ -112,11 +112,11 @@
#include <asm/dma.h>
#include <asm/io.h>
#include <asm/system.h>
+#include <asm/spinlock.h>
#include <linux/delay.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/errno.h>
-#include <linux/bios32.h>
#include <linux/pci.h>
#include <linux/string.h>
#include <linux/malloc.h>
@@ -141,6 +141,7 @@
#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,35)
#include <linux/init.h>
#else
+#include <linux/bios32.h>
#ifndef __initdata
#define __initdata
#endif
@@ -280,8 +281,12 @@ typedef u32 u_int32;
typedef u_long vm_offset_t;
typedef int vm_size_t;
+#ifndef bcopy
#define bcopy(s, d, n) memcpy((d), (s), (n))
+#endif
+#ifndef bzero
#define bzero(d, n) memset((d), 0, (n))
+#endif
#ifndef offsetof
#define offsetof(t, m) ((size_t) (&((t *)0)->m))
@@ -316,6 +321,12 @@ typedef int vm_size_t;
** architecture.
*/
+#ifdef __sparc__
+#define remap_pci_mem(base, size) ((vm_offset_t) __va(base))
+#define unmap_pci_mem(vaddr, size)
+#define pcivtophys(p) ((p) & pci_dvma_mask)
+#else /* __sparc__ */
+#define pcivtophys(p) (p)
#ifndef NCR_IOMAPPED
__initfunc(
static vm_offset_t remap_pci_mem(u_long base, u_long size)
@@ -344,6 +355,7 @@ static void unmap_pci_mem(vm_offset_t vaddr, u_long size)
#endif
}
#endif /* !NCR_IOMAPPED */
+#endif /* __sparc__ */
#else /* linux-1.2.13 */
@@ -553,6 +565,7 @@ static void ncr53c8xx_select_queue_depths(struct Scsi_Host *host, struct scsi_de
#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,70)
static void ncr53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs);
+static void do_ncr53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs);
#else
static void ncr53c8xx_intr(int irq, struct pt_regs * regs);
#endif
@@ -674,12 +687,12 @@ static u_char Tekram_sync[12] __initdata = {25,31,37,43,50,62,75,125,12,15,18,21
typedef struct {
int bus;
u_char device_fn;
- u_int base;
- u_int base_2;
- u_int io_port;
+ u_long base;
+ u_long base_2;
+ u_long io_port;
int irq;
/* port and reg fields to use INB, OUTB macros */
- u_int port;
+ u_long port;
volatile struct ncr_reg *reg;
} ncr_slot;
@@ -1806,8 +1819,8 @@ struct ncb {
** Profiling data
*/
struct profile profile;
- u_long disc_phys;
- u_long disc_ref;
+ u_int disc_phys;
+ u_int disc_ref;
/*
** The global control block.
@@ -1845,12 +1858,12 @@ struct ncb {
/*
** address of the ncr control registers in io space
*/
- u_int port;
+ u_long port;
/*
** irq level
*/
- u_short irq;
+ u_int irq;
};
#define NCB_SCRIPT_PHYS(np,lbl) (np->p_script + offsetof (struct script, lbl))
@@ -3806,7 +3819,8 @@ static void ncr_script_copy_and_bind (ncb_p np, ncrcmd *src, ncrcmd *dst, int le
switch (old & RELOC_MASK) {
case RELOC_REGISTER:
- new = (old & ~RELOC_MASK) + np->paddr;
+ new = (old & ~RELOC_MASK)
+ + pcivtophys(np->paddr);
break;
case RELOC_LABEL:
new = (old & ~RELOC_MASK) + np->p_script;
@@ -4399,9 +4413,15 @@ static int ncr_attach (Scsi_Host_Template *tpnt, int unit, ncr_device *device)
u_long flags = 0;
ncr_nvram *nvram = device->nvram;
-printf(KERN_INFO "ncr53c%s-%d: rev=0x%02x, base=0x%x, io_port=0x%x, irq=%d\n",
+#ifdef __sparc__
+printf(KERN_INFO "ncr53c%s-%d: rev=0x%02x, base=0x%lx, io_port=0x%lx, irq=0x%x\n",
device->chip.name, unit, device->chip.revision_id, device->slot.base,
device->slot.io_port, device->slot.irq);
+#else
+printf(KERN_INFO "ncr53c%s-%d: rev=0x%02x, base=0x%lx, io_port=0x%lx, irq=%d\n",
+ device->chip.name, unit, device->chip.revision_id, device->slot.base,
+ device->slot.io_port, device->slot.irq);
+#endif
/*
** Allocate host_data structure
@@ -4554,7 +4574,7 @@ printf(KERN_INFO "ncr53c%s-%d: rev=0x%02x, base=0x%x, io_port=0x%x, irq=%d\n",
np->p_scripth = vtophys(np->scripth);
np->script = (np->vaddr2) ? (struct script *) np->vaddr2 : np->script0;
- np->p_script = (np->vaddr2) ? np->paddr2 : vtophys(np->script0);
+ np->p_script = (np->vaddr2) ? pcivtophys(np->paddr2) : vtophys(np->script0);
ncr_script_copy_and_bind (np, (ncrcmd *) &script0, (ncrcmd *) np->script0, sizeof(struct script));
ncr_script_copy_and_bind (np, (ncrcmd *) &scripth0, (ncrcmd *) np->scripth0, sizeof(struct scripth));
@@ -4605,10 +4625,10 @@ printf(KERN_INFO "ncr53c%s-%d: rev=0x%02x, base=0x%x, io_port=0x%x, irq=%d\n",
if (bootverbose > 1)
printf("%s: requesting shared irq %d (dev_id=0x%lx)\n",
ncr_name(np), device->slot.irq, (u_long) np);
- if (request_irq(device->slot.irq, ncr53c8xx_intr,
+ if (request_irq(device->slot.irq, do_ncr53c8xx_intr,
SA_INTERRUPT|SA_SHIRQ, "ncr53c8xx", np)) {
#else
- if (request_irq(device->slot.irq, ncr53c8xx_intr,
+ if (request_irq(device->slot.irq, do_ncr53c8xx_intr,
SA_INTERRUPT, "ncr53c8xx", np)) {
#endif
#else
@@ -4629,7 +4649,7 @@ printf(KERN_INFO "ncr53c%s-%d: rev=0x%02x, base=0x%x, io_port=0x%x, irq=%d\n",
** Then enable disconnects.
*/
save_flags(flags); cli();
- if (ncr_reset_scsi_bus(np, 0, driver_setup.settle_delay) != 0) {
+ if (ncr_reset_scsi_bus(np, 1, driver_setup.settle_delay) != 0) {
printf("%s: FATAL ERROR: CHECK SCSI BUS - CABLES, TERMINATION, DEVICE POWER etc.!\n", ncr_name(np));
restore_flags(flags);
goto attach_error;
@@ -5515,8 +5535,12 @@ static int ncr_detach(ncb_p np)
*/
#ifdef DEBUG_NCR53C8XX
+#ifdef __sparc__
+ printf("%s: freeing irq 0x%x\n", ncr_name(np), np->irq);
+#else
printf("%s: freeing irq %d\n", ncr_name(np), np->irq);
#endif
+#endif
#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,70)
free_irq(np->irq, np);
#else
@@ -5823,8 +5847,14 @@ void ncr_complete (ncb_p np, ccb_p cp)
** Announce changes to the generic driver.
*/
if (tp->numtags) {
+ /*
+ * Decrease tp->maxtags (ecd, 980110)
+ */
+ tp->maxtags = tp->numtags - 1;
+
PRINT_ADDR(cmd);
- printf("QUEUE FULL! suspending tagged command queueing\n");
+ printf("QUEUE FULL! suspending tagged command queueing (setting maxtags to %d)\n", tp->maxtags);
+
tp->numtags = 0;
tp->num_good = 0;
if (lp) {
@@ -7328,10 +7358,10 @@ static void ncr_int_ma (ncb_p np)
if (dsp == vtophys (&cp->patch[2])) {
vdsp = &cp->patch[0];
- nxtdsp = vdsp[3];
+ nxtdsp = scr_to_cpu(vdsp[3]);
} else if (dsp == vtophys (&cp->patch[6])) {
vdsp = &cp->patch[4];
- nxtdsp = vdsp[3];
+ nxtdsp = scr_to_cpu(vdsp[3]);
} else if (dsp > np->p_script && dsp <= np->p_script + sizeof(struct script)) {
vdsp = (u_int32 *) ((char*)np->script - np->p_script + dsp -8);
nxtdsp = dsp;
@@ -8244,13 +8274,13 @@ static void ncr_alloc_ccb (ncb_p np, u_long target, u_long lun)
cpu_to_scr(SCR_COPY(1)):cpu_to_scr(SCR_COPY_F(1));
tp->getscr[1] = cpu_to_scr(vtophys (&tp->sval));
tp->getscr[2] =
- cpu_to_scr(np->paddr + offsetof (struct ncr_reg, nc_sxfer));
+ cpu_to_scr(pcivtophys(np->paddr) + offsetof (struct ncr_reg, nc_sxfer));
tp->getscr[3] = (np->features & FE_PFEN) ?
cpu_to_scr(SCR_COPY(1)):cpu_to_scr(SCR_COPY_F(1));
tp->getscr[4] = cpu_to_scr(vtophys (&tp->wval));
tp->getscr[5] =
- cpu_to_scr(np->paddr + offsetof (struct ncr_reg, nc_scntl3));
+ cpu_to_scr(pcivtophys(np->paddr) + offsetof (struct ncr_reg, nc_scntl3));
assert (( (offsetof(struct ncr_reg, nc_sxfer) ^
offsetof(struct tcb , sval )) &3) == 0);
@@ -8647,8 +8677,8 @@ flush_cache_all();
#define PROFILE cp->phys.header.stamp
static void ncb_profile (ncb_p np, ccb_p cp)
{
- int co, st, en, di, se, post,work,disc;
- u_long diff;
+ long co, st, en, di, se, post, work, disc;
+ u_int diff;
PROFILE.end = jiffies;
@@ -8671,7 +8701,7 @@ static void ncb_profile (ncb_p np, ccb_p cp)
work = (st - co) - disc;
- diff = (np->disc_phys - np->disc_ref) & 0xff;
+ diff = (scr_to_cpu(np->disc_phys) - np->disc_ref) & 0xff;
np->disc_ref += diff;
np->profile.num_trans += 1;
@@ -9097,7 +9127,7 @@ ncr_attach_using_nvram(Scsi_Host_Template *tpnt, int nvram_index, int count, ncr
int i, j;
int attach_count = 0;
ncr_nvram *nvram;
- ncr_device *devp;
+ ncr_device *devp = 0; /* to shut up gcc */
if (!nvram_index)
return 0;
@@ -9223,7 +9253,7 @@ if (ncr53c8xx)
** the order they are detected.
*/
- if (!pcibios_present())
+ if (!pci_present())
return 0;
chips = sizeof(ncr_chip_ids) / sizeof(ncr_chip_ids[0]);
@@ -9307,11 +9337,17 @@ static int ncr53c8xx_pci_init(Scsi_Host_Template *tpnt,
{
ushort vendor_id, device_id, command;
uchar cache_line_size, latency_timer;
- uchar irq, revision;
-#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0)
+ uchar revision;
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,85)
+ struct pci_dev *pdev;
+ ulong base, base_2, io_port;
+ uint irq;
+#elif LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0)
+ uchar irq;
uint base, base_2, io_port;
#else
- ulong base, base_2;
+ uchar irq;
+ ulong base, base_2, io_port;
#endif
int i;
@@ -9335,6 +9371,13 @@ static int ncr53c8xx_pci_init(Scsi_Host_Template *tpnt,
PCI_DEVICE_ID, &device_id);
(void) pcibios_read_config_word(bus, device_fn,
PCI_COMMAND, &command);
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,85)
+ pdev = pci_find_slot(bus, device_fn);
+ io_port = pdev->base_address[0];
+ base = pdev->base_address[1];
+ base_2 = pdev->base_address[2];
+ irq = pdev->irq;
+#else
(void) pcibios_read_config_dword(bus, device_fn,
PCI_BASE_ADDRESS_0, &io_port);
(void) pcibios_read_config_dword(bus, device_fn,
@@ -9342,9 +9385,10 @@ static int ncr53c8xx_pci_init(Scsi_Host_Template *tpnt,
(void) pcibios_read_config_dword(bus, device_fn,
PCI_BASE_ADDRESS_2, &base_2);
(void) pcibios_read_config_byte(bus, device_fn,
- PCI_CLASS_REVISION,&revision);
- (void) pcibios_read_config_byte(bus, device_fn,
PCI_INTERRUPT_LINE, &irq);
+#endif
+ (void) pcibios_read_config_byte(bus, device_fn,
+ PCI_CLASS_REVISION,&revision);
(void) pcibios_read_config_byte(bus, device_fn,
PCI_CACHE_LINE_SIZE, &cache_line_size);
(void) pcibios_read_config_byte(bus, device_fn,
@@ -9380,24 +9424,105 @@ printk("ncr53c8xx_pci_init() #1: bus == %d, device_fn == %d\n", bus, device_fn);
}
#ifdef __powerpc__
+ if (!(command & PCI_COMMAND_MASTER)) {
+ printk("ncr53c8xx: attempting to force PCI_COMMAND_MASTER...");
+ command |= PCI_COMMAND_MASTER;
+ pcibios_write_config_word(bus, device_fn, PCI_COMMAND, command);
+ pcibios_read_config_word(bus, device_fn, PCI_COMMAND, &command);
+ if (!(command & PCI_COMMAND_MASTER)) {
+ printk("failed!\n");
+ } else {
+ printk("succeeded.\n");
+ }
+ }
+
+ if (!(command & PCI_COMMAND_IO)) {
+ printk("ncr53c8xx: attempting to force PCI_COMMAND_IO...");
+ command |= PCI_COMMAND_IO;
+ pcibios_write_config_word(bus, device_fn, PCI_COMMAND, command);
+ pcibios_read_config_word(bus, device_fn, PCI_COMMAND, &command);
+ if (!(command & PCI_COMMAND_IO)) {
+ printk("failed!\n");
+ } else {
+ printk("succeeded.\n");
+ }
+ }
+
+ if (!(command & PCI_COMMAND_MEMORY)) {
+ printk("ncr53c8xx: attempting to force PCI_COMMAND_MEMORY...");
+ command |= PCI_COMMAND_MEMORY;
+ pcibios_write_config_word(bus, device_fn, PCI_COMMAND, command);
+ pcibios_read_config_word(bus, device_fn, PCI_COMMAND, &command);
+ if (!(command & PCI_COMMAND_MEMORY)) {
+ printk("failed!\n");
+ } else {
+ printk("succeeded.\n");
+ }
+ }
+
+ if ( is_prep ) {
+ if (io_port >= 0x10000000) {
+ printk("ncr53c8xx: reallocating io_port (Wacky IBM)");
+ io_port = (io_port & 0x00FFFFFF) | 0x01000000;
+ pcibios_write_config_dword(bus, device_fn, PCI_BASE_ADDRESS_0, io_port);
+ }
+ if (base >= 0x10000000) {
+ printk("ncr53c8xx: reallocating base (Wacky IBM)");
+ base = (base & 0x00FFFFFF) | 0x01000000;
+ pcibios_write_config_dword(bus, device_fn, PCI_BASE_ADDRESS_1, base);
+ }
+ if (base_2 >= 0x10000000) {
+ printk("ncr53c8xx: reallocating base2 (Wacky IBM)");
+ base_2 = (base_2 & 0x00FFFFFF) | 0x01000000;
+ pcibios_write_config_dword(bus, device_fn, PCI_BASE_ADDRESS_2, base_2);
+ }
+ }
+#endif
+#ifdef __sparc__
/*
- * Severall fix-up for power/pc.
- * Should not be performed by the driver.
+ * Severall fix-ups for sparc.
+ *
+ * Should not be performed by the driver, but how can OBP know
+ * each and every PCI card, if they don't use Fcode?
*/
- if ((command &
- (PCI_COMMAND_MASTER|PCI_COMMAND_IO|PCI_COMMAND_MEMORY)) !=
- (PCI_COMMAND_MASTER|PCI_COMMAND_IO|PCI_COMMAND_MEMORY)) {
- printk("ncr53c8xx : setting PCI master/io/command bit\n");
- command |= PCI_COMMAND_MASTER|PCI_COMMAND_IO|PCI_COMMAND_MEMORY;
+
+ base = __pa(base);
+ base_2 = __pa(base_2);
+
+ if (!(command & PCI_COMMAND_MASTER)) {
+ if (initverbose >= 2)
+ printk("ncr53c8xx: setting PCI_COMMAND_MASTER bit (fixup)\n");
+ command |= PCI_COMMAND_MASTER;
pcibios_write_config_word(bus, device_fn, PCI_COMMAND, command);
+ pcibios_read_config_word(bus, device_fn, PCI_COMMAND, &command);
}
- if (io_port >= 0x10000000) {
- io_port = (io_port & 0x00FFFFFF) | 0x01000000;
- pcibios_write_config_dword(bus, device_fn, PCI_BASE_ADDRESS_0, io_port);
+
+ if ((chip->features & FE_WRIE) && !(command & PCI_COMMAND_INVALIDATE)) {
+ if (initverbose >= 2)
+ printk("ncr53c8xx: setting PCI_COMMAND_INVALIDATE bit (fixup)\n");
+ command |= PCI_COMMAND_INVALIDATE;
+ pcibios_write_config_word(bus, device_fn, PCI_COMMAND, command);
+ pcibios_read_config_word(bus, device_fn, PCI_COMMAND, &command);
}
- if (base >= 0x10000000) {
- base = (base & 0x00FFFFFF) | 0x01000000;
- pcibios_write_config_dword(bus, device_fn, PCI_BASE_ADDRESS_1, base);
+
+ if ((chip->features & FE_CLSE) && !cache_line_size) {
+ cache_line_size = 16;
+ if (initverbose >= 2)
+ printk("ncr53c8xx: setting PCI_CACHE_LINE_SIZE to %d (fixup)\n", cache_line_size);
+ pcibios_write_config_byte(bus, device_fn,
+ PCI_CACHE_LINE_SIZE, cache_line_size);
+ pcibios_read_config_byte(bus, device_fn,
+ PCI_CACHE_LINE_SIZE, &cache_line_size);
+ }
+
+ if (!latency_timer) {
+ latency_timer = 248;
+ if (initverbose >= 2)
+ printk("ncr53c8xx: setting PCI_LATENCY_TIMER to %d bus clocks (fixup)\n", latency_timer);
+ pcibios_write_config_byte(bus, device_fn,
+ PCI_LATENCY_TIMER, latency_timer);
+ pcibios_read_config_byte(bus, device_fn,
+ PCI_LATENCY_TIMER, &latency_timer);
}
#endif
@@ -9436,8 +9561,13 @@ printk("ncr53c8xx_pci_init() #1: bus == %d, device_fn == %d\n", bus, device_fn);
base_2 &= PCI_BASE_ADDRESS_MEM_MASK;
if (io_port && check_region (io_port, 128)) {
+#ifdef __sparc__
+ printk("ncr53c8xx: IO region 0x%lx to 0x%lx is in use\n",
+ io_port, (io_port + 127));
+#else
printk("ncr53c8xx: IO region 0x%x to 0x%x is in use\n",
(int) io_port, (int) (io_port + 127));
+#endif
return -1;
}
@@ -9690,6 +9820,15 @@ static void ncr53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs)
if (DEBUG_FLAGS & DEBUG_TINY) printf ("]\n");
}
+static void do_ncr53c8xx_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&io_request_lock, flags);
+ ncr53c8xx_intr(irq, dev_id, regs);
+ spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
#else
static void ncr53c8xx_intr(int irq, struct pt_regs * regs)
{
diff --git a/drivers/scsi/ncr53c8xx.h b/drivers/scsi/ncr53c8xx.h
index 9b54fc3b2..6a3a165a3 100644
--- a/drivers/scsi/ncr53c8xx.h
+++ b/drivers/scsi/ncr53c8xx.h
@@ -161,6 +161,8 @@
#define SCSI_NCR_IOMAPPED
#elif defined(__alpha__) || defined(__powerpc__)
#define SCSI_NCR_IOMAPPED
+#elif defined(__sparc__)
+#undef SCSI_NCR_IOMAPPED
#endif
/*
@@ -347,13 +349,18 @@ int ncr53c8xx_release(struct Scsi_Host *);
#error "BIG ENDIAN byte ordering needs kernel version >= 2.1.0"
#endif
-#ifdef __powerpc__
+#if defined(__powerpc__)
#define inw_l2b inw
#define inl_l2b inl
#define outw_b2l outw
#define outl_b2l outl
+#elif defined(__sparc__)
+#define readw_l2b readw
+#define readl_l2b readl
+#define writew_b2l writew
+#define writel_b2l writel
#else
-#error "Support for BIG ENDIAN is only available for the PowerPC"
+#error "Support for BIG ENDIAN is only available for PowerPC and SPARC"
#endif
#else /* Assumed x86 or alpha */
diff --git a/drivers/scsi/pas16.c b/drivers/scsi/pas16.c
index c126030d9..0414f19ff 100644
--- a/drivers/scsi/pas16.c
+++ b/drivers/scsi/pas16.c
@@ -426,7 +426,7 @@ __initfunc(int pas16_detect(Scsi_Host_Template * tpnt)) {
instance->irq = NCR5380_probe_irq(instance, PAS16_IRQS);
if (instance->irq != IRQ_NONE)
- if (request_irq(instance->irq, pas16_intr, SA_INTERRUPT, "pas16", NULL)) {
+ if (request_irq(instance->irq, do_pas16_intr, SA_INTERRUPT, "pas16", NULL)) {
printk("scsi%d : IRQ%d not free, interrupts disabled\n",
instance->host_no, instance->irq);
instance->irq = IRQ_NONE;
diff --git a/drivers/scsi/pas16.h b/drivers/scsi/pas16.h
index 308f26473..fd8b83df6 100644
--- a/drivers/scsi/pas16.h
+++ b/drivers/scsi/pas16.h
@@ -186,6 +186,7 @@ int pas16_proc_info (char *buffer ,char **start, off_t offset,
#define NCR5380_intr pas16_intr
+#define do_NCR5380_intr do_pas16_intr
#define NCR5380_queue_command pas16_queue_command
#define NCR5380_abort pas16_abort
#define NCR5380_reset pas16_reset
diff --git a/drivers/scsi/pci2000.c b/drivers/scsi/pci2000.c
index 89ef9beb0..86798b27c 100644
--- a/drivers/scsi/pci2000.c
+++ b/drivers/scsi/pci2000.c
@@ -28,7 +28,6 @@
#include <linux/head.h>
#include <linux/types.h>
#include <linux/string.h>
-#include <linux/bios32.h>
#include <linux/pci.h>
#include <linux/ioport.h>
#include <linux/delay.h>
@@ -36,6 +35,7 @@
#include <linux/proc_fs.h>
#include <asm/dma.h>
#include <asm/system.h>
+#include <asm/spinlock.h>
#include <asm/io.h>
#include <linux/blk.h>
#include "scsi.h"
@@ -467,6 +467,14 @@ finished:;
OpDone (SCpnt, rc << 16);
return 0;
}
+static void do_Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave(&io_request_lock, flags);
+ Irq_Handler(irq, dev_id, regs);
+ spin_unlock_irqrestore(&io_request_lock, flags);
+ }
/****************************************************************
* Name: internal_done :LOCAL
*
@@ -519,21 +527,15 @@ int Pci2000_Detect (Scsi_Host_Template *tpnt)
PADAPTER2000 padapter;
int z;
int setirq;
+ struct pci_dev *pdev = NULL;
- if ( pcibios_present () )
- {
- for ( pci_index = 0; pci_index <= MAXADAPTER; ++pci_index )
+ if ( pci_present () )
+ while ((pdev = pci_find_device(VENDOR_PSI, DEVICE_ROY_1, pdev)))
{
- UCHAR pci_bus, pci_device_fn;
-
- if ( pcibios_find_device (VENDOR_PSI, DEVICE_ROY_1, pci_index, &pci_bus, &pci_device_fn) != 0 )
- break;
-
pshost = scsi_register (tpnt, sizeof(ADAPTER2000));
padapter = HOSTDATA(pshost);
- pcibios_read_config_word (pci_bus, pci_device_fn, PCI_BASE_ADDRESS_1, &padapter->basePort);
- padapter->basePort &= 0xFFFE;
+ padapter->basePort = pdev->base_address[1] & PCI_BASE_ADDRESS_IO_MASK;
DEB (printk ("\nBase Regs = %#04X", padapter->basePort)); // get the base I/O port address
padapter->mb0 = padapter->basePort + RTR_MAILBOX; // get the 32 bit mail boxes
padapter->mb1 = padapter->basePort + RTR_MAILBOX + 4;
@@ -550,7 +552,7 @@ int Pci2000_Detect (Scsi_Host_Template *tpnt)
if ( WaitReady (padapter) )
goto unregister;
- pcibios_read_config_byte (pci_bus, pci_device_fn, PCI_INTERRUPT_LINE, &pshost->irq);
+ pshost->irq = pdev->irq;
setirq = 1;
for ( z = 0; z < pci_index; z++ ) // scan for shared interrupts
{
@@ -559,7 +561,7 @@ int Pci2000_Detect (Scsi_Host_Template *tpnt)
}
if ( setirq ) // if not shared, posses
{
- if ( request_irq (pshost->irq, Irq_Handler, 0, "pci2000", NULL) )
+ if ( request_irq (pshost->irq, do_Irq_Handler, 0, "pci2000", NULL) )
{
printk ("Unable to allocate IRQ for PSI-2000 controller.\n");
goto unregister;
@@ -573,13 +575,12 @@ int Pci2000_Detect (Scsi_Host_Template *tpnt)
printk("\nPSI-2000 EIDE CONTROLLER: at I/O = %X IRQ = %d\n", padapter->basePort, pshost->irq);
printk("(C) 1997 Perceptive Solutions, Inc. All rights reserved\n\n");
+ NumAdapters++;
continue;
unregister:;
scsi_unregister (pshost);
}
- }
- NumAdapters = pci_index;
- return pci_index;
+ return NumAdapters;
}
/****************************************************************
* Name: Pci2220i_Abort
diff --git a/drivers/scsi/pci2220i.c b/drivers/scsi/pci2220i.c
index 124cc7b44..3a109fc80 100644
--- a/drivers/scsi/pci2220i.c
+++ b/drivers/scsi/pci2220i.c
@@ -30,7 +30,6 @@
#include <linux/head.h>
#include <linux/types.h>
#include <linux/string.h>
-#include <linux/bios32.h>
#include <linux/pci.h>
#include <linux/ioport.h>
#include <linux/delay.h>
@@ -38,6 +37,7 @@
#include <linux/proc_fs.h>
#include <asm/dma.h>
#include <asm/system.h>
+#include <asm/spinlock.h>
#include <asm/io.h>
#include <linux/blk.h>
#include "scsi.h"
@@ -432,6 +432,14 @@ irqerror:;
SCpnt->result = DecodeError (shost, status);
SCpnt->scsi_done (SCpnt);
}
+static void do_Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave(&io_request_lock, flags);
+ Irq_Handler(irq, dev_id, regs);
+ spin_unlock_irqrestore(&io_request_lock, flags);
+ }
/****************************************************************
* Name: Pci2220i_QueueCommand
*
@@ -632,7 +640,7 @@ VOID ReadFlash (PADAPTER2220I hostdata, VOID *pdata, ULONG base, ULONG length)
****************************************************************/
int Pci2220i_Detect (Scsi_Host_Template *tpnt)
{
- int pci_index = 0;
+ struct pci_dev *pdev = NULL;
struct Scsi_Host *pshost;
PADAPTER2220I hostdata;
ULONG modearray[] = {DALE_DATA_MODE2, DALE_DATA_MODE3, DALE_DATA_MODE4, DALE_DATA_MODE4P};
@@ -640,20 +648,13 @@ int Pci2220i_Detect (Scsi_Host_Template *tpnt)
int z;
int setirq;
- if ( pcibios_present () )
- {
- for ( pci_index = 0; pci_index <= MAXADAPTER; ++pci_index )
+ if ( pci_present () )
+ while ((pdev = pci_find_device(VENDOR_PSI, DEVICE_DALE_1, pdev)))
{
- UCHAR pci_bus, pci_device_fn;
-
- if ( pcibios_find_device (VENDOR_PSI, DEVICE_DALE_1, pci_index, &pci_bus, &pci_device_fn) != 0 )
- break;
-
pshost = scsi_register (tpnt, sizeof(ADAPTER2220I));
hostdata = HOSTDATA(pshost);
- pcibios_read_config_word (pci_bus, pci_device_fn, PCI_BASE_ADDRESS_1, &hostdata->basePort);
- hostdata->basePort &= 0xFFFE;
+ hostdata->basePort = pdev->base_address[1] & PCI_BASE_ADDRESS_IO_MASK;
DEB (printk ("\nBase Regs = %#04X", hostdata->basePort));
hostdata->regRemap = hostdata->basePort + RTR_LOCAL_REMAP; // 32 bit local space remap
DEB (printk (" %#04X", hostdata->regRemap));
@@ -666,8 +667,7 @@ int Pci2220i_Detect (Scsi_Host_Template *tpnt)
hostdata->regScratchPad = hostdata->basePort + RTR_MAILBOX; // 16 byte scratchpad I/O base address
DEB (printk (" %#04X", hostdata->regScratchPad));
- pcibios_read_config_word (pci_bus, pci_device_fn, PCI_BASE_ADDRESS_2, &hostdata->regBase);
- hostdata->regBase &= 0xFFFE;
+ hostdata->regBase = pdev->base_address[2] & PCI_BASE_ADDRESS_IO_MASK;
for ( z = 0; z < 9; z++ ) // build regester address array
hostdata->ports[z] = hostdata->regBase + 0x80 + (z * 4);
hostdata->ports[PORT_FAIL] = hostdata->regBase + REG_FAIL;
@@ -691,22 +691,22 @@ int Pci2220i_Detect (Scsi_Host_Template *tpnt)
if ( !inb_p (hostdata->regScratchPad + DALE_NUM_DRIVES) ) // if no devices on this board
goto unregister;
- pcibios_read_config_byte (pci_bus, pci_device_fn, PCI_INTERRUPT_LINE, &pshost->irq);
+ pshost->irq = pdev->irq;
setirq = 1;
- for ( z = 0; z < pci_index; z++ ) // scan for shared interrupts
+ for ( z = 0; z < NumAdapters; z++ ) // scan for shared interrupts
{
- if ( PsiHost[z]->irq == pshost->irq ) // if shared then, don't posses
+ if ( PsiHost[z]->irq == pshost->irq ) // if shared then, don't posses
setirq = 0;
}
if ( setirq ) // if not shared, posses
{
- if ( request_irq (pshost->irq, Irq_Handler, 0, "pci2220i", NULL) )
+ if ( request_irq (pshost->irq, do_Irq_Handler, 0, "pci2220i", NULL) )
{
printk ("Unable to allocate IRQ for PSI-2220I controller.\n");
goto unregister;
}
}
- PsiHost[pci_index] = pshost; // save SCSI_HOST pointer
+ PsiHost[NumAdapters] = pshost; // save SCSI_HOST pointer
pshost->unique_id = hostdata->regBase;
pshost->max_id = 4;
@@ -743,7 +743,6 @@ unregister:
scsi_unregister (pshost);
NumAdapters++;
}
- }
return NumAdapters;
}
/****************************************************************
diff --git a/drivers/scsi/pluto.c b/drivers/scsi/pluto.c
index 3b4598a3f..bfbddd0c9 100644
--- a/drivers/scsi/pluto.c
+++ b/drivers/scsi/pluto.c
@@ -1,6 +1,7 @@
/* pluto.c: SparcSTORAGE Array SCSI host adapter driver.
*
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ *
*/
#include <linux/kernel.h>
@@ -12,6 +13,10 @@
#include <linux/proc_fs.h>
#include <linux/stat.h>
#include <linux/init.h>
+#include <linux/config.h>
+#ifdef CONFIG_KERNELD
+#include <linux/kerneld.h>
+#endif
#include <asm/irq.h>
@@ -45,9 +50,9 @@ static struct ctrl_inquiry {
Scsi_Cmnd cmd;
char inquiry[256];
fc_channel *fc;
-} *fcs __initdata;
-static int fcscount __initdata;
-static atomic_t fcss __initdata;
+} *fcs __initdata = { 0 };
+static int fcscount __initdata = 0;
+static atomic_t fcss __initdata = ATOMIC_INIT(0);
static struct timer_list fc_timer __initdata = { 0 };
struct semaphore fc_sem __initdata = MUTEX_LOCKED;
@@ -98,8 +103,16 @@ __initfunc(int pluto_detect(Scsi_Host_Template *tpnt))
for_each_online_fc_channel(fc)
fcscount++;
PLND(("%d channels online\n", fcscount))
- if (!fcscount)
- return 0;
+ if (!fcscount) {
+#if defined(MODULE) && defined(CONFIG_FC4_SOC_MODULE) && defined(CONFIG_KERNELD)
+ request_module("soc");
+
+ for_each_online_fc_channel(fc)
+ fcscount++;
+ if (!fcscount)
+#endif
+ return 0;
+ }
fcs = (struct ctrl_inquiry *) scsi_init_malloc (sizeof (struct ctrl_inquiry) * fcscount, GFP_DMA);
if (!fcs) {
printk ("PLUTO: Not enough memory to probe\n");
@@ -213,6 +226,8 @@ __initfunc(int pluto_detect(Scsi_Host_Template *tpnt))
nplutos++;
+ if (fc->module) __MOD_INC_USE_COUNT(fc->module);
+
pluto = (struct pluto *)host->hostdata;
host->max_id = inq->targets;
@@ -256,9 +271,13 @@ int pluto_release(struct Scsi_Host *host)
{
struct pluto *pluto = (struct pluto *)host->hostdata;
fc_channel *fc = pluto->fc;
+
+ if (fc->module) __MOD_DEC_USE_COUNT(fc->module);
fc->fcp_register(fc, TYPE_SCSI_FCP, 1);
+ PLND((" releasing pluto.\n"));
kfree (fc->ages);
+ PLND(("released pluto!\n"));
return 0;
}
@@ -288,7 +307,7 @@ const char *pluto_info(struct Scsi_Host *host)
static int pluto_encode_addr(Scsi_Cmnd *SCpnt, u16 *addr)
{
PLND(("encode addr %d %d %d\n", SCpnt->channel, SCpnt->target, SCpnt->cmnd[1] & 0xe0))
- /* We don't support LUNs */
+ /* We don't support LUNs - neither does SSA :) */
if (SCpnt->cmnd[1] & 0xe0) return -EINVAL;
if (!SCpnt->channel) {
if (SCpnt->target) return -EINVAL;
diff --git a/drivers/scsi/pluto.h b/drivers/scsi/pluto.h
index 6dbda6a57..e1d267054 100644
--- a/drivers/scsi/pluto.h
+++ b/drivers/scsi/pluto.h
@@ -43,17 +43,23 @@ int pluto_release(struct Scsi_Host *);
const char * pluto_info(struct Scsi_Host *);
#define PLUTO { \
+ name: "Sparc Storage Array 100/200", \
detect: pluto_detect, \
release: pluto_release, \
info: pluto_info, \
queuecommand: fcp_scsi_queuecommand, \
- abort: fcp_scsi_abort, \
- reset: fcp_scsi_reset, \
can_queue: PLUTO_CAN_QUEUE, \
this_id: -1, \
sg_tablesize: 1, \
cmd_per_lun: 1, \
- use_clustering: ENABLE_CLUSTERING \
+ use_clustering: ENABLE_CLUSTERING, \
+ use_new_eh_code: FCP_SCSI_USE_NEW_EH_CODE, \
+ abort: fcp_old_abort, \
+ eh_abort_handler: fcp_scsi_abort, \
+ eh_device_reset_handler:fcp_scsi_dev_reset, \
+ eh_bus_reset_handler: fcp_scsi_bus_reset, \
+ eh_host_reset_handler: fcp_scsi_host_reset, \
}
#endif /* !(_PLUTO_H) */
+
diff --git a/drivers/scsi/psi240i.c b/drivers/scsi/psi240i.c
index 8e12f4b23..a2cdbfd54 100644
--- a/drivers/scsi/psi240i.c
+++ b/drivers/scsi/psi240i.c
@@ -36,6 +36,7 @@
#include <linux/proc_fs.h>
#include <asm/dma.h>
#include <asm/system.h>
+#include <asm/spinlock.h>
#include <asm/io.h>
#include <linux/blk.h>
#include "scsi.h"
@@ -370,6 +371,14 @@ irqerror:;
SCpnt->result = DecodeError (shost, status);
SCpnt->scsi_done (SCpnt);
}
+static void do_Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave(&io_request_lock, flags);
+ Irq_Handler(irq, dev_id, regs);
+ spin_unlock_irqrestore(&io_request_lock, flags);
+ }
/****************************************************************
* Name: Psi240i_QueueCommand
*
@@ -595,7 +604,7 @@ int Psi240i_Detect (Scsi_Host_Template *tpnt)
save_flags (flags);
cli ();
- if ( request_irq (chipConfig.irq, Irq_Handler, 0, "psi240i", NULL) )
+ if ( request_irq (chipConfig.irq, do_Irq_Handler, 0, "psi240i", NULL) )
{
printk ("Unable to allocate IRQ for PSI-240I controller.\n");
restore_flags (flags);
diff --git a/drivers/scsi/qlogicfas.c b/drivers/scsi/qlogicfas.c
index e01cd5e2a..4279ee6f3 100644
--- a/drivers/scsi/qlogicfas.c
+++ b/drivers/scsi/qlogicfas.c
@@ -125,6 +125,7 @@
#include <linux/unistd.h>
#include <asm/io.h>
#include <asm/irq.h>
+#include <asm/spinlock.h>
#include "sd.h"
#include "hosts.h"
#include "qlogicfas.h"
@@ -446,7 +447,7 @@ rtrc(0)
#if QL_USE_IRQ
/*----------------------------------------------------------------*/
/* interrupt handler */
-static void ql_ihandl(int irq, void *dev_id, struct pt_regs * regs)
+static void ql_ihandl(int irq, void *dev_id, struct pt_regs * regs)
{
Scsi_Cmnd *icmd;
REG0;
@@ -464,6 +465,15 @@ Scsi_Cmnd *icmd;
/* if result is CHECK CONDITION done calls qcommand to request sense */
(icmd->scsi_done) (icmd);
}
+
+static void do_ql_ihandl(int irq, void *dev_id, struct pt_regs * regs)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&io_request_lock, flags);
+ ql_ihandl(irq, dev_id, regs);
+ spin_unlock_irqrestore(&io_request_lock, flags);
+}
#endif
/*----------------------------------------------------------------*/
@@ -609,7 +619,7 @@ host->proc_dir = &proc_scsi_qlogicfas;
else
printk( "Ql: Using preset IRQ %d\n", qlirq );
- if (qlirq >= 0 && !request_irq(qlirq, ql_ihandl, 0, "qlogicfas", NULL))
+ if (qlirq >= 0 && !request_irq(qlirq, do_ql_ihandl, 0, "qlogicfas", NULL))
host->can_queue = 1;
#endif
request_region( qbase , 0x10 ,"qlogicfas");
diff --git a/drivers/scsi/qlogicisp.c b/drivers/scsi/qlogicisp.c
index 861e12632..7044d6ad1 100644
--- a/drivers/scsi/qlogicisp.c
+++ b/drivers/scsi/qlogicisp.c
@@ -21,12 +21,12 @@
#include <linux/ioport.h>
#include <linux/sched.h>
#include <linux/types.h>
-#include <linux/bios32.h>
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/unistd.h>
#include <asm/io.h>
#include <asm/irq.h>
+#include <asm/spinlock.h>
#include "sd.h"
#include "hosts.h"
@@ -486,11 +486,10 @@ struct dev_param {
#define QUEUE_ENTRY_LEN 64
struct isp1020_hostdata {
- u_char bus;
u_char revision;
- u_char device_fn;
struct host_param host_param;
struct dev_param dev_param[MAX_TARGETS];
+ struct pci_dev *pci_dev;
/* result and request queues (shared with isp1020): */
u_int req_in_ptr; /* index of next request slot */
@@ -509,8 +508,6 @@ struct isp1020_hostdata {
QLOGICISP_REQ_QUEUE_LEN)
#define RES_QUEUE_DEPTH(in, out) QUEUE_DEPTH(in, out, RES_QUEUE_LEN)
-static struct Scsi_Host *irq2host[NR_IRQS];
-
static void isp1020_enable_irqs(struct Scsi_Host *);
static void isp1020_disable_irqs(struct Scsi_Host *);
static int isp1020_init(struct Scsi_Host *);
@@ -520,6 +517,7 @@ static int isp1020_load_parameters(struct Scsi_Host *);
static int isp1020_mbox_command(struct Scsi_Host *, u_short []);
static int isp1020_return_status(struct Status_Entry *);
static void isp1020_intr_handler(int, void *, struct pt_regs *);
+static void do_isp1020_intr_handler(int, void *, struct pt_regs *);
#if USE_NVRAM_DEFAULTS
static int isp1020_get_defaults(struct Scsi_Host *);
@@ -555,33 +553,26 @@ static inline void isp1020_disable_irqs(struct Scsi_Host *host)
int isp1020_detect(Scsi_Host_Template *tmpt)
{
int hosts = 0;
- u_short index;
- u_char bus, device_fn;
struct Scsi_Host *host;
struct isp1020_hostdata *hostdata;
+ struct pci_dev *pdev = NULL;
ENTER("isp1020_detect");
tmpt->proc_dir = &proc_scsi_isp1020;
- if (pcibios_present() == 0) {
- printk("qlogicisp : PCI bios not present\n");
+ if (pci_present() == 0) {
+ printk("qlogicisp : PCI not present\n");
return 0;
}
- memset(irq2host, 0, sizeof(irq2host));
-
- for (index = 0; pcibios_find_device(PCI_VENDOR_ID_QLOGIC,
- PCI_DEVICE_ID_QLOGIC_ISP1020,
- index, &bus, &device_fn) == 0;
- index++)
+ while ((pdev = pci_find_device(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP1020, pdev)))
{
host = scsi_register(tmpt, sizeof(struct isp1020_hostdata));
hostdata = (struct isp1020_hostdata *) host->hostdata;
memset(hostdata, 0, sizeof(struct isp1020_hostdata));
- hostdata->bus = bus;
- hostdata->device_fn = device_fn;
+ hostdata->pci_dev = pdev;
if (isp1020_init(host) || isp1020_reset_hardware(host)
#if USE_NVRAM_DEFAULTS
@@ -596,8 +587,8 @@ int isp1020_detect(Scsi_Host_Template *tmpt)
host->this_id = hostdata->host_param.initiator_scsi_id;
- if (request_irq(host->irq, isp1020_intr_handler, SA_INTERRUPT,
- "qlogicisp", NULL))
+ if (request_irq(host->irq, do_isp1020_intr_handler, SA_INTERRUPT | SA_SHIRQ,
+ "qlogicisp", host))
{
printk("qlogicisp : interrupt %d already in use\n",
host->irq);
@@ -606,16 +597,15 @@ int isp1020_detect(Scsi_Host_Template *tmpt)
}
if (check_region(host->io_port, 0xff)) {
- printk("qlogicisp : i/o region 0x%04x-0x%04x already "
+ printk("qlogicisp : i/o region 0x%lx-0x%lx already "
"in use\n",
host->io_port, host->io_port + 0xff);
- free_irq(host->irq, NULL);
+ free_irq(host->irq, host);
scsi_unregister(host);
continue;
}
request_region(host->io_port, 0xff, "qlogicisp");
- irq2host[host->irq] = host;
outw(0x0, host->io_port + PCI_SEMAPHORE);
outw(HCCR_CLEAR_RISC_INTR, host->io_port + HOST_HCCR);
@@ -639,7 +629,7 @@ int isp1020_release(struct Scsi_Host *host)
hostdata = (struct isp1020_hostdata *) host->hostdata;
outw(0x0, host->io_port + PCI_INTF_CTL);
- free_irq(host->irq, NULL);
+ free_irq(host->irq, host);
release_region(host->io_port, 0xff);
@@ -658,8 +648,8 @@ const char *isp1020_info(struct Scsi_Host *host)
hostdata = (struct isp1020_hostdata *) host->hostdata;
sprintf(buf,
- "QLogic ISP1020 SCSI on PCI bus %d device %d irq %d base 0x%x",
- hostdata->bus, (hostdata->device_fn & 0xf8) >> 3, host->irq,
+ "QLogic ISP1020 SCSI on PCI bus %02x device %02x irq %d base 0x%lx",
+ hostdata->pci_dev->bus->number, hostdata->pci_dev->devfn, host->irq,
host->io_port);
LEAVE("isp1020_info");
@@ -813,22 +803,26 @@ int isp1020_queuecommand(Scsi_Cmnd *Cmnd, void (*done)(Scsi_Cmnd *))
#define ASYNC_EVENT_INTERRUPT 0x01
+void do_isp1020_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&io_request_lock, flags);
+ isp1020_intr_handler(irq, dev_id, regs);
+ spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
void isp1020_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
{
Scsi_Cmnd *Cmnd;
struct Status_Entry *sts;
- struct Scsi_Host *host;
+ struct Scsi_Host *host = dev_id;
struct isp1020_hostdata *hostdata;
u_int in_ptr, out_ptr;
u_short status;
ENTER_INTR("isp1020_intr_handler");
- host = irq2host[irq];
- if (!host) {
- printk("qlogicisp : unexpected interrupt on line %d\n", irq);
- return;
- }
hostdata = (struct isp1020_hostdata *) host->hostdata;
DEBUG_INTR(printk("qlogicisp : interrupt on line %d\n", irq));
@@ -1168,40 +1162,34 @@ static int isp1020_init(struct Scsi_Host *sh)
{
u_int io_base;
struct isp1020_hostdata *hostdata;
- u_char bus, device_fn, revision, irq;
- u_short vendor_id, device_id, command;
+ u_char revision;
+ u_int irq;
+ u_short command;
+ struct pci_dev *pdev;
ENTER("isp1020_init");
hostdata = (struct isp1020_hostdata *) sh->hostdata;
- bus = hostdata->bus;
- device_fn = hostdata->device_fn;
-
- if (pcibios_read_config_word(bus, device_fn, PCI_VENDOR_ID, &vendor_id)
- || pcibios_read_config_word(bus, device_fn,
- PCI_DEVICE_ID, &device_id)
- || pcibios_read_config_word(bus, device_fn,
- PCI_COMMAND, &command)
- || pcibios_read_config_dword(bus, device_fn,
- PCI_BASE_ADDRESS_0, &io_base)
- || pcibios_read_config_byte(bus, device_fn,
- PCI_CLASS_REVISION, &revision)
- || pcibios_read_config_byte(bus, device_fn,
- PCI_INTERRUPT_LINE, &irq))
+ pdev = hostdata->pci_dev;
+
+ if (pci_read_config_word(pdev, PCI_COMMAND, &command)
+ || pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision))
{
printk("qlogicisp : error reading PCI configuration\n");
return 1;
}
+ io_base = pdev->base_address[0];
+ irq = pdev->irq;
- if (vendor_id != PCI_VENDOR_ID_QLOGIC) {
+ if (pdev->vendor != PCI_VENDOR_ID_QLOGIC) {
printk("qlogicisp : 0x%04x is not QLogic vendor ID\n",
- vendor_id);
+ pdev->vendor);
return 1;
}
- if (device_id != PCI_DEVICE_ID_QLOGIC_ISP1020) {
+ if (pdev->device != PCI_DEVICE_ID_QLOGIC_ISP1020) {
printk("qlogicisp : 0x%04x does not match ISP1020 device id\n",
- device_id);
+ pdev->device);
return 1;
}
diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c
index ab6c12f5c..fefbc3b45 100644
--- a/drivers/scsi/qlogicpti.c
+++ b/drivers/scsi/qlogicpti.c
@@ -31,6 +31,7 @@
#include <asm/sbus.h>
#include <asm/dma.h>
#include <asm/system.h>
+#include <asm/spinlock.h>
#include <asm/machines.h>
#include <asm/ptrace.h>
#include <asm/pgtable.h>
@@ -421,36 +422,37 @@ __initfunc(static int qlogicpti_load_firmware(struct qlogicpti *qpti))
/* Load the firmware. */
#if !defined(MODULE) && !defined(__sparc_v9__)
- dvma_addr = (unsigned long) mmu_lockarea((char *)&risc_code01[0],
- (sizeof(u_short) * risc_code_length01));
- param[0] = MBOX_LOAD_RAM;
- param[1] = risc_code_addr01;
- param[2] = (dvma_addr >> 16);
- param[3] = (dvma_addr & 0xffff);
- param[4] = (sizeof(u_short) * risc_code_length01);
- if(qlogicpti_mbox_command(qpti, param, 1) ||
- (param[0] != MBOX_COMMAND_COMPLETE)) {
- printk(KERN_EMERG "qlogicpti%d: Firmware dload failed, I'm bolixed!\n",
- qpti->qpti_id);
- restore_flags(flags);
- return 1;
- }
- mmu_unlockarea((char *)dvma_addr, (sizeof(u_short) * risc_code_length01));
-#else
- /* We need to do it this slow way always on Ultra. */
- for(i = 0; i < risc_code_length01; i++) {
- param[0] = MBOX_WRITE_RAM_WORD;
- param[1] = risc_code_addr01 + i;
- param[2] = risc_code01[i];
+ if (sparc_cpu_model != sun4d) {
+ dvma_addr = (unsigned long) mmu_lockarea((char *)&risc_code01[0],
+ (sizeof(u_short) * risc_code_length01));
+ param[0] = MBOX_LOAD_RAM;
+ param[1] = risc_code_addr01;
+ param[2] = (dvma_addr >> 16);
+ param[3] = (dvma_addr & 0xffff);
+ param[4] = (sizeof(u_short) * risc_code_length01);
if(qlogicpti_mbox_command(qpti, param, 1) ||
- param[0] != MBOX_COMMAND_COMPLETE) {
- printk("qlogicpti%d: Firmware dload failed, I'm bolixed!\n",
+ (param[0] != MBOX_COMMAND_COMPLETE)) {
+ printk(KERN_EMERG "qlogicpti%d: Firmware dload failed, I'm bolixed!\n",
qpti->qpti_id);
restore_flags(flags);
return 1;
}
- }
+ mmu_unlockarea((char *)dvma_addr, (sizeof(u_short) * risc_code_length01));
+ } else
#endif
+ /* We need to do it this slow way always on Ultra, SS[12]000. */
+ for(i = 0; i < risc_code_length01; i++) {
+ param[0] = MBOX_WRITE_RAM_WORD;
+ param[1] = risc_code_addr01 + i;
+ param[2] = risc_code01[i];
+ if(qlogicpti_mbox_command(qpti, param, 1) ||
+ param[0] != MBOX_COMMAND_COMPLETE) {
+ printk("qlogicpti%d: Firmware dload failed, I'm bolixed!\n",
+ qpti->qpti_id);
+ restore_flags(flags);
+ return 1;
+ }
+ }
/* Reset the ISP again. */
qregs->hcctrl = HCCTRL_RESET;
@@ -562,6 +564,7 @@ static inline void qlogicpti_set_hostdev_defaults(struct qlogicpti *qpti)
}
static void qlogicpti_intr_handler(int irq, void *dev_id, struct pt_regs *regs);
+static void do_qlogicpti_intr_handler(int irq, void *dev_id, struct pt_regs *regs);
/* Detect all PTI Qlogic ISP's in the machine. */
__initfunc(int qlogicpti_detect(Scsi_Host_Template *tpnt))
@@ -582,8 +585,13 @@ __initfunc(int qlogicpti_detect(Scsi_Host_Template *tpnt))
tpnt->proc_dir = &proc_scsi_qlogicpti;
qptichain = 0;
- if(!SBus_chain)
+ if(!SBus_chain) {
+#ifdef __sparc_v9__
+ return 0; /* Could be a PCI-only machine. */
+#else
panic("No SBUS in qlogicpti_detect()");
+#endif
+ }
for_each_sbus(sbus) {
for_each_sbusdev(sbdev_iter, sbus) {
qpti_dev = sbdev_iter;
@@ -669,7 +677,7 @@ __initfunc(int qlogicpti_detect(Scsi_Host_Template *tpnt))
goto qpti_irq_acquired; /* BASIC rulez */
}
}
- if(request_irq(qpti->qhost->irq, qlogicpti_intr_handler,
+ if(request_irq(qpti->qhost->irq, do_qlogicpti_intr_handler,
SA_SHIRQ, "PTI Qlogic/ISP SCSI", NULL)) {
printk("Cannot acquire PTI Qlogic/ISP irq line\n");
/* XXX Unmap regs, unregister scsi host, free things. */
@@ -685,7 +693,7 @@ qpti_irq_acquired:
dcookie.imap = dcookie.iclr = 0;
dcookie.pil = -1;
dcookie.bus_cookie = sbus;
- if(request_irq(qpti->qhost->irq, qlogicpti_intr_handler,
+ if(request_irq(qpti->qhost->irq, do_qlogicpti_intr_handler,
(SA_SHIRQ | SA_SBUS | SA_DCOOKIE),
"PTI Qlogic/ISP SCSI", &dcookie)) {
printk("Cannot acquire PTI Qlogic/ISP irq line\n");
@@ -776,8 +784,9 @@ qpti_irq_acquired:
nqptis_in_use++;
}
}
- printk("QPTI: Total of %d PTI Qlogic/ISP hosts found, %d actually in use.\n",
- nqptis, nqptis_in_use);
+ if (nqptis)
+ printk("QPTI: Total of %d PTI Qlogic/ISP hosts found, %d actually in use.\n",
+ nqptis, nqptis_in_use);
qptis_running = nqptis_in_use;
return nqptis;
}
@@ -929,7 +938,9 @@ static inline u_int load_cmd(Scsi_Cmnd *Cmnd, struct Command_Entry *cmd,
static inline void update_can_queue(struct Scsi_Host *host, u_int in_ptr, u_int out_ptr)
{
- int num_free = QLOGICISP_REQ_QUEUE_LEN - REQ_QUEUE_DEPTH(in_ptr, out_ptr);
+ /* Temporary workaround until bug is found and fixed (one bug has been found
+ already, but fixing it makes things even worse) -jj */
+ int num_free = QLOGICISP_REQ_QUEUE_LEN - REQ_QUEUE_DEPTH(in_ptr, out_ptr) - 64;
host->can_queue = host->host_busy + num_free;
host->sg_tablesize = QLOGICISP_MAX_SG(num_free);
}
@@ -1040,6 +1051,15 @@ static int qlogicpti_return_status(struct Status_Entry *sts)
return (sts->scsi_status & STATUS_MASK) | (host_status << 16);
}
+static void do_qlogicpti_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&io_request_lock, flags);
+ qlogicpti_intr_handler(irq, dev_id, regs);
+ spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
#ifndef __sparc_v9__
static void qlogicpti_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
@@ -1245,4 +1265,6 @@ int qlogicpti_reset(Scsi_Cmnd *Cmnd, unsigned int reset_flags)
Scsi_Host_Template driver_template = QLOGICPTI;
#include "scsi_module.c"
+
+EXPORT_NO_SYMBOLS;
#endif /* MODULE */
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index 90bb6e2d4..0dc7f398f 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -141,7 +141,7 @@ static unsigned char ** dma_malloc_pages = NULL;
*/
unsigned int scsi_logging_level = 0;
-static volatile struct Scsi_Host * host_active = NULL;
+volatile struct Scsi_Host * host_active = NULL;
#if CONFIG_PROC_FS
/*
@@ -248,6 +248,7 @@ static struct dev_info device_list[] =
{"SONY","CD-ROM CDU-55S","1.0i", BLIST_NOLUN},
{"SONY","CD-ROM CDU-561","1.7x", BLIST_NOLUN},
{"TANDBERG","TDC 3600","U07", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */
+{"TEAC","CD-R55S","1.0H", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */
{"TEAC","CD-ROM","1.06", BLIST_NOLUN}, /* causes failed REQUEST SENSE on lun 1
* for seagate controller, which causes
* SCSI code to reset bus.*/
@@ -332,7 +333,6 @@ void
scsi_make_blocked_list(void)
{
int block_count = 0, index;
- unsigned long flags;
struct Scsi_Host * sh[128], * shpnt;
/*
@@ -354,7 +354,6 @@ scsi_make_blocked_list(void)
*/
- spin_lock_irqsave(&io_request_lock, flags);
host_active = NULL;
for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next) {
@@ -386,7 +385,6 @@ scsi_make_blocked_list(void)
sh[index]->host_no);
}
- spin_unlock_irqrestore(&io_request_lock, flags);
}
static void scan_scsis_done (Scsi_Cmnd * SCpnt)
@@ -657,9 +655,11 @@ int scan_scsis_single (int channel, int dev, int lun, int *max_dev_lun,
struct semaphore sem = MUTEX_LOCKED;
SCpnt->request.sem = &sem;
SCpnt->request.rq_status = RQ_SCSI_BUSY;
+ spin_lock_irq(&io_request_lock);
scsi_do_cmd (SCpnt, (void *) scsi_cmd,
(void *) scsi_result,
256, scan_scsis_done, SCSI_TIMEOUT + 4 * HZ, 5);
+ spin_unlock_irq(&io_request_lock);
down (&sem);
SCpnt->request.sem = NULL;
}
@@ -698,9 +698,11 @@ int scan_scsis_single (int channel, int dev, int lun, int *max_dev_lun,
struct semaphore sem = MUTEX_LOCKED;
SCpnt->request.sem = &sem;
SCpnt->request.rq_status = RQ_SCSI_BUSY;
+ spin_lock_irq(&io_request_lock);
scsi_do_cmd (SCpnt, (void *) scsi_cmd,
(void *) scsi_result,
256, scan_scsis_done, SCSI_TIMEOUT, 3);
+ spin_unlock_irq(&io_request_lock);
down (&sem);
SCpnt->request.sem = NULL;
}
@@ -840,9 +842,11 @@ int scan_scsis_single (int channel, int dev, int lun, int *max_dev_lun,
struct semaphore sem = MUTEX_LOCKED;
SCpnt->request.rq_status = RQ_SCSI_BUSY;
SCpnt->request.sem = &sem;
+ spin_lock_irq(&io_request_lock);
scsi_do_cmd (SCpnt, (void *) scsi_cmd,
(void *) scsi_result, 0x2a,
scan_scsis_done, SCSI_TIMEOUT, 3);
+ spin_unlock_irq(&io_request_lock);
down (&sem);
SCpnt->request.sem = NULL;
}
@@ -1078,7 +1082,6 @@ Scsi_Cmnd * scsi_allocate_device (struct request ** reqp, Scsi_Device * device,
kdev_t dev;
struct request * req = NULL;
int tablesize;
- unsigned long flags;
struct buffer_head * bh, *bhp;
struct Scsi_Host * host;
Scsi_Cmnd * SCpnt = NULL;
@@ -1137,21 +1140,18 @@ Scsi_Cmnd * scsi_allocate_device (struct request ** reqp, Scsi_Device * device,
SCpnt = found;
}
- __save_flags(flags);
- __cli();
/* See if this request has already been queued by an interrupt routine
*/
if (req && (req->rq_status == RQ_INACTIVE || req->rq_dev != dev)) {
- __restore_flags(flags);
return NULL;
}
if (!SCpnt || SCpnt->request.rq_status != RQ_INACTIVE) /* Might have changed */
{
if (wait && SCwait && SCwait->request.rq_status != RQ_INACTIVE){
+ spin_unlock(&io_request_lock); /* FIXME!!!! */
sleep_on(&device->device_wait);
- __restore_flags(flags);
+ spin_lock_irq(&io_request_lock); /* FIXME!!!! */
} else {
- __restore_flags(flags);
if (!wait) return NULL;
if (!SCwait) {
printk("Attempt to allocate device channel %d,"
@@ -1201,7 +1201,6 @@ Scsi_Cmnd * scsi_allocate_device (struct request ** reqp, Scsi_Device * device,
* to complete */
}
atomic_inc(&SCpnt->host->host_active);
- __restore_flags(flags);
SCSI_LOG_MLQUEUE(5, printk("Activating command for device %d (%d)\n",
SCpnt->target,
atomic_read(&SCpnt->host->host_active)));
@@ -1282,7 +1281,6 @@ inline int internal_cmnd (Scsi_Cmnd * SCpnt)
#ifdef DEBUG_DELAY
unsigned long clock;
#endif
- unsigned long flags;
struct Scsi_Host * host;
int rtn = 0;
unsigned long timeout;
@@ -1298,7 +1296,6 @@ inline int internal_cmnd (Scsi_Cmnd * SCpnt)
host = SCpnt->host;
- spin_lock_irqsave(&io_request_lock, flags);
/* Assign a unique nonzero serial_number. */
if (++serial_number == 0) serial_number = 1;
SCpnt->serial_number = serial_number;
@@ -1308,7 +1305,6 @@ inline int internal_cmnd (Scsi_Cmnd * SCpnt)
* we can avoid the drive not being ready.
*/
timeout = host->last_reset + MIN_RESET_DELAY;
- spin_unlock(&io_request_lock);
if (jiffies < timeout) {
int ticks_remaining = timeout - jiffies;
@@ -1321,11 +1317,11 @@ inline int internal_cmnd (Scsi_Cmnd * SCpnt)
* interrupt handler (assuming there is one irq-level per
* host).
*/
- __sti();
+ spin_unlock_irq(&io_request_lock);
while (--ticks_remaining >= 0) udelay(1000000/HZ);
host->last_reset = jiffies - MIN_RESET_DELAY;
+ spin_lock_irq(&io_request_lock);
}
- __restore_flags(flags); /* this possibly puts us back into __cli() */
if( host->hostt->use_new_eh_code )
{
@@ -1352,18 +1348,6 @@ inline int internal_cmnd (Scsi_Cmnd * SCpnt)
{
SCSI_LOG_MLQUEUE(3,printk("queuecommand : routine at %p\n",
host->hostt->queuecommand));
- /* This locking tries to prevent all sorts of races between
- * queuecommand and the interrupt code. In effect,
- * we are only allowed to be in queuecommand once at
- * any given time, and we can only be in the interrupt
- * handler and the queuecommand function at the same time
- * when queuecommand is called while servicing the
- * interrupt.
- */
-
- if(!in_interrupt() && SCpnt->host->irq)
- disable_irq(SCpnt->host->irq);
-
/*
* Use the old error handling code if we haven't converted the driver
* to use the new one yet. Note - only the new queuecommand variant
@@ -1381,9 +1365,6 @@ inline int internal_cmnd (Scsi_Cmnd * SCpnt)
{
host->hostt->queuecommand (SCpnt, scsi_old_done);
}
-
- if(!in_interrupt() && SCpnt->host->irq)
- enable_irq(SCpnt->host->irq);
}
else
{
@@ -1394,7 +1375,9 @@ inline int internal_cmnd (Scsi_Cmnd * SCpnt)
SCpnt->result = temp;
#ifdef DEBUG_DELAY
clock = jiffies + 4 * HZ;
+ spin_unlock_irq(&io_request_lock);
while (jiffies < clock) barrier();
+ spin_lock_irq(&io_request_lock);
printk("done(host = %d, result = %04x) : routine at %p\n",
host->host_no, temp, host->hostt->command);
#endif
@@ -1422,7 +1405,6 @@ void scsi_do_cmd (Scsi_Cmnd * SCpnt, const void *cmnd ,
void *buffer, unsigned bufflen, void (*done)(Scsi_Cmnd *),
int timeout, int retries)
{
- unsigned long flags;
struct Scsi_Host * host = SCpnt->host;
Scsi_Device * device = SCpnt->device;
@@ -1456,20 +1438,18 @@ SCSI_LOG_MLQUEUE(4,
* ourselves.
*/
- spin_lock_irqsave(&io_request_lock, flags);
SCpnt->pid = scsi_pid++;
while (SCSI_BLOCK((Scsi_Device *) NULL, host)) {
- spin_unlock_irqrestore(&io_request_lock, flags);
+ spin_unlock(&io_request_lock); /* FIXME!!! */
SCSI_SLEEP(&host->host_wait, SCSI_BLOCK((Scsi_Device *) NULL, host));
- spin_lock_irqsave(&io_request_lock, flags);
+ spin_lock_irq(&io_request_lock); /* FIXME!!! */
}
if (host->block) host_active = host;
host->host_busy++;
device->device_busy++;
- spin_unlock_irqrestore(&io_request_lock, flags);
/*
* Our own function scsi_done (which marks the host as not busy, disables
@@ -1818,12 +1798,10 @@ static void scsi_unregister_host(Scsi_Host_Template *);
void *scsi_malloc(unsigned int len)
{
unsigned int nbits, mask;
- unsigned long flags;
int i, j;
if(len % SECTOR_SIZE != 0 || len > PAGE_SIZE)
return NULL;
- spin_lock_irqsave(&io_request_lock, flags);
nbits = len >> 9;
mask = (1 << nbits) - 1;
@@ -1831,7 +1809,6 @@ void *scsi_malloc(unsigned int len)
for(j=0; j<=SECTORS_PER_PAGE - nbits; j++){
if ((dma_malloc_freelist[i] & (mask << j)) == 0){
dma_malloc_freelist[i] |= (mask << j);
- spin_unlock_irqrestore(&io_request_lock, flags);
scsi_dma_free_sectors -= nbits;
#ifdef DEBUG
SCSI_LOG_MLQUEUE(3,printk("SMalloc: %d %p [From:%p]\n",len, dma_malloc_pages[i] + (j << 9)));
@@ -1840,14 +1817,12 @@ void *scsi_malloc(unsigned int len)
return (void *) ((unsigned long) dma_malloc_pages[i] + (j << 9));
}
}
- spin_unlock_irqrestore(&io_request_lock, flags);
return NULL; /* Nope. No more */
}
int scsi_free(void *obj, unsigned int len)
{
unsigned int page, sector, nbits, mask;
- unsigned long flags;
#ifdef DEBUG
unsigned long ret = 0;
@@ -1874,20 +1849,16 @@ int scsi_free(void *obj, unsigned int len)
if ((mask << sector) >= (1 << SECTORS_PER_PAGE))
panic ("scsi_free:Bad memory alignment");
- spin_lock_irqsave(&io_request_lock, flags);
if((dma_malloc_freelist[page] &
(mask << sector)) != (mask<<sector)){
- spin_unlock_irqrestore(&io_request_lock, flags);
#ifdef DEBUG
printk("scsi_free(obj=%p, len=%d) called from %08lx\n",
obj, len, ret);
#endif
panic("scsi_free:Trying to free unused memory");
- spin_lock_irqsave(&io_request_lock, flags);
}
scsi_dma_free_sectors += nbits;
dma_malloc_freelist[page] &= ~(mask << sector);
- spin_unlock_irqrestore(&io_request_lock, flags);
return 0;
}
}
@@ -2430,7 +2401,6 @@ static void resize_dma_pool(void)
struct Scsi_Host * shpnt;
struct Scsi_Host * host = NULL;
Scsi_Device * SDpnt;
- unsigned long flags;
FreeSectorBitmap * new_dma_malloc_freelist = NULL;
unsigned int new_dma_sectors = 0;
unsigned int new_need_isa_buffer = 0;
@@ -2551,7 +2521,6 @@ static void resize_dma_pool(void)
/* When we dick with the actual DMA list, we need to
* protect things
*/
- spin_lock_irqsave(&io_request_lock, flags);
if (dma_malloc_freelist)
{
size = (dma_sectors / SECTORS_PER_PAGE)*sizeof(FreeSectorBitmap);
@@ -2571,7 +2540,6 @@ static void resize_dma_pool(void)
dma_malloc_pages = new_dma_malloc_pages;
dma_sectors = new_dma_sectors;
scsi_need_isa_buffer = new_need_isa_buffer;
- spin_unlock_irqrestore(&io_request_lock, flags);
#ifdef DEBUG_INIT
printk("resize_dma_pool: dma free sectors = %d\n", scsi_dma_free_sectors);
@@ -2741,7 +2709,6 @@ static int scsi_register_host(Scsi_Host_Template * tpnt)
*/
static void scsi_unregister_host(Scsi_Host_Template * tpnt)
{
- unsigned long flags;
int online_status;
int pcount;
Scsi_Cmnd * SCpnt;
@@ -2810,10 +2777,8 @@ static void scsi_unregister_host(Scsi_Host_Template * tpnt)
{
online_status = SDpnt->online;
SDpnt->online = FALSE;
- spin_lock_irqsave(&io_request_lock, flags);
if(SCpnt->request.rq_status != RQ_INACTIVE)
{
- spin_unlock_irqrestore(&io_request_lock, flags);
printk("SCSI device not inactive - state=%d, id=%d\n",
SCpnt->request.rq_status, SCpnt->target);
for(SDpnt1 = shpnt->host_queue; SDpnt1;
@@ -2834,7 +2799,6 @@ static void scsi_unregister_host(Scsi_Host_Template * tpnt)
*/
SCpnt->state = SCSI_STATE_DISCONNECTING;
SCpnt->request.rq_status = RQ_SCSI_DISCONNECTING; /* Mark as busy */
- spin_unlock_irqrestore(&io_request_lock, flags);
}
}
}
diff --git a/drivers/scsi/scsi.h b/drivers/scsi/scsi.h
index 9826fb990..035d90b7a 100644
--- a/drivers/scsi/scsi.h
+++ b/drivers/scsi/scsi.h
@@ -686,7 +686,6 @@ static Scsi_Cmnd * end_scsi_request(Scsi_Cmnd * SCpnt, int uptodate, int sectors
#define INIT_SCSI_REQUEST \
if (!CURRENT) { \
CLEAR_INTR; \
- spin_unlock_irqrestore(&io_request_lock,flags); \
return; \
} \
if (MAJOR(CURRENT->rq_dev) != MAJOR_NR) \
diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c
index eafaf6a00..a052caadf 100644
--- a/drivers/scsi/scsi_ioctl.c
+++ b/drivers/scsi/scsi_ioctl.c
@@ -96,6 +96,7 @@ static void scsi_ioctl_done (Scsi_Cmnd * SCpnt)
static int ioctl_internal_command(Scsi_Device *dev, char * cmd)
{
+ unsigned long flags;
int result;
Scsi_Cmnd * SCpnt;
Scsi_Device * SDpnt;
@@ -105,9 +106,11 @@ static int ioctl_internal_command(Scsi_Device *dev, char * cmd)
{
struct semaphore sem = MUTEX_LOCKED;
SCpnt->request.sem = &sem;
+ spin_lock_irqsave(&io_request_lock, flags);
scsi_do_cmd(SCpnt, cmd, NULL, 0,
scsi_ioctl_done, MAX_TIMEOUT,
MAX_RETRIES);
+ spin_unlock_irqrestore(&io_request_lock, flags);
down(&sem);
SCpnt->request.sem = NULL;
}
@@ -164,8 +167,9 @@ static int ioctl_internal_command(Scsi_Device *dev, char * cmd)
* interface instead, as this is a more flexible approach to performing
* generic SCSI commands on a device.
*/
-static int ioctl_command(Scsi_Device *dev, Scsi_Ioctl_Command *sic)
+int scsi_ioctl_send_command(Scsi_Device *dev, Scsi_Ioctl_Command *sic)
{
+ unsigned long flags;
char * buf;
unsigned char cmd[12];
char * cmd_in;
@@ -271,8 +275,10 @@ static int ioctl_command(Scsi_Device *dev, Scsi_Ioctl_Command *sic)
{
struct semaphore sem = MUTEX_LOCKED;
SCpnt->request.sem = &sem;
+ spin_lock_irqsave(&io_request_lock, flags);
scsi_do_cmd(SCpnt, cmd, buf, needed, scsi_ioctl_done,
timeout, retries);
+ spin_unlock_irqrestore(&io_request_lock, flags);
down(&sem);
SCpnt->request.sem = NULL;
}
@@ -381,7 +387,8 @@ int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg)
return ioctl_probe(dev->host, arg);
case SCSI_IOCTL_SEND_COMMAND:
if(!suser()) return -EACCES;
- return ioctl_command((Scsi_Device *) dev, (Scsi_Ioctl_Command *) arg);
+ return scsi_ioctl_send_command((Scsi_Device *) dev,
+ (Scsi_Ioctl_Command *) arg);
case SCSI_IOCTL_DOORLOCK:
if (!dev->removable || !dev->lockable) return 0;
scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL;
@@ -405,6 +412,8 @@ int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg)
return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd);
break;
default :
+ if (dev->host->hostt->ioctl)
+ return dev->host->hostt->ioctl(dev, cmd, arg);
return -EINVAL;
}
return -EINVAL;
diff --git a/drivers/scsi/scsi_obsolete.c b/drivers/scsi/scsi_obsolete.c
index daede4a56..fcb3348d4 100644
--- a/drivers/scsi/scsi_obsolete.c
+++ b/drivers/scsi/scsi_obsolete.c
@@ -83,7 +83,7 @@ static int update_timeout (Scsi_Cmnd *, int);
extern void scsi_old_times_out (Scsi_Cmnd * SCpnt);
extern void internal_cmnd (Scsi_Cmnd * SCpnt);
-static volatile struct Scsi_Host * host_active = NULL;
+extern volatile struct Scsi_Host * host_active;
#define SCSI_BLOCK(HOST) ((HOST->block && host_active && HOST != host_active) \
|| (HOST->can_queue && HOST->host_busy >= HOST->can_queue))
@@ -143,7 +143,9 @@ static void scsi_dump_status(void);
void scsi_old_times_out (Scsi_Cmnd * SCpnt)
{
+ unsigned long flags;
+ spin_lock_irqsave(&io_request_lock, flags);
switch (SCpnt->internal_timeout & (IN_ABORT | IN_RESET | IN_RESET2 | IN_RESET3))
{
case NORMAL_TIMEOUT:
@@ -154,12 +156,12 @@ void scsi_old_times_out (Scsi_Cmnd * SCpnt)
}
if (!scsi_abort (SCpnt, DID_TIME_OUT))
- return;
+ break;
case IN_ABORT:
printk("SCSI host %d abort (pid %ld) timed out - resetting\n",
SCpnt->host->host_no, SCpnt->pid);
if (!scsi_reset (SCpnt, SCSI_RESET_ASYNCHRONOUS))
- return;
+ break;
case IN_RESET:
case (IN_ABORT | IN_RESET):
/* This might be controversial, but if there is a bus hang,
@@ -173,7 +175,7 @@ void scsi_old_times_out (Scsi_Cmnd * SCpnt)
SCpnt->internal_timeout |= IN_RESET2;
scsi_reset (SCpnt,
SCSI_RESET_ASYNCHRONOUS | SCSI_RESET_SUGGEST_BUS_RESET);
- return;
+ break;
case (IN_ABORT | IN_RESET | IN_RESET2):
/* Obviously the bus reset didn't work.
* Let's try even harder and call for an HBA reset.
@@ -185,28 +187,29 @@ void scsi_old_times_out (Scsi_Cmnd * SCpnt)
SCpnt->internal_timeout |= IN_RESET3;
scsi_reset (SCpnt,
SCSI_RESET_ASYNCHRONOUS | SCSI_RESET_SUGGEST_HOST_RESET);
- return;
+ break;
default:
printk("SCSI host %d reset (pid %ld) timed out again -\n",
SCpnt->host->host_no, SCpnt->pid);
printk("probably an unrecoverable SCSI bus or device hang.\n");
- return;
+ break;
}
+ spin_unlock_irqrestore(&io_request_lock, flags);
}
-
+/*
+ * From what I can find in scsi_obsolete.c, this function is only called
+ * by scsi_old_done and scsi_reset. Both of these functions run with the
+ * io_request_lock already held, so we need do nothing here about grabbing
+ * any locks.
+ */
static void scsi_request_sense (Scsi_Cmnd * SCpnt)
{
- unsigned long flags;
-
- save_flags(flags);
- cli();
SCpnt->flags |= WAS_SENSE | ASKED_FOR_SENSE;
update_timeout(SCpnt, SENSE_TIMEOUT);
- restore_flags(flags);
memcpy ((void *) SCpnt->cmnd , (void *) generic_sense,
@@ -688,28 +691,25 @@ void scsi_old_done (Scsi_Cmnd * SCpnt)
static int scsi_abort (Scsi_Cmnd * SCpnt, int why)
{
int oldto;
- unsigned long flags;
struct Scsi_Host * host = SCpnt->host;
while(1)
{
- save_flags(flags);
- cli();
/*
* Protect against races here. If the command is done, or we are
* on a different command forget it.
*/
if (SCpnt->serial_number != SCpnt->serial_number_at_timeout) {
- restore_flags(flags);
return 0;
}
if (SCpnt->internal_timeout & IN_ABORT)
{
- restore_flags(flags);
+ spin_unlock_irq(&io_request_lock);
while (SCpnt->internal_timeout & IN_ABORT)
barrier();
+ spin_lock_irq(&io_request_lock);
}
else
{
@@ -725,7 +725,6 @@ static int scsi_abort (Scsi_Cmnd * SCpnt, int why)
SCpnt->channel, SCpnt->target, SCpnt->lun);
}
- restore_flags(flags);
if (!host->host_busy) {
SCpnt->internal_timeout &= ~IN_ABORT;
update_timeout(SCpnt, oldto);
@@ -749,11 +748,8 @@ static int scsi_abort (Scsi_Cmnd * SCpnt, int why)
*/
case SCSI_ABORT_SNOOZE:
if(why == DID_TIME_OUT) {
- save_flags(flags);
- cli();
SCpnt->internal_timeout &= ~IN_ABORT;
if(SCpnt->flags & WAS_TIMEDOUT) {
- restore_flags(flags);
return 1; /* Indicate we cannot handle this.
* We drop down into the reset handler
* and try again
@@ -763,15 +759,11 @@ static int scsi_abort (Scsi_Cmnd * SCpnt, int why)
oldto = SCpnt->timeout_per_command;
update_timeout(SCpnt, oldto);
}
- restore_flags(flags);
}
return 0;
case SCSI_ABORT_PENDING:
if(why != DID_TIME_OUT) {
- save_flags(flags);
- cli();
update_timeout(SCpnt, oldto);
- restore_flags(flags);
}
return 0;
case SCSI_ABORT_SUCCESS:
@@ -837,7 +829,6 @@ static void scsi_mark_bus_reset(struct Scsi_Host *Host, int channel)
static int scsi_reset (Scsi_Cmnd * SCpnt, unsigned int reset_flags)
{
int temp;
- unsigned long flags;
Scsi_Cmnd * SCpnt1;
Scsi_Device * SDpnt;
struct Scsi_Host * host = SCpnt->host;
@@ -894,8 +885,6 @@ static int scsi_reset (Scsi_Cmnd * SCpnt, unsigned int reset_flags)
#endif
while (1) {
- save_flags(flags);
- cli();
/*
* Protect against races here. If the command is done, or we are
@@ -903,15 +892,15 @@ static int scsi_reset (Scsi_Cmnd * SCpnt, unsigned int reset_flags)
*/
if (reset_flags & SCSI_RESET_ASYNCHRONOUS)
if (SCpnt->serial_number != SCpnt->serial_number_at_timeout) {
- restore_flags(flags);
return 0;
}
if (SCpnt->internal_timeout & IN_RESET)
{
- restore_flags(flags);
+ spin_unlock_irq(&io_request_lock);
while (SCpnt->internal_timeout & IN_RESET)
barrier();
+ spin_lock_irq(&io_request_lock);
}
else
{
@@ -920,7 +909,6 @@ static int scsi_reset (Scsi_Cmnd * SCpnt, unsigned int reset_flags)
if (host->host_busy)
{
- restore_flags(flags);
for(SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next)
{
SCpnt1 = SDpnt->device_queue;
@@ -955,7 +943,6 @@ static int scsi_reset (Scsi_Cmnd * SCpnt, unsigned int reset_flags)
else
{
if (!host->block) host->host_busy++;
- restore_flags(flags);
host->last_reset = jiffies;
SCpnt->flags |= (WAS_RESET | IS_RESETTING);
temp = host->hostt->reset(SCpnt, reset_flags);
@@ -985,10 +972,7 @@ static int scsi_reset (Scsi_Cmnd * SCpnt, unsigned int reset_flags)
else if (temp & SCSI_RESET_BUS_RESET)
scsi_mark_bus_reset(host, SCpnt->channel);
else scsi_mark_device_reset(SCpnt->device);
- save_flags(flags);
- cli();
SCpnt->internal_timeout &= ~(IN_RESET|IN_RESET2|IN_RESET3);
- restore_flags(flags);
return 0;
case SCSI_RESET_PENDING:
if (temp & SCSI_RESET_HOST_RESET)
@@ -1048,11 +1032,8 @@ static int scsi_reset (Scsi_Cmnd * SCpnt, unsigned int reset_flags)
* and we return 1 so that we get a message on the
* screen.
*/
- save_flags(flags);
- cli();
SCpnt->internal_timeout &= ~(IN_RESET|IN_RESET2|IN_RESET3);
update_timeout(SCpnt, 0);
- restore_flags(flags);
/* If you snooze, you lose... */
case SCSI_RESET_ERROR:
default:
diff --git a/drivers/scsi/scsiiom.c b/drivers/scsi/scsiiom.c
index e0838ba17..09c3407d6 100644
--- a/drivers/scsi/scsiiom.c
+++ b/drivers/scsi/scsiiom.c
@@ -269,6 +269,15 @@ DC390_Interrupt( int irq, void *dev_id, struct pt_regs *regs)
}
}
+static void
+do_DC390_Interrupt( int irq, void *dev_id, struct pt_regs *regs)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&io_request_lock, flags);
+ DC390_Interrupt(irq, dev_id, regs);
+ spin_unlock_irqrestore(&io_request_lock, flags);
+}
static void
DC390_DataOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 5f0668eb6..e7da5c954 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -36,6 +36,9 @@
#include <linux/errno.h>
#include <linux/interrupt.h>
+#include <linux/smp.h>
+#include <asm/smp_lock.h>
+
#include <asm/system.h>
#include <asm/io.h>
@@ -513,14 +516,10 @@ static void do_sd_request (void)
Scsi_Cmnd * SCpnt = NULL;
Scsi_Device * SDev;
struct request * req = NULL;
- unsigned long flags;
int flag = 0;
while (1==1){
- spin_lock_irqsave(&io_request_lock, flags);
-
if (CURRENT != NULL && CURRENT->rq_status == RQ_INACTIVE) {
- spin_unlock_irqrestore(&io_request_lock, flags);
return;
}
@@ -535,7 +534,6 @@ static void do_sd_request (void)
*/
if( SDev->host->in_recovery )
{
- spin_unlock_irqrestore(&io_request_lock, flags);
return;
}
@@ -555,10 +553,11 @@ static void do_sd_request (void)
*/
if( SDev->removable && !in_interrupt() )
{
- spin_unlock_irqrestore(&io_request_lock, flags);
+ spin_unlock_irq(&io_request_lock); /* FIXME!!!! */
scsi_ioctl(SDev, SCSI_IOCTL_DOORLOCK, 0);
/* scsi_ioctl may allow CURRENT to change, so start over. */
SDev->was_reset = 0;
+ spin_lock_irq(&io_request_lock); /* FIXME!!!! */
continue;
}
SDev->was_reset = 0;
@@ -587,7 +586,6 @@ static void do_sd_request (void)
* Using a "sti()" gets rid of the latency problems but causes
* race conditions and crashes.
*/
- spin_unlock_irqrestore(&io_request_lock, flags);
/* This is a performance enhancement. We dig down into the request
* list and try to find a queueable request (i.e. device not busy,
@@ -605,7 +603,6 @@ static void do_sd_request (void)
if (!SCpnt && sd_template.nr_dev > 1){
struct request *req1;
req1 = NULL;
- spin_lock_irqsave(&io_request_lock, flags);
req = CURRENT;
while(req){
SCpnt = scsi_request_queueable(req,
@@ -620,7 +617,6 @@ static void do_sd_request (void)
else
req1->next = req->next;
}
- spin_unlock_irqrestore(&io_request_lock, flags);
}
if (!SCpnt) return; /* Could not find anything to do */
@@ -1125,6 +1121,8 @@ static int sd_init_onedisk(int i)
return i;
}
+ spin_lock_irq(&io_request_lock);
+
/* We need to retry the READ_CAPACITY because a UNIT_ATTENTION is
* considered a fatal error, and many devices report such an error
* just after a scsi bus reset.
@@ -1157,7 +1155,9 @@ static int sd_init_onedisk(int i)
(void *) cmd, (void *) buffer,
512, sd_init_done, SD_TIMEOUT,
MAX_RETRIES);
+ spin_unlock_irq(&io_request_lock);
down(&sem);
+ spin_lock_irq(&io_request_lock);
SCpnt->request.sem = NULL;
}
@@ -1193,7 +1193,9 @@ static int sd_init_onedisk(int i)
(void *) cmd, (void *) buffer,
512, sd_init_done, SD_TIMEOUT,
MAX_RETRIES);
+ spin_unlock_irq(&io_request_lock);
down(&sem);
+ spin_lock_irq(&io_request_lock);
SCpnt->request.sem = NULL;
}
@@ -1201,8 +1203,10 @@ static int sd_init_onedisk(int i)
}
time1 = jiffies + HZ;
+ spin_unlock_irq(&io_request_lock);
while(jiffies < time1); /* Wait 1 second for next try */
printk( "." );
+ spin_lock_irq(&io_request_lock);
}
} while(the_result && spintime && spintime+100*HZ > jiffies);
if (spintime) {
@@ -1231,7 +1235,9 @@ static int sd_init_onedisk(int i)
(void *) cmd, (void *) buffer,
8, sd_init_done, SD_TIMEOUT,
MAX_RETRIES);
+ spin_unlock_irq(&io_request_lock);
down(&sem); /* sleep until it is ready */
+ spin_lock_irq(&io_request_lock);
SCpnt->request.sem = NULL;
}
@@ -1406,7 +1412,9 @@ static int sd_init_onedisk(int i)
(void *) cmd, (void *) buffer,
512, sd_init_done, SD_TIMEOUT,
MAX_RETRIES);
+ spin_unlock_irq(&io_request_lock);
down(&sem);
+ spin_lock_irq(&io_request_lock);
SCpnt->request.sem = NULL;
}
@@ -1431,6 +1439,7 @@ static int sd_init_onedisk(int i)
rscsi_disks[i].ten = 1;
rscsi_disks[i].remap = 1;
scsi_free(buffer, 512);
+ spin_unlock_irq(&io_request_lock);
return i;
}
@@ -1590,7 +1599,6 @@ static int sd_attach(Scsi_Device * SDp){
int revalidate_scsidisk(kdev_t dev, int maxusage){
int target;
struct gendisk * gdev;
- unsigned long flags;
int max_p;
int start;
int i;
@@ -1598,14 +1606,11 @@ int revalidate_scsidisk(kdev_t dev, int maxusage){
target = DEVICE_NR(dev);
gdev = &GENDISK_STRUCT;
- spin_lock_irqsave(&io_request_lock, flags);
if (DEVICE_BUSY || USAGE > maxusage) {
- spin_unlock_irqrestore(&io_request_lock, flags);
printk("Device busy for revalidation (usage=%d)\n", USAGE);
return -EBUSY;
}
DEVICE_BUSY = 1;
- spin_unlock_irqrestore(&io_request_lock, flags);
max_p = gdev->max_p;
start = target << gdev->minor_shift;
diff --git a/drivers/scsi/seagate.c b/drivers/scsi/seagate.c
index d532c13e4..2cd06a2d9 100644
--- a/drivers/scsi/seagate.c
+++ b/drivers/scsi/seagate.c
@@ -91,6 +91,7 @@
#include <asm/io.h>
#include <asm/system.h>
+#include <asm/spinlock.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/string.h>
@@ -343,6 +344,7 @@ static const Signature signatures[] =
static int hostno = -1;
static void seagate_reconnect_intr (int, void *, struct pt_regs *);
+static void do_seagate_reconnect_intr (int, void *, struct pt_regs *);
#ifdef FAST
static int fast = 1;
@@ -505,7 +507,7 @@ int seagate_st0x_detect (Scsi_Host_Template * tpnt)
*/
instance = scsi_register (tpnt, 0);
hostno = instance->host_no;
- if (request_irq ((int) irq, seagate_reconnect_intr, SA_INTERRUPT,
+ if (request_irq ((int) irq, do_seagate_reconnect_intr, SA_INTERRUPT,
(controller_type == SEAGATE) ? "seagate" : "tmc-8xx", NULL))
{
printk ("scsi%d : unable to allocate IRQ%d\n", hostno, (int) irq);
@@ -631,6 +633,16 @@ static int should_reconnect = 0;
* asserting SEL.
*/
+static void do_seagate_reconnect_intr (int irq, void *dev_id,
+ struct pt_regs *regs)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&io_request_lock, flags);
+ seagate_reconnect_intr(irq, dev_id, regs);
+ spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
static void seagate_reconnect_intr (int irq, void *dev_id,
struct pt_regs *regs)
{
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 1d14136fb..4232a56a5 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -28,6 +28,8 @@
#include <scsi/scsi_ioctl.h>
#include <scsi/sg.h>
+int sg_big_buff = SG_BIG_BUFF; /* for now, sg_big_buff is read-only through sysctl */
+
static int sg_init(void);
static int sg_attach(Scsi_Device *);
static int sg_detect(Scsi_Device *);
@@ -93,6 +95,15 @@ static int sg_ioctl(struct inode * inode,struct file * file,
return 0;
case SG_GET_TIMEOUT:
return scsi_generics[dev].timeout;
+ case SG_EMULATED_HOST:
+ return put_user(scsi_generics[dev].device->host->hostt->emulated, (int *) arg);
+ case SCSI_IOCTL_SEND_COMMAND:
+ /*
+ Allow SCSI_IOCTL_SEND_COMMAND without checking suser() since the
+ user already has read/write access to the generic device and so
+ can execute arbitrary SCSI commands.
+ */
+ return scsi_ioctl_send_command(scsi_generics[dev].device, (void *) arg);
default:
return scsi_ioctl(scsi_generics[dev].device, cmd_in, (void *) arg);
}
@@ -224,7 +235,6 @@ static ssize_t sg_read(struct file *filp, char *buf,
struct inode *inode = filp->f_dentry->d_inode;
int dev=MINOR(inode->i_rdev);
int i;
- unsigned long flags;
struct scsi_generic *device=&scsi_generics[dev];
/*
@@ -248,23 +258,18 @@ static ssize_t sg_read(struct file *filp, char *buf,
/*
* Wait until the command is actually done.
*/
- save_flags(flags);
- cli();
while(!device->pending || !device->complete)
{
if (filp->f_flags & O_NONBLOCK)
{
- restore_flags(flags);
return -EAGAIN;
}
interruptible_sleep_on(&device->read_wait);
if (signal_pending(current))
{
- restore_flags(flags);
return -ERESTARTSYS;
}
}
- restore_flags(flags);
/*
* Now copy the result back to the user buffer.
@@ -363,6 +368,7 @@ static void sg_command_done(Scsi_Cmnd * SCpnt)
static ssize_t sg_write(struct file *filp, const char *buf,
size_t count, loff_t *ppos)
{
+ unsigned long flags;
struct inode *inode = filp->f_dentry->d_inode;
int bsize,size,amt,i;
unsigned char cmnd[MAX_COMMAND_SIZE];
@@ -530,9 +536,11 @@ static ssize_t sg_write(struct file *filp, const char *buf,
* do not do any more here - when the interrupt arrives, we will
* then do the post-processing.
*/
+ spin_lock_irqsave(&io_request_lock, flags);
scsi_do_cmd (SCpnt,(void *) cmnd,
(void *) device->buff,amt,
sg_command_done,device->timeout,SG_DEFAULT_RETRIES);
+ spin_unlock_irqrestore(&io_request_lock, flags);
#ifdef DEBUG
printk("done cmd\n");
diff --git a/drivers/scsi/sgiwd93.c b/drivers/scsi/sgiwd93.c
index afd9fd6a9..d618bd54d 100644
--- a/drivers/scsi/sgiwd93.c
+++ b/drivers/scsi/sgiwd93.c
@@ -5,7 +5,7 @@
*
* (In all truth, Jed Schimmel wrote all this code.)
*
- * $Id: sgiwd93.c,v 1.7 1996/07/23 09:00:16 dm Exp $
+ * $Id: sgiwd93.c,v 1.6 1998/04/05 11:24:32 ralf Exp $
*/
#include <linux/init.h>
#include <linux/types.h>
@@ -21,6 +21,7 @@
#include <asm/sgihpc.h>
#include <asm/sgint23.h>
#include <asm/irq.h>
+#include <asm/spinlock.h>
#include <asm/io.h>
#include "scsi.h"
@@ -65,7 +66,11 @@ static inline unsigned long read_wd33c93_count(wd33c93_regs *regp)
/* XXX woof! */
static void sgiwd93_intr(int irq, void *dev_id, struct pt_regs *regs)
{
+ unsigned long flags;
+
+ spin_lock_irqsave(&io_request_lock, flags);
wd33c93_intr(sgiwd93_host);
+ spin_unlock_irqrestore(&io_request_lock, flags);
}
#undef DEBUG_DMA
diff --git a/drivers/scsi/sparc_esp.c b/drivers/scsi/sparc_esp.c
index 2b3341b3a..8bf8cf7e9 100644
--- a/drivers/scsi/sparc_esp.c
+++ b/drivers/scsi/sparc_esp.c
@@ -218,7 +218,7 @@ int esp_detect(Scsi_Host_Template *tpnt)
goto esp_irq_acquired; /* BASIC rulez */
}
}
- if(request_irq(esp->irq, esp_intr, SA_SHIRQ,
+ if(request_irq(esp->irq, do_esp_intr, SA_SHIRQ,
"Sparc ESP SCSI", NULL))
panic("Cannot acquire ESP irq line");
esp_irq_acquired:
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
index e5d3e830a..bbbffbd84 100644
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -427,14 +427,10 @@ static void do_sr_request (void)
Scsi_Cmnd * SCpnt = NULL;
struct request * req = NULL;
Scsi_Device * SDev;
- unsigned long flags;
int flag = 0;
while (1==1){
- spin_lock_irqsave(&io_request_lock, flags);
-
if (CURRENT != NULL && CURRENT->rq_status == RQ_INACTIVE) {
- spin_unlock_irqrestore(&io_request_lock, flags);
return;
};
@@ -450,7 +446,6 @@ static void do_sr_request (void)
*/
if( SDev->host->in_recovery )
{
- spin_unlock_irqrestore(&io_request_lock, flags);
return;
}
@@ -469,8 +464,9 @@ static void do_sr_request (void)
*/
if( SDev->removable && !in_interrupt() )
{
- spin_unlock_irqrestore(&io_request_lock, flags);
+ spin_unlock_irq(&io_request_lock); /* FIXME!!!! */
scsi_ioctl(SDev, SCSI_IOCTL_DOORLOCK, 0);
+ spin_lock_irq(&io_request_lock); /* FIXME!!!! */
/* scsi_ioctl may allow CURRENT to change, so start over. */
SDev->was_reset = 0;
continue;
@@ -493,7 +489,6 @@ static void do_sr_request (void)
SCpnt = scsi_allocate_device(&CURRENT,
scsi_CDs[DEVICE_NR(CURRENT->rq_dev)].device, 0);
else SCpnt = NULL;
- spin_unlock_irqrestore(&io_request_lock, flags);
/* This is a performance enhancement. We dig down into the request list and
* try to find a queueable request (i.e. device not busy, and host able to
@@ -505,7 +500,6 @@ static void do_sr_request (void)
if (!SCpnt && sr_template.nr_dev > 1){
struct request *req1;
req1 = NULL;
- spin_lock_irqsave(&io_request_lock, flags);
req = CURRENT;
while(req){
SCpnt = scsi_request_queueable(req,
@@ -520,7 +514,6 @@ static void do_sr_request (void)
else
req1->next = req->next;
}
- spin_unlock_irqrestore(&io_request_lock, flags);
}
if (!SCpnt)
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index 809dc93a6..35af3e391 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -30,6 +30,7 @@
#include <asm/uaccess.h>
#include <asm/dma.h>
#include <asm/system.h>
+#include <asm/spinlock.h>
/* The driver prints some debugging information on the console if DEBUG
is defined and non-zero. */
@@ -250,6 +251,9 @@ st_sleep_done (Scsi_Cmnd * SCpnt)
st_do_scsi(Scsi_Cmnd *SCpnt, Scsi_Tape *STp, unsigned char *cmd, int bytes,
int timeout, int retries)
{
+ unsigned long flags;
+
+ spin_lock_irqsave(&io_request_lock, flags);
if (SCpnt == NULL)
if ((SCpnt = scsi_allocate_device(NULL, STp->device, 1)) == NULL) {
printk(KERN_ERR "st%d: Can't get SCSI request.\n", TAPE_NR(STp->devt));
@@ -264,6 +268,7 @@ st_do_scsi(Scsi_Cmnd *SCpnt, Scsi_Tape *STp, unsigned char *cmd, int bytes,
scsi_do_cmd(SCpnt, (void *)cmd, (STp->buffer)->b_data, bytes,
st_sleep_done, timeout, retries);
+ spin_unlock_irqrestore(&io_request_lock, flags);
down(SCpnt->request.sem);
@@ -976,6 +981,7 @@ st_write(struct file * filp, const char * buf, size_t count, loff_t *ppos)
ST_mode * STm;
ST_partstat * STps;
int dev = TAPE_NR(inode->i_rdev);
+ unsigned long flags;
STp = &(scsi_tapes[dev]);
@@ -1271,10 +1277,12 @@ st_write(struct file * filp, const char * buf, size_t count, loff_t *ppos)
STp->write_pending = 1;
#endif
+ spin_lock_irqsave(&io_request_lock, flags);
scsi_do_cmd (SCpnt,
(void *) cmd, (STp->buffer)->b_data,
(STp->buffer)->writing,
st_sleep_done, STp->timeout, MAX_WRITE_RETRIES);
+ spin_unlock_irqrestore(&io_request_lock, flags);
}
else if (SCpnt != NULL)
{
diff --git a/drivers/scsi/t128.c b/drivers/scsi/t128.c
index 48036ed33..5c40b1e7e 100644
--- a/drivers/scsi/t128.c
+++ b/drivers/scsi/t128.c
@@ -250,7 +250,7 @@ __initfunc(int t128_detect(Scsi_Host_Template * tpnt)) {
instance->irq = NCR5380_probe_irq(instance, T128_IRQS);
if (instance->irq != IRQ_NONE)
- if (request_irq(instance->irq, t128_intr, SA_INTERRUPT, "t128", NULL)) {
+ if (request_irq(instance->irq, do_t128_intr, SA_INTERRUPT, "t128", NULL)) {
printk("scsi%d : IRQ%d not free, interrupts disabled\n",
instance->host_no, instance->irq);
instance->irq = IRQ_NONE;
diff --git a/drivers/scsi/t128.h b/drivers/scsi/t128.h
index 8f4f27f85..e3a8b6c90 100644
--- a/drivers/scsi/t128.h
+++ b/drivers/scsi/t128.h
@@ -163,6 +163,7 @@ int t128_proc_info (char *buffer, char **start, off_t offset,
#endif
#define NCR5380_intr t128_intr
+#define do_NCR5380_intr do_t128_intr
#define NCR5380_queue_command t128_queue_command
#define NCR5380_abort t128_abort
#define NCR5380_reset t128_reset
diff --git a/drivers/scsi/tmscsim.c b/drivers/scsi/tmscsim.c
index 980aadccc..ae272c215 100644
--- a/drivers/scsi/tmscsim.c
+++ b/drivers/scsi/tmscsim.c
@@ -26,7 +26,7 @@
* pending interrupt in DC390_detect() *
* 1.11 02/05/97 KG/CLH Fixeds problem with partitions greater *
* than 1GB *
- * 1.12 25/02/98 KG Cleaned up ifdefs for 2.1 kernel *
+ * 1.12 15/02/98 MJ Rewritten PCI probing *
***********************************************************************/
@@ -41,13 +41,13 @@
#include <asm/dma.h>
#include <asm/io.h>
#include <asm/system.h>
+#include <asm/spinlock.h>
#include <linux/delay.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/ioport.h>
-#include <linux/bios32.h>
#include <linux/pci.h>
#include <linux/proc_fs.h>
#include <linux/string.h>
@@ -118,8 +118,6 @@ static PDCB pPrevDCB = NULL;
static USHORT adapterCnt = 0;
static USHORT InitialTime = 0;
static USHORT CurrSyncOffset = 0;
-static ULONG mech1addr;
-static UCHAR mech2bus, mech2Agent, mech2CfgSPenR;
static PVOID DC390_phase0[]={
DC390_DataOut_0,
@@ -1160,7 +1158,7 @@ __initfunc(int DC390_initAdapter( PSH psh, ULONG io_port, UCHAR Irq, USHORT inde
if( !used_irq )
{
- if( request_irq(Irq, DC390_Interrupt, SA_INTERRUPT | SA_SHIRQ, "tmscsim", NULL))
+ if( request_irq(Irq, do_DC390_Interrupt, SA_INTERRUPT | SA_SHIRQ, "tmscsim", NULL))
{
printk("DC390: register IRQ error!\n");
return( -1 );
@@ -1200,147 +1198,7 @@ __initfunc(int DC390_initAdapter( PSH psh, ULONG io_port, UCHAR Irq, USHORT inde
void
-DC390_EnableCfg( USHORT mechnum, UCHAR regval )
-{
- ULONG wlval;
-
- if(mechnum == 2)
- {
- outb(mech2bus, PCI_CFG2_FORWARD_REG);
- outb(mech2CfgSPenR, PCI_CFG2_ENABLE_REG);
- }
- else
- {
- regval &= 0xFC;
- wlval = mech1addr;
- wlval |= (((ULONG)regval) & 0xff);
- outl(wlval, PCI_CFG1_ADDRESS_REG);
- }
-}
-
-
-void
-DC390_DisableCfg( USHORT mechnum )
-{
-
- if(mechnum == 2)
- outb(0, PCI_CFG2_ENABLE_REG);
- else
- outl(0, PCI_CFG1_ADDRESS_REG);
-}
-
-
-UCHAR
-DC390_inByte( USHORT mechnum, UCHAR regval )
-{
- UCHAR bval;
- ULONG wval;
- ULONG flags;
-
- save_flags(flags);
- cli();
- DC390_EnableCfg( mechnum, regval );
- if(mechnum == 2)
- {
- wval = mech2Agent;
- wval <<= 8;
- wval |= ((USHORT) regval) & 0xff;
- bval = inb(wval);
- }
- else
- {
- regval &= 3;
- bval = inb(PCI_CFG1_DATA_REG | regval);
- }
- DC390_DisableCfg(mechnum);
- restore_flags(flags);
- return(bval);
-}
-
-
-USHORT
-DC390_inWord( USHORT mechnum, UCHAR regval )
-{
- USHORT wval;
- ULONG flags;
-
- save_flags(flags);
- cli();
- DC390_EnableCfg(mechnum,regval);
- if(mechnum == 2)
- {
- wval = mech2Agent;
- wval <<= 8;
- wval |= regval;
- wval = inw(wval);
- }
- else
- {
- regval &= 3;
- wval = inw(PCI_CFG1_DATA_REG | regval);
- }
- DC390_DisableCfg(mechnum);
- restore_flags(flags);
- return(wval);
-}
-
-
-ULONG
-DC390_inDword(USHORT mechnum, UCHAR regval )
-{
- ULONG wlval;
- ULONG flags;
- USHORT wval;
-
- save_flags(flags);
- cli();
- DC390_EnableCfg(mechnum,regval);
- if(mechnum == 2)
- {
- wval = mech2Agent;
- wval <<= 8;
- wval |= regval;
- wlval = inl(wval);
- }
- else
- {
- wlval = inl(PCI_CFG1_DATA_REG);
- }
- DC390_DisableCfg(mechnum);
- restore_flags(flags);
- return(wlval);
-}
-
-
-void
-DC390_OutB(USHORT mechnum, UCHAR regval, UCHAR bval )
-{
-
- USHORT wval;
- ULONG flags;
-
- save_flags(flags);
- cli();
- DC390_EnableCfg(mechnum,regval);
- if(mechnum == 2)
- {
- wval = mech2Agent;
- wval <<= 8;
- wval |= regval;
- outb(bval, wval);
- }
- else
- {
- regval &= 3;
- outb(bval, PCI_CFG1_DATA_REG | regval);
- }
- DC390_DisableCfg(mechnum);
- restore_flags(flags);
-}
-
-
-void
-DC390_EnDisableCE( UCHAR mode, USHORT mechnum, PUCHAR regval )
+DC390_EnDisableCE( UCHAR mode, struct pci_dev *pdev, PUCHAR regval )
{
UCHAR bval;
@@ -1350,15 +1208,15 @@ DC390_EnDisableCE( UCHAR mode, USHORT mechnum, PUCHAR regval )
*regval = 0xc0;
else
*regval = 0x80;
- DC390_OutB(mechnum,*regval,bval);
+ pci_write_config_byte(pdev, *regval, bval);
if(mode == DISABLE_CE)
- DC390_OutB(mechnum,*regval,bval);
+ pci_write_config_byte(pdev, *regval, bval);
udelay(160);
}
void
-DC390_EEpromOutDI( USHORT mechnum, PUCHAR regval, USHORT Carry )
+DC390_EEpromOutDI( struct pci_dev *pdev, PUCHAR regval, USHORT Carry )
{
UCHAR bval;
@@ -1367,32 +1225,28 @@ DC390_EEpromOutDI( USHORT mechnum, PUCHAR regval, USHORT Carry )
{
bval = 0x40;
*regval = 0x80;
- DC390_OutB(mechnum,*regval,bval);
+ pci_write_config_byte(pdev, *regval, bval);
}
udelay(160);
bval |= 0x80;
- DC390_OutB(mechnum,*regval,bval);
+ pci_write_config_byte(pdev, *regval, bval);
udelay(160);
bval = 0;
- DC390_OutB(mechnum,*regval,bval);
+ pci_write_config_byte(pdev, *regval, bval);
udelay(160);
}
UCHAR
-DC390_EEpromInDO( USHORT mechnum )
+DC390_EEpromInDO( struct pci_dev *pdev )
{
- UCHAR bval,regval;
+ UCHAR bval;
- regval = 0x80;
- bval = 0x80;
- DC390_OutB(mechnum,regval,bval);
+ pci_write_config_byte(pdev, 0x80, 0x80);
udelay(160);
- bval = 0x40;
- DC390_OutB(mechnum,regval,bval);
+ pci_write_config_byte(pdev, 0x80, 0x40);
udelay(160);
- regval = 0x0;
- bval = DC390_inByte(mechnum,regval);
+ pci_read_config_byte(pdev, 0x00, &bval);
if(bval == 0x22)
return(1);
else
@@ -1401,7 +1255,7 @@ DC390_EEpromInDO( USHORT mechnum )
USHORT
-EEpromGetData1( USHORT mechnum )
+EEpromGetData1( struct pci_dev *pdev )
{
UCHAR i;
UCHAR carryFlag;
@@ -1411,7 +1265,7 @@ EEpromGetData1( USHORT mechnum )
for(i=0; i<16; i++)
{
wval <<= 1;
- carryFlag = DC390_EEpromInDO(mechnum);
+ carryFlag = DC390_EEpromInDO(pdev);
wval |= carryFlag;
}
return(wval);
@@ -1419,7 +1273,7 @@ EEpromGetData1( USHORT mechnum )
void
-DC390_Prepare( USHORT mechnum, PUCHAR regval, UCHAR EEpromCmd )
+DC390_Prepare( struct pci_dev *pdev, PUCHAR regval, UCHAR EEpromCmd )
{
UCHAR i,j;
USHORT carryFlag;
@@ -1428,7 +1282,7 @@ DC390_Prepare( USHORT mechnum, PUCHAR regval, UCHAR EEpromCmd )
j = 0x80;
for(i=0; i<9; i++)
{
- DC390_EEpromOutDI(mechnum,regval,carryFlag);
+ DC390_EEpromOutDI(pdev,regval,carryFlag);
carryFlag = (EEpromCmd & j) ? 1 : 0;
j >>= 1;
}
@@ -1436,7 +1290,7 @@ DC390_Prepare( USHORT mechnum, PUCHAR regval, UCHAR EEpromCmd )
void
-DC390_ReadEEprom( USHORT mechnum, USHORT index )
+DC390_ReadEEprom( struct pci_dev *pdev, int index )
{
UCHAR regval,cmd;
PUSHORT ptr;
@@ -1446,23 +1300,23 @@ DC390_ReadEEprom( USHORT mechnum, USHORT index )
cmd = EEPROM_READ;
for(i=0; i<0x40; i++)
{
- DC390_EnDisableCE(ENABLE_CE, mechnum, &regval);
- DC390_Prepare(mechnum, &regval, cmd);
- *ptr = EEpromGetData1(mechnum);
+ DC390_EnDisableCE(ENABLE_CE, pdev, &regval);
+ DC390_Prepare(pdev, &regval, cmd);
+ *ptr = EEpromGetData1(pdev);
ptr++;
cmd++;
- DC390_EnDisableCE(DISABLE_CE,mechnum,&regval);
+ DC390_EnDisableCE(DISABLE_CE, pdev, &regval);
}
}
USHORT
-DC390_CheckEEpromCheckSum( USHORT MechNum, USHORT index )
+DC390_CheckEEpromCheckSum( struct pci_dev *pdev, int index )
{
USHORT wval, rc, *ptr;
UCHAR i;
- DC390_ReadEEprom( MechNum, index );
+ DC390_ReadEEprom( pdev, index );
wval = 0;
ptr = (PUSHORT) &eepromBuf[index][0];
for(i=0; i<128 ;i+=2, ptr++)
@@ -1475,30 +1329,6 @@ DC390_CheckEEpromCheckSum( USHORT MechNum, USHORT index )
}
-USHORT
-DC390_ToMech( USHORT Mechnum, USHORT BusDevFunNum )
-{
- USHORT devnum;
-
- devnum = BusDevFunNum;
-
- if(Mechnum == 2)
- {
- if(devnum & 0x80)
- return(-1);
- mech2bus = (UCHAR)((devnum & 0xff00) >> 8); /* Bus num */
- mech2Agent = ((UCHAR)(devnum & 0xff)) >> 3; /* Dev num */
- mech2Agent |= 0xc0;
- mech2CfgSPenR = ((UCHAR)(devnum & 0xff)) & 0x07; /* Fun num */
- mech2CfgSPenR = (mech2CfgSPenR << 1) | 0x20;
- }
- else /* use mech #1 method */
- {
- mech1addr = 0x80000000 | ((ULONG)devnum << 8);
- }
- return(0);
-}
-
/***********************************************************************
* Function : static int DC390_init (struct Scsi_Host *host)
*
@@ -1511,12 +1341,12 @@ DC390_ToMech( USHORT Mechnum, USHORT BusDevFunNum )
***********************************************************************/
__initfunc(static int
-DC390_init (PSHT psht, ULONG io_port, UCHAR Irq, USHORT index, USHORT MechNum))
+DC390_init (PSHT psht, ULONG io_port, UCHAR Irq, struct pci_dev *pdev, int index))
{
PSH psh;
PACB pACB;
- if( !DC390_CheckEEpromCheckSum( MechNum, index) )
+ if( !DC390_CheckEEpromCheckSum( pdev, index ) )
{
psh = scsi_register( psht, sizeof(DC390_ACB) );
if( !psh )
@@ -1594,20 +1424,10 @@ DC390_init (PSHT psht, ULONG io_port, UCHAR Irq, USHORT index, USHORT MechNum))
__initfunc(int
DC390_detect(Scsi_Host_Template *psht))
{
-#ifdef FOR_PCI_OK
- UCHAR pci_bus, pci_device_fn;
- int error = 0;
- USHORT chipType = 0;
- USHORT i;
-#endif
-
- UCHAR irq;
- UCHAR istatus;
+ struct pci_dev *pdev = NULL;
+ UINT irq;
UINT io_port;
USHORT adaptCnt = 0; /* Number of boards detected */
- USHORT pci_index = 0; /* Device index to PCI BIOS calls */
- USHORT MechNum, BusDevFunNum;
- ULONG wlval;
psht->proc_dir = &proc_scsi_tmscsim;
@@ -1615,81 +1435,17 @@ DC390_detect(Scsi_Host_Template *psht))
pSHT_start = psht;
pACB_start = NULL;
- MechNum = 1;
- for( ; (MechNum < 3) && (!adaptCnt); MechNum++)
- {
- BusDevFunNum = 0;
- for (; adaptCnt < MAX_ADAPTER_NUM ;)
+ if ( pci_present() )
+ while ((pdev = pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD53C974, pdev)))
{
- if( !DC390_ToMech( MechNum, BusDevFunNum) )
- {
- wlval = DC390_inDword( MechNum, PCI_VENDOR_ID);
- if(wlval == ( (PCI_DEVICE_ID_AMD53C974 << 16)+
- PCI_VENDOR_ID_AMD) )
- {
- io_port =DC390_inDword(MechNum,PCI_BASE_ADDRESS_0) & 0xFFFE;
- irq = DC390_inByte( MechNum, PCI_INTERRUPT_LINE);
+ io_port = pdev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK;
+ irq = pdev->irq;
#ifdef DC390_DEBUG0
- printk("DC390: IO_PORT=%4x,IRQ=%x,\n",(UINT) io_port, irq);
+ printk("DC390: IO_PORT=%4x,IRQ=%x,\n",(UINT) io_port, irq);
#endif
- if( !DC390_init(psht, io_port, irq, pci_index, MechNum) )
- {
- adaptCnt++;
- pci_index++;
- istatus = inb( (USHORT)io_port+INT_Status ); /* Reset Pending INT */
-#ifdef DC390_DEBUG0
- printk("DC390: Mech=%2x,\n",(UCHAR) MechNum);
-#endif
- }
- }
- }
- if( BusDevFunNum != 0xfff8 )
- BusDevFunNum += 8; /* next device # */
- else
- break;
+ if( !DC390_init(psht, io_port, irq, pdev, adaptCnt))
+ adaptCnt++;
}
- }
-
-#ifdef FOR_PCI_OK
- if ( pcibios_present() )
- {
- for (i = 0; i < MAX_ADAPTER_NUM; ++i)
- {
- if( !pcibios_find_device( PCI_VENDOR_ID_AMD,
- PCI_DEVICE_ID_AMD53C974,
- pci_index, &pci_bus, &pci_device_fn) )
- {
- chipType = PCI_DEVICE_ID_AMD53C974;
- pci_index++;
- }
-
- if( chipType )
- {
-
- error = pcibios_read_config_dword(pci_bus, pci_device_fn,
- PCI_BASE_ADDRESS_0, &io_port);
- error |= pcibios_read_config_byte(pci_bus, pci_device_fn,
- PCI_INTERRUPT_LINE, &irq);
- if( error )
- {
- printk("DC390_detect: reading configuration registers error!\n");
- InitialTime = 0;
- return( 0 );
- }
-
- (USHORT) io_port = (USHORT) io_port & 0xFFFE;
-#ifdef DC390_DEBUG0
- printk("DC390: IO_PORT=%4x,IRQ=%x,\n",(UINT) io_port, irq);
-#endif
- if( !DC390_init(psht, io_port, irq, i) )
- adaptCnt++;
- chipType = 0;
- }
- else
- break;
- }
- }
-#endif
InitialTime = 0;
adapterCnt = adaptCnt;
diff --git a/drivers/scsi/tmscsim.h b/drivers/scsi/tmscsim.h
index ed22865fd..bdc582621 100644
--- a/drivers/scsi/tmscsim.h
+++ b/drivers/scsi/tmscsim.h
@@ -660,21 +660,4 @@ UCHAR xx2;
outl((value), DC390_ioport + (address)))
-/* Configuration method #1 */
-#define PCI_CFG1_ADDRESS_REG 0xcf8
-#define PCI_CFG1_DATA_REG 0xcfc
-#define PCI_CFG1_ENABLE 0x80000000
-#define PCI_CFG1_TUPPLE(bus, device, function, register) \
- (PCI_CFG1_ENABLE | (((bus) << 16) & 0xff0000) | \
- (((device) << 11) & 0xf800) | (((function) << 8) & 0x700)| \
- (((register) << 2) & 0xfc))
-
-/* Configuration method #2 */
-#define PCI_CFG2_ENABLE_REG 0xcf8
-#define PCI_CFG2_FORWARD_REG 0xcfa
-#define PCI_CFG2_ENABLE 0x0f0
-#define PCI_CFG2_TUPPLE(function) \
- (PCI_CFG2_ENABLE | (((function) << 1) & 0xe))
-
-
#endif /* _TMSCSIM_H */
diff --git a/drivers/scsi/u14-34f.c b/drivers/scsi/u14-34f.c
index fa980051a..6263e2258 100644
--- a/drivers/scsi/u14-34f.c
+++ b/drivers/scsi/u14-34f.c
@@ -1,6 +1,28 @@
/*
* 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.
+ *
+ * 17 Mar 1998 rev. 4.01 for linux 2.0.33 and 2.1.88
+ * 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.
@@ -21,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
@@ -105,15 +127,15 @@
* 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-1997 Dario Ballabio (dario@milano.europe.dg.com)
+ * Copyright (C) 1994-1998 Dario Ballabio (dario@milano.europe.dg.com)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that redistributions of source
@@ -134,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.
*
@@ -154,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.
@@ -185,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.
*
@@ -232,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:
@@ -248,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.
* ----------------------------------------------------------------------------
@@ -259,11 +281,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");
@@ -272,6 +297,7 @@ MODULE_PARM(link_statistics, "i");
MODULE_PARM(max_queue_depth, "i");
MODULE_AUTHOR("Dario Ballabio");
#endif
+
#endif
#include <linux/string.h>
@@ -282,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"
@@ -329,19 +360,16 @@ struct proc_dir_entry proc_scsi_u14_34f = {
#undef DEBUG_LINKED_COMMANDS
#undef DEBUG_DETECT
#undef DEBUG_INTERRUPT
-#undef DEBUG_STATISTICS
#undef DEBUG_RESET
-#undef DEBUG_SMP
#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)
#define MAX_CHANNEL 1
#define MAX_LUN 8
#define MAX_TARGET 8
-#define MAX_IRQ 16
#define MAX_MAILBOXES 16
#define MAX_SGLIST 32
#define MAX_SAFE_SGLIST 16
@@ -349,7 +377,7 @@ struct proc_dir_entry proc_scsi_u14_34f = {
#define MAX_CMD_PER_LUN 2
#define MAX_TAGGED_CMD_PER_LUN (MAX_MAILBOXES - MAX_CMD_PER_LUN)
-#define SKIP UINT_MAX
+#define SKIP ULONG_MAX
#define FALSE 0
#define TRUE 1
#define FREE 0
@@ -424,7 +452,6 @@ struct hostdata {
unsigned int cp_stat[MAX_MAILBOXES]; /* FREE, IN_USE, LOCKED, IN_RESET */
unsigned int last_cp_used; /* Index of last mailbox used */
unsigned int iocount; /* Total i/o done for this board */
- unsigned int multicount; /* Total ... in second ihdlr loop */
int board_number; /* Number of this board */
char board_name[16]; /* Name of this board */
char board_id[256]; /* data from INQUIRY on this board */
@@ -443,9 +470,12 @@ struct hostdata {
static struct Scsi_Host *sh[MAX_BOARDS + 1];
static const char *driver_name = "Ux4F";
-static unsigned int irqlist[MAX_IRQ], calls[MAX_IRQ];
+static char sha[MAX_BOARDS];
-static unsigned int io_port[] __initdata = {
+/* 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 = {
/* Space for MAX_INT_PARAM ports usable while loading as a module */
SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP,
@@ -462,10 +492,10 @@ static unsigned int io_port[] __initdata = {
#define BN(board) (HD(board)->board_name)
#define SWAP_BYTE(x) ((unsigned long)( \
- (((unsigned long)(x) & 0x000000ffU) << 24) | \
- (((unsigned long)(x) & 0x0000ff00U) << 8) | \
- (((unsigned long)(x) & 0x00ff0000U) >> 8) | \
- (((unsigned long)(x) & 0xff000000U) >> 24)))
+ (((unsigned long)(x) & 0x000000ffU) << 24) | \
+ (((unsigned long)(x) & 0x0000ff00U) << 8) | \
+ (((unsigned long)(x) & 0x00ff0000U) >> 8) | \
+ (((unsigned long)(x) & 0xff000000U) >> 24)))
#if defined(__BIG_ENDIAN)
#define H2DEV(x) SWAP_BYTE(x)
@@ -477,7 +507,7 @@ static unsigned int 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 u14_34f_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;
@@ -503,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);
@@ -560,7 +590,7 @@ static void select_queue_depths(struct Scsi_Host *host, Scsi_Device *devlist) {
return;
}
-static inline int wait_on_busy(unsigned int iobase, unsigned int loop) {
+static inline int wait_on_busy(unsigned long iobase, unsigned int loop) {
while (inb(iobase + REG_LCL_INTR) & BSY_ASSERTED) {
udelay(1L);
@@ -614,31 +644,31 @@ static int board_inquiry(unsigned int j) {
}
__initfunc (static inline int port_detect \
- (unsigned int port_base, unsigned int j, Scsi_Host_Template *tpnt)) {
+ (unsigned long port_base, unsigned int j, Scsi_Host_Template *tpnt)) {
unsigned char irq, dma_channel, subversion, i;
unsigned char in_byte;
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] = {
- { 16, 63 }, { 64, 32 }, { 64, 63 }, { 64, 32 }
- };
+ } mapping_table[4] = {
+ { 16, 63 }, { 64, 32 }, { 64, 63 }, { 64, 32 }
+ };
struct config_1 {
unsigned char bios_segment: 3;
@@ -659,7 +689,7 @@ __initfunc (static inline int port_detect \
sprintf(name, "%s%d", driver_name, j);
if(check_region(port_base, REGION_SIZE)) {
- printk("%s: address 0x%03x in use, skipping probe.\n", name, port_base);
+ printk("%s: address 0x%03lx in use, skipping probe.\n", name, port_base);
return FALSE;
}
@@ -676,17 +706,18 @@ __initfunc (static inline int port_detect \
dma_channel = dma_channel_table[config_1.dma_channel];
subversion = (in_byte & 0x0f);
- /* Board detected, allocate its IRQ if not already done */
- if ((irq >= MAX_IRQ) || (!irqlist[irq] && request_irq(irq,
- u14_34f_interrupt_handler, SA_INTERRUPT, driver_name, NULL))) {
+ /* Board detected, allocate its IRQ */
+ 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);
return FALSE;
}
if (subversion == ISA && request_dma(dma_channel, driver_name)) {
printk("%s: unable to allocate DMA channel %u, detaching.\n",
- name, dma_channel);
- free_irq(irq, NULL);
+ name, dma_channel);
+ free_irq(irq, &sha[j]);
return FALSE;
}
@@ -695,7 +726,7 @@ __initfunc (static inline int port_detect \
if (sh[j] == NULL) {
printk("%s: unable to register host, detaching.\n", name);
- if (!irqlist[irq]) free_irq(irq, NULL);
+ free_irq(irq, &sha[j]);
if (subversion == ISA) free_dma(dma_channel);
@@ -734,7 +765,6 @@ __initfunc (static inline int port_detect \
HD(j)->sectors = mapping_table[config_2.mapping_mode].sectors;
HD(j)->subversion = subversion;
HD(j)->board_number = j;
- irqlist[irq]++;
if (have_old_firmware) sh[j]->sg_tablesize = MAX_SAFE_SGLIST;
@@ -767,12 +797,12 @@ __initfunc (static inline int port_detect \
HD(j)->board_id[40] = 0;
if (strcmp(&HD(j)->board_id[32], "06000600")) {
- printk("%s: %s.\n", BN(j), &HD(j)->board_id[8]);
- printk("%s: firmware %s is outdated, FW PROM should be 28004-006.\n",
- BN(j), &HD(j)->board_id[32]);
- sh[j]->hostt->use_clustering = DISABLE_CLUSTERING;
- sh[j]->sg_tablesize = MAX_SAFE_SGLIST;
- }
+ printk("%s: %s.\n", BN(j), &HD(j)->board_id[8]);
+ printk("%s: firmware %s is outdated, FW PROM should be 28004-006.\n",
+ BN(j), &HD(j)->board_id[32]);
+ sh[j]->hostt->use_clustering = DISABLE_CLUSTERING;
+ sh[j]->sg_tablesize = MAX_SAFE_SGLIST;
+ }
}
if (dma_channel == NO_DMA) sprintf(dma_name, "%s", "BMST");
@@ -780,22 +810,23 @@ __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;
- printk("%s: %s 0x%03x, BIOS 0x%05x, IRQ %u, %s, SG %d, MB %d, of:%c, "\
- "lc:%c, mq:%d.\n", BN(j), bus_type, sh[j]->io_port, (int)sh[j]->base,
- sh[j]->irq, dma_name, sh[j]->sg_tablesize, sh[j]->can_queue,
- YESNO(have_old_firmware), YESNO(linked_comm), max_queue_depth);
+ printk("%s: %s 0x%03lx, BIOS 0x%05x, IRQ %u, %s, SG %d, MB %d, of:%c, "\
+ "lc:%c, mq:%d.\n", BN(j), bus_type, (unsigned long)sh[j]->io_port,
+ (int)sh[j]->base, sh[j]->irq, dma_name, sh[j]->sg_tablesize,
+ sh[j]->can_queue, YESNO(have_old_firmware), YESNO(linked_comm),
+ max_queue_depth);
if (sh[j]->max_id > 8 || sh[j]->max_lun > 8)
printk("%s: wide SCSI support enabled, max_id %u, max_lun %u.\n",
@@ -816,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;
}
@@ -857,11 +888,6 @@ __initfunc (int u14_34f_detect(Scsi_Host_Template *tpnt)) {
}
#endif
- for (k = 0; k < MAX_IRQ; k++) {
- irqlist[k] = 0;
- calls[k] = 0;
- }
-
for (k = 0; k < MAX_BOARDS + 1; k++) sh[k] = NULL;
for (k = 0; io_port[k]; k++) {
@@ -871,9 +897,10 @@ __initfunc (int u14_34f_detect(Scsi_Host_Template *tpnt)) {
if (j < MAX_BOARDS && port_detect(io_port[k], j, tpnt)) j++;
}
- if (j > 0)
- printk("UltraStor 14F/34F: Copyright (C) 1994-1997 Dario Ballabio.\n");
+ if (j > 0)
+ printk("UltraStor 14F/34F: Copyright (C) 1994-1998 Dario Ballabio.\n");
+ num_boards = j;
restore_flags(flags);
return j;
}
@@ -902,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
};
@@ -920,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;
@@ -938,26 +965,26 @@ int u14_34f_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
if (i >= sh[j]->can_queue) i = 0;
if (HD(j)->cp_stat[i] == FREE) {
- HD(j)->last_cp_used = i;
- break;
- }
+ HD(j)->last_cp_used = i;
+ break;
+ }
}
if (k == sh[j]->can_queue) {
printk("%s: qcomm, no free mailbox, resetting.\n", BN(j));
- 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)
- panic("%s: qcomm, SCSI_RESET_SUCCESS.\n", BN(j));
+ 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)
+ 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);
- return 0;
+ done(SCpnt);
+ return 1;
}
/* Set pointer to control packet structure */
@@ -969,16 +996,16 @@ 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;
for (k = 0; k < ARRAY_SIZE(data_out_cmds); k++)
if (SCpnt->cmnd[0] == data_out_cmds[k]) {
- cpp->xdir = DTD_OUT;
- break;
- }
+ cpp->xdir = DTD_OUT;
+ break;
+ }
if (cpp->xdir == DTD_IN)
for (k = 0; k < ARRAY_SIZE(data_none_cmds); k++)
@@ -1023,7 +1050,7 @@ int u14_34f_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
SCpnt->pid);
restore_flags(flags);
done(SCpnt);
- return 0;
+ return 1;
}
/* Store pointer in OGM address bytes */
@@ -1048,14 +1075,14 @@ int u14_34f_abort(Scsi_Cmnd *SCarg) {
if (SCarg->host_scribble == NULL
|| SCarg->serial_number != SCarg->serial_number_at_timeout) {
printk("%s: abort, target %d.%d:%d, pid %ld inactive.\n",
- BN(j), SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid);
+ BN(j), SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid);
restore_flags(flags);
return SCSI_ABORT_NOT_RUNNING;
}
i = *(unsigned int *)SCarg->host_scribble;
printk("%s: abort, mbox %d, target %d.%d:%d, pid %ld.\n",
- BN(j), i, SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid);
+ BN(j), i, SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid);
if (i >= sh[j]->can_queue)
panic("%s: abort, invalid SCarg->host_scribble.\n", BN(j));
@@ -1076,8 +1103,8 @@ int u14_34f_abort(Scsi_Cmnd *SCarg) {
printk("%s: abort, mbox %d is in use.\n", BN(j), i);
if (SCarg != HD(j)->cp[i].SCpnt)
- panic("%s: abort, mbox %d, SCarg %p, cp SCpnt %p.\n",
- BN(j), i, SCarg, HD(j)->cp[i].SCpnt);
+ panic("%s: abort, mbox %d, SCarg %p, cp SCpnt %p.\n",
+ BN(j), i, SCarg, HD(j)->cp[i].SCpnt);
if (inb(sh[j]->io_port + REG_SYS_INTR) & IRQ_ASSERTED)
printk("%s: abort, mbox %d, interrupt pending.\n", BN(j), i);
@@ -1103,7 +1130,7 @@ int u14_34f_abort(Scsi_Cmnd *SCarg) {
SCarg->host_scribble = NULL;
HD(j)->cp_stat[i] = FREE;
printk("%s, abort, mbox %d ready, DID_ABORT, pid %ld done.\n",
- BN(j), i, SCarg->pid);
+ BN(j), i, SCarg->pid);
SCarg->scsi_done(SCarg);
restore_flags(flags);
return SCSI_ABORT_SUCCESS;
@@ -1122,8 +1149,8 @@ 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",
- BN(j), SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid,
+ 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);
if (SCarg->host_scribble == NULL)
@@ -1160,13 +1187,13 @@ int u14_34f_reset(Scsi_Cmnd *SCarg, unsigned int reset_flags) {
if (HD(j)->cp_stat[i] == FREE) continue;
if (HD(j)->cp_stat[i] == LOCKED) {
- HD(j)->cp_stat[i] = FREE;
- printk("%s: reset, locked mbox %d forced free.\n", BN(j), i);
- continue;
- }
+ HD(j)->cp_stat[i] = FREE;
+ printk("%s: reset, locked mbox %d forced free.\n", BN(j), i);
+ continue;
+ }
if (!(SCpnt = HD(j)->cp[i].SCpnt))
- panic("%s: reset, mbox %d, SCpnt == NULL.\n", BN(j), i);
+ panic("%s: reset, mbox %d, SCpnt == NULL.\n", BN(j), i);
if (HD(j)->cp_stat[i] == READY || HD(j)->cp_stat[i] == ABORTING) {
HD(j)->cp_stat[i] = ABORTING;
@@ -1181,13 +1208,13 @@ 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);
+ panic("%s: reset, mbox %d, garbled SCpnt.\n", BN(j), i);
- if (*(unsigned int *)SCpnt->host_scribble != i)
- panic("%s: reset, mbox %d, index mismatch.\n", BN(j), i);
+ if (*(unsigned int *)SCpnt->host_scribble != i)
+ panic("%s: reset, mbox %d, index mismatch.\n", BN(j), i);
- if (SCpnt->scsi_done == NULL)
- panic("%s: reset, mbox %d, SCpnt->scsi_done == NULL.\n", BN(j), i);
+ if (SCpnt->scsi_done == NULL)
+ panic("%s: reset, mbox %d, SCpnt->scsi_done == NULL.\n", BN(j), i);
if (SCpnt == SCarg) arg_done = TRUE;
}
@@ -1223,7 +1250,7 @@ int u14_34f_reset(Scsi_Cmnd *SCarg, unsigned int reset_flags) {
HD(j)->cp_stat[i] = LOCKED;
printk("%s, reset, mbox %d locked, DID_RESET, pid %ld done.\n",
- BN(j), i, SCpnt->pid);
+ BN(j), i, SCpnt->pid);
}
else if (HD(j)->cp_stat[i] == ABORTING) {
@@ -1235,7 +1262,7 @@ int u14_34f_reset(Scsi_Cmnd *SCarg, unsigned int reset_flags) {
HD(j)->cp_stat[i] = FREE;
printk("%s, reset, mbox %d aborting, DID_RESET, pid %ld done.\n",
- BN(j), i, SCpnt->pid);
+ BN(j), i, SCpnt->pid);
}
else
@@ -1280,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;
}
@@ -1297,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;
@@ -1306,6 +1333,7 @@ static inline void reorder(unsigned int j, unsigned long cursec,
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;
@@ -1316,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;
@@ -1330,12 +1358,13 @@ static inline void reorder(unsigned int j, unsigned long cursec,
if (SCpnt->request.sector > maxsec) maxsec = SCpnt->request.sector;
sl[n] = SCpnt->request.sector;
+ ioseek += SCpnt->request.nr_sectors;
if (!n) continue;
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];
@@ -1351,6 +1380,8 @@ static inline void reorder(unsigned int j, unsigned long cursec,
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++) {
@@ -1358,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;
}
@@ -1367,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; }
@@ -1384,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,
@@ -1409,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;
@@ -1426,227 +1458,214 @@ 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 void u14_34f_interrupt_handler(int irq, void *dev_id,
- struct pt_regs *regs) {
+static inline void ihdlr(int irq, unsigned int j) {
Scsi_Cmnd *SCpnt;
- unsigned long flags;
- unsigned int i, j, k, c, status, tstatus, loops, total_loops = 0, reg, ret;
- struct mscp *spp;
+ unsigned int i, k, c, status, tstatus, reg, ret;
+ struct mscp *spp, *cpp;
- save_flags(flags);
- cli();
+ if (sh[j]->irq != irq)
+ panic("%s: ihdlr, irq %d, sh[j]->irq %d.\n", BN(j), irq, sh[j]->irq);
- if (!irqlist[irq]) {
- printk("%s, ihdlr, irq %d, unexpected interrupt.\n", driver_name, irq);
- restore_flags(flags);
+ /* 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 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;
}
- if (do_trace) printk("%s: ihdlr, enter, irq %d, calls %d.\n",
- driver_name, irq, calls[irq]);
-
- /* Service all the boards configured on this irq */
- for (j = 0; sh[j] != NULL; j++) {
+ 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);
+
+ /* 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),
+ (void *)ret, HD(j)->cp);
+
+ 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]);
+
+ HD(j)->cp_stat[i] = FREE;
+ 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 (*(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))
+ 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;
- if (sh[j]->irq != irq) continue;
+ /* 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;
- loops = 0;
+ 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;
- /* Loop until all interrupts for a board are serviced */
- while ((reg = inb(sh[j]->io_port + REG_SYS_INTR)) & IRQ_ASSERTED) {
- total_loops++;
- loops++;
-
- if (do_trace) printk("%s: ihdlr, start service, count %d.\n",
- BN(j), HD(j)->iocount);
+ if (HD(j)->last_retried_pid == SCpnt->pid) HD(j)->retries = 0;
- spp = (struct mscp *)DEV2V(ret = inl(sh[j]->io_port + REG_ICM));
+ break;
+ case ASST: /* Selection 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]++;
+ }
- /* Clear interrupt pending flag */
- outb(CMD_CLR_INTR, sh[j]->io_port + REG_SYS_INTR);
-
- i = spp - HD(j)->cp;
+ break;
- if (spp < HD(j)->cp || spp >= 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);
+ /* Perform a limited number of internal retries */
+ case 0x93: /* Unexpected bus free */
+ case 0x94: /* Target bus phase sequence failure */
+ case 0x96: /* Illegal SCSI command */
+ case 0xa3: /* SCSI bus reset error */
- if (HD(j)->cp_stat[i] == IGNORE) {
- HD(j)->cp_stat[i] = FREE;
- continue;
- }
- 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);
- continue;
- }
- else if (HD(j)->cp_stat[i] == FREE) {
- printk("%s: ihdlr, mbox %d is free, count %d.\n",
- BN(j), i, HD(j)->iocount);
- continue;
- }
- 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);
-
- HD(j)->cp_stat[i] = FREE;
- SCpnt = spp->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 (*(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 (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 */
-
- 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 0x93: /* Unexpected bus free */
- case 0x94: /* Target bus phase sequence failure */
- 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++)
- HD(j)->target_redo[k][c] = TRUE;
-
-
- case 0x92: /* Data over/under-run */
-
- 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 0x01: /* Invalid command */
- case 0x02: /* Invalid parameters */
- case 0x03: /* Invalid data list */
- case 0x84: /* SCSI bus abort error */
- case 0x9b: /* Auto request sense error */
- case 0x9f: /* Unexpected command complete message error */
- case 0xff: /* Invalid parameter in the S/G list */
- default:
- status = DID_ERROR << 16;
- break;
- }
-
- SCpnt->result = status | spp->target_status;
- HD(j)->iocount++;
-
- if (loops > 1) HD(j)->multicount++;
+ 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 */
+
+ 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 0x01: /* Invalid command */
+ case 0x02: /* Invalid parameters */
+ case 0x03: /* Invalid data list */
+ case 0x84: /* SCSI bus abort error */
+ case 0x9b: /* Auto request sense error */
+ case 0x9f: /* Unexpected command complete message error */
+ case 0xff: /* Invalid parameter in the S/G list */
+ 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;
+ /* Set the command state to inactive */
+ SCpnt->host_scribble = NULL;
- restore_flags(flags);
- SCpnt->scsi_done(SCpnt);
- cli();
+ SCpnt->scsi_done(SCpnt);
- } /* Multiple command loop */
+ if (do_trace) printk("%s: ihdlr, exit, irq %d, count %d.\n", BN(j), irq,
+ HD(j)->iocount);
- } /* Boards loop */
+ return;
+}
- calls[irq]++;
+static void do_interrupt_handler(int irq, void *shap, struct pt_regs *regs) {
-#if defined (DEBUG_SMP)
- if (total_loops == 0)
- printk("%s: ihdlr, irq %d, no command completed, calls %d.\n",
- driver_name, irq, calls[irq]);
-#endif
+ unsigned int j;
- if (do_trace) printk("%s: ihdlr, exit, irq %d, calls %d.\n",
- driver_name, irq, calls[irq]);
+ /* Check if the interrupt must be processed by this handler */
+ if ((j = (unsigned int)((char *)shap - sha)) >= num_boards) return;
-#if defined (DEBUG_STATISTICS)
- if ((calls[irq] % 100000) == 10000)
- for (j = 0; sh[j] != NULL; j++)
- printk("%s: ihdlr, calls %d, count %d, multi %d.\n", BN(j),
- calls[(sh[j]->irq)], HD(j)->iocount, HD(j)->multicount);
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,95)
+ {
+ unsigned long flags;
+ spin_lock_irqsave(&io_request_lock, flags);
+ ihdlr(irq, j);
+ spin_unlock_irqrestore(&io_request_lock, flags);
+ }
+#else
+ ihdlr(irq, j);
#endif
- restore_flags(flags);
- return;
}
int u14_34f_release(struct Scsi_Host *shpnt) {
@@ -1657,14 +1676,14 @@ 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);
- if (! --irqlist[sh[j]->irq]) free_irq(sh[j]->irq, NULL);
+ free_irq(sh[j]->irq, &sha[j]);
if (sh[j]->dma_channel != NO_DMA) free_dma(sh[j]->dma_channel);
diff --git a/drivers/scsi/u14-34f.h b/drivers/scsi/u14-34f.h
index 244bc811d..3c5e4a75c 100644
--- a/drivers/scsi/u14-34f.h
+++ b/drivers/scsi/u14-34f.h
@@ -4,6 +4,8 @@
#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 *));
@@ -11,18 +13,41 @@ 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 "3.11.00"
-
-#define ULTRASTOR_14_34F { \
- name: "UltraStor 14F/34F rev. " U14_34F_VERSION " ", \
- detect: u14_34f_detect, \
- release: u14_34f_release, \
- queuecommand: u14_34f_queuecommand, \
- abort: u14_34f_abort, \
- reset: u14_34f_reset, \
- bios_param: u14_34f_biosparam, \
- this_id: 7, /* this_id, reset by detect */ \
- unchecked_isa_dma: 1, /* unchecked isa dma, reset by detect */ \
- use_clustering: ENABLE_CLUSTERING \
- }
+#define U14_34F_VERSION "4.20.00"
+
+#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,88)
+
+#define ULTRASTOR_14_34F { \
+ name: "UltraStor 14F/34F rev. " U14_34F_VERSION " ", \
+ detect: u14_34f_detect, \
+ release: u14_34f_release, \
+ queuecommand: u14_34f_queuecommand, \
+ abort: u14_34f_abort, \
+ reset: u14_34f_reset, \
+ bios_param: u14_34f_biosparam, \
+ this_id: 7, \
+ unchecked_isa_dma: 1, \
+ use_clustering: ENABLE_CLUSTERING, \
+ use_new_eh_code: 1 /* Enable new error code */ \
+ }
+
+#else /* Use old scsi code */
+
+#define ULTRASTOR_14_34F { \
+ name: "UltraStor 14F/34F rev. " U14_34F_VERSION " ", \
+ detect: u14_34f_detect, \
+ release: u14_34f_release, \
+ queuecommand: u14_34f_queuecommand, \
+ abort: u14_34f_abort, \
+ reset: u14_34f_reset, \
+ bios_param: u14_34f_biosparam, \
+ this_id: 7, \
+ unchecked_isa_dma: 1, \
+ use_clustering: ENABLE_CLUSTERING, \
+ }
+
+#endif
+
#endif
diff --git a/drivers/scsi/ultrastor.c b/drivers/scsi/ultrastor.c
index 20f90e6e0..793875190 100644
--- a/drivers/scsi/ultrastor.c
+++ b/drivers/scsi/ultrastor.c
@@ -137,6 +137,7 @@
#include <asm/io.h>
#include <asm/bitops.h>
#include <asm/system.h>
+#include <asm/spinlock.h>
#include <asm/dma.h>
#define ULTRASTOR_PRIVATE /* Get the private stuff from ultrastor.h */
@@ -294,6 +295,7 @@ static const unsigned short ultrastor_ports_14f[] = {
#endif
static void ultrastor_interrupt(int, void *, struct pt_regs *);
+static void do_ultrastor_interrupt(int, void *, struct pt_regs *);
static inline void build_sg_list(struct mscp *, Scsi_Cmnd *SCpnt);
@@ -507,7 +509,7 @@ static int ultrastor_14f_detect(Scsi_Host_Template * tpnt)
config.mscp_free = ~0;
#endif
- if (request_irq(config.interrupt, ultrastor_interrupt, 0, "Ultrastor", NULL)) {
+ if (request_irq(config.interrupt, do_ultrastor_interrupt, 0, "Ultrastor", NULL)) {
printk("Unable to allocate IRQ%u for UltraStor controller.\n",
config.interrupt);
return FALSE;
@@ -577,7 +579,7 @@ static int ultrastor_24f_detect(Scsi_Host_Template * tpnt)
printk("U24F: invalid IRQ\n");
return FALSE;
}
- if (request_irq(config.interrupt, ultrastor_interrupt, 0, "Ultrastor", NULL))
+ if (request_irq(config.interrupt, do_ultrastor_interrupt, 0, "Ultrastor", NULL))
{
printk("Unable to allocate IRQ%u for UltraStor controller.\n",
config.interrupt);
@@ -1157,6 +1159,15 @@ static void ultrastor_interrupt(int irq, void *dev_id, struct pt_regs *regs)
#endif
}
+static void do_ultrastor_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&io_request_lock, flags);
+ ultrastor_interrupt(irq, dev_id, regs);
+ spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
#ifdef MODULE
/* Eventually this will go into an include file, but this will be later */
Scsi_Host_Template driver_template = ULTRASTOR_14F;
diff --git a/drivers/scsi/wd7000.c b/drivers/scsi/wd7000.c
index 1b915e3ed..89947e8a1 100644
--- a/drivers/scsi/wd7000.c
+++ b/drivers/scsi/wd7000.c
@@ -154,6 +154,7 @@
#include <linux/sched.h>
#include <linux/malloc.h>
#include <asm/system.h>
+#include <asm/spinlock.h>
#include <asm/dma.h>
#include <asm/io.h>
#include <linux/ioport.h>
@@ -513,7 +514,7 @@ typedef struct icbRevLvl {
typedef struct icbUnsMask { /* I'm totally guessing here */
unchar op;
volatile unchar mask[14]; /* mask bits */
-#ifdef 0
+#if 0
unchar rsvd[12]; /* reserved */
#endif
volatile unchar vue; /* vendor-unique error code */
@@ -1148,6 +1149,15 @@ void wd7000_intr_handle (int irq, void *dev_id, struct pt_regs *regs)
#endif
}
+void do_wd7000_intr_handle (int irq, void *dev_id, struct pt_regs *regs)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&io_request_lock, flags);
+ wd7000_intr_handle(irq, dev_id, regs);
+ spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
int wd7000_queuecommand (Scsi_Cmnd *SCpnt, void (*done) (Scsi_Cmnd *))
{
@@ -1314,7 +1324,7 @@ int wd7000_init (Adapter *host)
return (0);
}
- if (request_irq (host->irq, wd7000_intr_handle, SA_INTERRUPT, "wd7000", NULL)) {
+ if (request_irq (host->irq, do_wd7000_intr_handle, SA_INTERRUPT, "wd7000", NULL)) {
printk ("wd7000_init: can't get IRQ %d.\n", host->irq);
return (0);
}