summaryrefslogtreecommitdiffstats
path: root/drivers/acorn
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-04-19 04:00:00 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-04-19 04:00:00 +0000
commit46e045034336a2cc90c1798cd7cc07af744ddfd6 (patch)
tree3b9b51fc482e729f663d25333e77fbed9aaa939a /drivers/acorn
parent31dc59d503a02e84c4de98826452acaeb56dc15a (diff)
Merge with Linux 2.3.99-pre4.
Diffstat (limited to 'drivers/acorn')
-rw-r--r--drivers/acorn/char/keyb_ps2.c7
-rw-r--r--drivers/acorn/scsi/acornscsi.h5
-rw-r--r--drivers/acorn/scsi/arxescsi.c21
-rw-r--r--drivers/acorn/scsi/arxescsi.h38
-rw-r--r--drivers/acorn/scsi/cumana_2.c55
-rw-r--r--drivers/acorn/scsi/cumana_2.h45
-rw-r--r--drivers/acorn/scsi/eesox.c76
-rw-r--r--drivers/acorn/scsi/eesox.h37
-rw-r--r--drivers/acorn/scsi/fas216.c1032
-rw-r--r--drivers/acorn/scsi/fas216.h12
-rw-r--r--drivers/acorn/scsi/msgqueue.h2
-rw-r--r--drivers/acorn/scsi/powertec.c51
-rw-r--r--drivers/acorn/scsi/powertec.h43
-rw-r--r--drivers/acorn/scsi/queue.h2
14 files changed, 789 insertions, 637 deletions
diff --git a/drivers/acorn/char/keyb_ps2.c b/drivers/acorn/char/keyb_ps2.c
index 306feb2e9..8d26b37b1 100644
--- a/drivers/acorn/char/keyb_ps2.c
+++ b/drivers/acorn/char/keyb_ps2.c
@@ -32,8 +32,6 @@ extern struct tasklet_struct keyboard_tasklet;
extern void kbd_reset_kdown(void);
int kbd_read_mask;
-#define IRQ_KEYBOARDRX 15
-
#define VERSION 100
#define KBD_REPORT_ERR
@@ -330,6 +328,10 @@ int __init ps2kbd_init_hw(void)
{
unsigned long flags;
+ /* Reset the keyboard state machine. */
+ outb(0, IOMD_KCTRL);
+ outb(8, IOMD_KCTRL);
+
save_flags_cli (flags);
if (request_irq (IRQ_KEYBOARDRX, ps2kbd_rx, 0, "keyboard", NULL) != 0)
panic("Could not allocate keyboard receive IRQ!");
@@ -342,4 +344,3 @@ int __init ps2kbd_init_hw(void)
printk (KERN_INFO "PS/2 keyboard driver v%d.%02d\n", VERSION/100, VERSION%100);
return 0;
}
-
diff --git a/drivers/acorn/scsi/acornscsi.h b/drivers/acorn/scsi/acornscsi.h
index b6a7f3148..18cd873d5 100644
--- a/drivers/acorn/scsi/acornscsi.h
+++ b/drivers/acorn/scsi/acornscsi.h
@@ -1,3 +1,8 @@
+/*
+ * Acorn SCSI driver
+ *
+ * Copyright (C) 1997 Russell King
+ */
#ifndef ACORNSCSI_H
#define ACORNSCSI_H
diff --git a/drivers/acorn/scsi/arxescsi.c b/drivers/acorn/scsi/arxescsi.c
index cc1701708..27e5b266a 100644
--- a/drivers/acorn/scsi/arxescsi.c
+++ b/drivers/acorn/scsi/arxescsi.c
@@ -1,7 +1,7 @@
/*
- * linux/arch/arm/drivers/scsi/cumana_2.c
+ * linux/arch/arm/drivers/scsi/arxescsi.c
*
- * Copyright (C) 1997,1998 Russell King
+ * Copyright (C) 1997-2000 Russell King
*
* This driver is based on experimentation. Hence, it may have made
* assumptions about the particular card that I have available, and
@@ -13,6 +13,7 @@
* 15-04-1998 RMK 0.0.1 Only do PIO if FAS216 will allow it.
* 11-06-1998 0.0.2 Changed to support ARXE 16-bit SCSI card, enabled writing
* by Stefan Hanske
+ * 02-04-2000 RMK 0.0.3 Updated for new error handling code.
*/
#include <linux/module.h>
@@ -54,7 +55,7 @@
*/
#define VER_MAJOR 0
#define VER_MINOR 0
-#define VER_PATCH 2
+#define VER_PATCH 3
static struct expansion_card *ecs[MAX_ECARDS];
@@ -308,10 +309,9 @@ const char *arxescsi_info(struct Scsi_Host *host)
static char string[100], *p;
p = string;
- p += sprintf(string, "%s at port %lX irq %d v%d.%d.%d scsi %s",
- host->hostt->name, host->io_port, host->irq,
- VER_MAJOR, VER_MINOR, VER_PATCH,
- info->info.scsi.type);
+ p += sprintf(p, "%s ", host->hostt->name);
+ p += fas216_info(&info->info, p);
+ p += sprintf(p, "v%d.%d.%d", VER_MAJOR, VER_MINOR, VER_PATCH);
return string;
}
@@ -354,12 +354,7 @@ int arxescsi_proc_info(char *buffer, char **start, off_t offset,
pos = sprintf(buffer,
"ARXE 16-bit SCSI driver version %d.%d.%d\n",
VER_MAJOR, VER_MINOR, VER_PATCH);
- pos += sprintf(buffer + pos,
- "Address: %08lX IRQ : %d\n"
- "FAS : %s\n\n"
- "Statistics:\n",
- host->io_port, host->irq, info->info.scsi.type);
-
+ pos += fas216_print_host(&info->info, buffer + pos);
pos += fas216_print_stats(&info->info, buffer + pos);
pos += sprintf (buffer+pos, "\nAttached devices:\n");
diff --git a/drivers/acorn/scsi/arxescsi.h b/drivers/acorn/scsi/arxescsi.h
index 11dc6b6e3..dd97233ae 100644
--- a/drivers/acorn/scsi/arxescsi.h
+++ b/drivers/acorn/scsi/arxescsi.h
@@ -1,7 +1,8 @@
/*
* ARXE SCSI card driver
*
- * Copyright (C) 1997 Russell King
+ * Copyright (C) 1997-2000 Russell King
+ *
* Changes to support ARXE 16-bit SCSI card by Stefan Hanske
*/
#ifndef ARXE_SCSI_H
@@ -44,22 +45,25 @@ extern int arxescsi_proc_info (char *buffer, char **start, off_t offset,
#include "fas216.h"
#endif
-#define ARXEScsi { \
-proc_info: arxescsi_proc_info, \
-name: "ARXE SCSI card", \
-detect: arxescsi_detect, /* detect */ \
-release: arxescsi_release, /* release */ \
-info: arxescsi_info, /* info */ \
-command: fas216_command, /* command */ \
-queuecommand: fas216_queue_command, /* queuecommand */ \
-abort: fas216_abort, /* abort */ \
-reset: fas216_reset, /* reset */ \
-bios_param: scsicam_bios_param, /* biosparam */ \
-can_queue: CAN_QUEUE, /* can queue */ \
-this_id: SCSI_ID, /* scsi host id */ \
-sg_tablesize: SG_ALL, /* sg_tablesize */ \
-cmd_per_lun: CMD_PER_LUN, /* cmd per lun */ \
-use_clustering: DISABLE_CLUSTERING \
+#define ARXEScsi { \
+proc_info: arxescsi_proc_info, \
+name: "ARXE SCSI card", \
+detect: arxescsi_detect, \
+release: arxescsi_release, \
+info: arxescsi_info, \
+bios_param: scsicam_bios_param, \
+can_queue: CAN_QUEUE, \
+this_id: SCSI_ID, \
+sg_tablesize: SG_ALL, \
+cmd_per_lun: CMD_PER_LUN, \
+use_clustering: DISABLE_CLUSTERING, \
+command: fas216_command, \
+queuecommand: fas216_queue_command, \
+eh_host_reset_handler: fas216_eh_host_reset, \
+eh_bus_reset_handler: fas216_eh_bus_reset, \
+eh_device_reset_handler: fas216_eh_device_reset, \
+eh_abort_handler: fas216_eh_abort, \
+use_new_eh_code: 1 \
}
#ifndef HOSTS_C
diff --git a/drivers/acorn/scsi/cumana_2.c b/drivers/acorn/scsi/cumana_2.c
index 2307ae397..b812ef2d0 100644
--- a/drivers/acorn/scsi/cumana_2.c
+++ b/drivers/acorn/scsi/cumana_2.c
@@ -1,7 +1,7 @@
/*
* linux/arch/arm/drivers/scsi/cumana_2.c
*
- * Copyright (C) 1997-1998 Russell King
+ * Copyright (C) 1997-2000 Russell King
*
* Changelog:
* 30-08-1997 RMK 0.0.0 Created, READONLY version.
@@ -10,6 +10,7 @@
* 02-05-1998 RMK 0.0.2 Updated & added DMA support.
* 27-06-1998 RMK Changed asm/delay.h to linux/delay.h
* 18-08-1998 RMK 0.0.3 Fixed synchronous transfer depth.
+ * 02-04-2000 RMK 0.0.4 Updated for new error handling code.
*/
#include <linux/module.h>
@@ -70,7 +71,7 @@
*/
#define VER_MAJOR 0
#define VER_MINOR 0
-#define VER_PATCH 3
+#define VER_PATCH 4
static struct expansion_card *ecs[MAX_ECARDS];
@@ -433,25 +434,11 @@ const char *cumanascsi_2_info(struct Scsi_Host *host)
static char string[100], *p;
p = string;
- p += sprintf(string, "%s at port %lX ",
- host->hostt->name, host->io_port);
-
- if (host->irq != NO_IRQ)
- p += sprintf(p, "irq %d ", host->irq);
- else
- p += sprintf(p, "NO IRQ ");
-
- if (host->dma_channel != NO_DMA)
- p += sprintf(p, "dma %d ", host->dma_channel);
- else
- p += sprintf(p, "NO DMA ");
-
- p += sprintf(p, "v%d.%d.%d scsi %s",
+ p += sprintf(p, "%s ", host->hostt->name);
+ p += fas216_info(&info->info, p);
+ p += sprintf(p, "v%d.%d.%d terminators o%s",
VER_MAJOR, VER_MINOR, VER_PATCH,
- info->info.scsi.type);
-
- p += sprintf(p, " terminators %s",
- info->terms ? "on" : "off");
+ info->terms ? "n" : "ff");
return string;
}
@@ -525,26 +512,14 @@ int cumanascsi_2_proc_info (char *buffer, char **start, off_t offset,
pos = sprintf(buffer,
"Cumana SCSI II driver version %d.%d.%d\n",
VER_MAJOR, VER_MINOR, VER_PATCH);
- pos += sprintf(buffer + pos,
- "Address: %08lX IRQ : %d DMA : %d\n"
- "FAS : %-10s TERM: %-3s\n\n"
- "Statistics:\n",
- host->io_port, host->irq, host->dma_channel,
- info->info.scsi.type, info->terms ? "on" : "off");
-
- pos += sprintf(buffer+pos,
- "Queued commands: %-10u Issued commands: %-10u\n"
- "Done commands : %-10u Reads : %-10u\n"
- "Writes : %-10u Others : %-10u\n"
- "Disconnects : %-10u Aborts : %-10u\n"
- "Resets : %-10u\n",
- info->info.stats.queues, info->info.stats.removes,
- info->info.stats.fins, info->info.stats.reads,
- info->info.stats.writes, info->info.stats.miscs,
- info->info.stats.disconnects, info->info.stats.aborts,
- info->info.stats.resets);
-
- pos += sprintf(buffer+pos, "\nAttached devices:%s\n", host->host_queue ? "" : " none");
+
+ pos += fas216_print_host(&info->info, buffer + pos);
+ pos += sprintf(buffer + pos, "Term : o%s\n",
+ info->terms ? "n" : "ff");
+
+ pos += fas216_print_stats(&info->info, buffer + pos);
+
+ pos += sprintf(buffer+pos, "\nAttached devices:\n");
for (scd = host->host_queue; scd; scd = scd->next) {
int len;
diff --git a/drivers/acorn/scsi/cumana_2.h b/drivers/acorn/scsi/cumana_2.h
index 66b374019..48ac695b7 100644
--- a/drivers/acorn/scsi/cumana_2.h
+++ b/drivers/acorn/scsi/cumana_2.h
@@ -1,7 +1,7 @@
/*
* Cumana SCSI II driver
*
- * Copyright (C) 1997-1998 Russell King
+ * Copyright (C) 1997-2000 Russell King
*/
#ifndef CUMANA_2_H
#define CUMANA_2_H
@@ -23,6 +23,13 @@ extern int cumanascsi_2_proc_info (char *buffer, char **start, off_t offset,
#define CAN_QUEUE 1
#endif
+#ifndef CMD_PER_LUN
+/*
+ * Default queue size
+ */
+#define CMD_PER_LUN 1
+#endif
+
#ifndef SCSI_ID
/*
* Default SCSI host ID
@@ -36,23 +43,25 @@ extern int cumanascsi_2_proc_info (char *buffer, char **start, off_t offset,
#include "fas216.h"
#endif
-#define CUMANASCSI_2 { \
-proc_info: cumanascsi_2_proc_info, \
-name: "Cumana SCSI II", \
-detect: cumanascsi_2_detect, /* detect */ \
-release: cumanascsi_2_release, /* release */ \
-info: cumanascsi_2_info, /* info */ \
-command: fas216_command, /* command */ \
-queuecommand: fas216_queue_command, /* queuecommand */ \
-abort: fas216_abort, /* abort */ \
-reset: fas216_reset, /* reset */ \
-bios_param: scsicam_bios_param, /* biosparam */ \
-can_queue: CAN_QUEUE, /* can queue */ \
-this_id: SCSI_ID, /* scsi host id */ \
-sg_tablesize: SG_ALL, /* sg_tablesize */ \
-cmd_per_lun: CAN_QUEUE, /* cmd per lun */ \
-unchecked_isa_dma: 0, /* unchecked isa dma */ \
-use_clustering: DISABLE_CLUSTERING \
+#define CUMANASCSI_2 { \
+proc_info: cumanascsi_2_proc_info, \
+name: "Cumana SCSI II", \
+detect: cumanascsi_2_detect, \
+release: cumanascsi_2_release, \
+info: cumanascsi_2_info, \
+bios_param: scsicam_bios_param, \
+can_queue: CAN_QUEUE, \
+this_id: SCSI_ID, \
+sg_tablesize: SG_ALL, \
+cmd_per_lun: CMD_PER_LUN, \
+use_clustering: DISABLE_CLUSTERING, \
+command: fas216_command, \
+queuecommand: fas216_queue_command, \
+eh_host_reset_handler: fas216_eh_host_reset, \
+eh_bus_reset_handler: fas216_eh_bus_reset, \
+eh_device_reset_handler: fas216_eh_device_reset, \
+eh_abort_handler: fas216_eh_abort, \
+use_new_eh_code: 1 \
}
#ifndef HOSTS_C
diff --git a/drivers/acorn/scsi/eesox.c b/drivers/acorn/scsi/eesox.c
index e6a6a4005..2ebe06f59 100644
--- a/drivers/acorn/scsi/eesox.c
+++ b/drivers/acorn/scsi/eesox.c
@@ -1,20 +1,22 @@
/*
* linux/arch/arm/drivers/scsi/eesox.c
*
- * Copyright (C) 1997-1998 Russell King
+ * Copyright (C) 1997-2000 Russell King
*
* This driver is based on experimentation. Hence, it may have made
* assumptions about the particular card that I have available, and
* may not be reliable!
*
* Changelog:
- * 01-10-1997 RMK Created, READONLY version
- * 15-02-1998 RMK READ/WRITE version
- * added DMA support and hardware definitions
- * 14-03-1998 RMK Updated DMA support
- * Added terminator control
- * 15-04-1998 RMK Only do PIO if FAS216 will allow it.
- * 27-06-1998 RMK Changed asm/delay.h to linux/delay.h
+ * 01-10-1997 RMK Created, READONLY version
+ * 15-02-1998 RMK READ/WRITE version
+ * added DMA support and hardware definitions
+ * 14-03-1998 RMK Updated DMA support
+ * Added terminator control
+ * 15-04-1998 RMK Only do PIO if FAS216 will allow it.
+ * 27-06-1998 RMK Changed asm/delay.h to linux/delay.h
+ * 02-04-2000 RMK 0.0.3 Fixed NO_IRQ/NO_DMA problem, updated for new
+ * error handling code.
*/
#include <linux/module.h>
@@ -67,7 +69,7 @@
*/
#define VER_MAJOR 0
#define VER_MINOR 0
-#define VER_PATCH 2
+#define VER_PATCH 3
static struct expansion_card *ecs[MAX_ECARDS];
@@ -382,14 +384,16 @@ eesoxscsi_detect(Scsi_Host_Template *tpnt)
request_region(host->io_port + EESOX_FAS216_OFFSET,
16 << EESOX_FAS216_SHIFT, "eesox2-fas");
- if (request_irq(host->irq, eesoxscsi_intr,
+ if (host->irq != NO_IRQ &&
+ request_irq(host->irq, eesoxscsi_intr,
SA_INTERRUPT, "eesox", host)) {
printk("scsi%d: IRQ%d not free, interrupts disabled\n",
host->host_no, host->irq);
host->irq = NO_IRQ;
}
- if (request_dma(host->dma_channel, "eesox")) {
+ if (host->dma_channel != NO_DMA &&
+ request_dma(host->dma_channel, "eesox")) {
printk("scsi%d: DMA%d not free, DMA disabled\n",
host->host_no, host->dma_channel);
host->dma_channel = NO_DMA;
@@ -435,24 +439,11 @@ const char *eesoxscsi_info(struct Scsi_Host *host)
static char string[100], *p;
p = string;
- p += sprintf(string, "%s at port %lX ",
- host->hostt->name, host->io_port);
-
- if (host->irq != NO_IRQ)
- p += sprintf(p, "irq %d ", host->irq);
- else
- p += sprintf(p, "NO IRQ ");
-
- if (host->dma_channel != NO_DMA)
- p += sprintf(p, "dma %d ", host->dma_channel);
- else
- p += sprintf(p, "NO DMA ");
-
- p += sprintf(p, "v%d.%d.%d scsi %s", VER_MAJOR, VER_MINOR, VER_PATCH,
- info->info.scsi.type);
-
- p += sprintf(p, " terminators %s",
- info->control.control & EESOX_TERM_ENABLE ? "on" : "off");
+ p += sprintf(p, "%s ", host->hostt->name);
+ p += fas216_info(&info->info, p);
+ p += sprintf(p, "v%d.%d.%d terminators o%s",
+ VER_MAJOR, VER_MINOR, VER_PATCH,
+ info->control.control & EESOX_TERM_ENABLE ? "n" : "ff");
return string;
}
@@ -526,26 +517,13 @@ int eesoxscsi_proc_info(char *buffer, char **start, off_t offset,
pos = sprintf(buffer,
"EESOX SCSI driver version %d.%d.%d\n",
VER_MAJOR, VER_MINOR, VER_PATCH);
- pos += sprintf(buffer + pos,
- "Address: %08lX IRQ : %d DMA : %d\n"
- "FAS : %-10s TERM: %-3s\n\n"
- "Statistics:\n",
- host->io_port, host->irq, host->dma_channel,
- info->info.scsi.type, info->control.control & EESOX_TERM_ENABLE ? "on" : "off");
-
- pos += sprintf(buffer+pos,
- "Queued commands: %-10u Issued commands: %-10u\n"
- "Done commands : %-10u Reads : %-10u\n"
- "Writes : %-10u Others : %-10u\n"
- "Disconnects : %-10u Aborts : %-10u\n"
- "Resets : %-10u\n",
- info->info.stats.queues, info->info.stats.removes,
- info->info.stats.fins, info->info.stats.reads,
- info->info.stats.writes, info->info.stats.miscs,
- info->info.stats.disconnects, info->info.stats.aborts,
- info->info.stats.resets);
-
- pos += sprintf (buffer+pos, "\nAttached devices:%s\n", host->host_queue ? "" : " none");
+ pos += fas216_print_host(&info->info, buffer + pos);
+ pos += sprintf(buffer + pos, "Term : o%s\n",
+ info->control.control & EESOX_TERM_ENABLE ? "n" : "ff");
+
+ pos += fas216_print_stats(&info->info, buffer + pos);
+
+ pos += sprintf (buffer+pos, "\nAttached devices:\n");
for (scd = host->host_queue; scd; scd = scd->next) {
int len;
diff --git a/drivers/acorn/scsi/eesox.h b/drivers/acorn/scsi/eesox.h
index 31c6c883e..05433fd6b 100644
--- a/drivers/acorn/scsi/eesox.h
+++ b/drivers/acorn/scsi/eesox.h
@@ -1,7 +1,7 @@
/*
* EESOX SCSI driver
*
- * Copyright (C) 1997-1998 Russell King
+ * Copyright (C) 1997-2000 Russell King
*/
#ifndef EESOXSCSI_H
#define EESOXSCSI_H
@@ -38,22 +38,25 @@ extern int eesoxscsi_proc_info (char *buffer, char **start, off_t offset,
#include "fas216.h"
-#define EESOXSCSI { \
-proc_info: eesoxscsi_proc_info, \
-name: "EESOX SCSI", \
-detect: eesoxscsi_detect, /* detect */ \
-release: eesoxscsi_release, /* release */ \
-info: eesoxscsi_info, /* info */ \
-command: fas216_command, /* command */ \
-queuecommand: fas216_queue_command, /* queuecommand */ \
-abort: fas216_abort, /* abort */ \
-reset: fas216_reset, /* reset */ \
-bios_param: scsicam_bios_param, /* biosparam */ \
-can_queue: CAN_QUEUE, /* can queue */ \
-this_id: SCSI_ID, /* scsi host id */ \
-sg_tablesize: SG_ALL, /* sg_tablesize */ \
-cmd_per_lun: CAN_QUEUE, /* cmd per lun */ \
-use_clustering: DISABLE_CLUSTERING \
+#define EESOXSCSI { \
+proc_info: eesoxscsi_proc_info, \
+name: "EESOX SCSI", \
+detect: eesoxscsi_detect, \
+release: eesoxscsi_release, \
+info: eesoxscsi_info, \
+bios_param: scsicam_bios_param, \
+can_queue: CAN_QUEUE, \
+this_id: SCSI_ID, \
+sg_tablesize: SG_ALL, \
+cmd_per_lun: CAN_QUEUE, \
+use_clustering: DISABLE_CLUSTERING, \
+command: fas216_command, \
+queuecommand: fas216_queue_command, \
+eh_host_reset_handler: fas216_eh_host_reset, \
+eh_bus_reset_handler: fas216_eh_bus_reset, \
+eh_device_reset_handler: fas216_eh_device_reset, \
+eh_abort_handler: fas216_eh_abort, \
+use_new_eh_code: 1 \
}
#ifndef HOSTS_C
diff --git a/drivers/acorn/scsi/fas216.c b/drivers/acorn/scsi/fas216.c
index 744480f51..1a89a91eb 100644
--- a/drivers/acorn/scsi/fas216.c
+++ b/drivers/acorn/scsi/fas216.c
@@ -1,11 +1,12 @@
/*
* linux/arch/arm/drivers/scsi/fas216.c
*
- * Copyright (C) 1997 Russell King
+ * Copyright (C) 1997-2000 Russell King
*
* Based on information in qlogicfas.c by Tom Zerucha, Michael Griffith, and
* other sources, including:
* the AMD Am53CF94 data sheet
+ * the AMD Am53C94 data sheet
*
* This is a generic driver. To use it, have a look at cumana_2.c. You
* should define your own structure that overlays FAS216_Info, eg:
@@ -25,6 +26,9 @@
* 24-05-1998 RMK Fixed synchronous transfers with period >= 200ns
* 27-06-1998 RMK Changed asm/delay.h to linux/delay.h
* 26-08-1998 RMK Improved message support wrt MESSAGE_REJECT
+ * 02-04-2000 RMK Converted to use the new error handling, and
+ * automatically request sense data upon check
+ * condition status from targets.
*
* Todo:
* - allow individual devices to enable sync xfers.
@@ -59,8 +63,6 @@ MODULE_DESCRIPTION("Generic FAS216/NCR53C9x driver");
#define VER_MINOR 0
#define VER_PATCH 5
-#define SCSI2_TAG
-
/* NOTE: SCSI2 Synchronous transfers *require* DMA according to
* the data sheet. This restriction is crazy, especially when
* you only want to send 16 bytes! What were the guys who
@@ -85,8 +87,8 @@ MODULE_DESCRIPTION("Generic FAS216/NCR53C9x driver");
* I was thinking that this was a good chip until I found this restriction ;(
*/
#define SCSI2_SYNC
-
-#define SCSI2_WIDE
+#undef SCSI2_WIDE
+#undef SCSI2_TAG
#undef DEBUG_CONNECT
#undef DEBUG_BUSSERVICE
@@ -143,10 +145,11 @@ static void fas216_dumpinfo(FAS216_Info *info)
info->scsi.async_stp,
info->scsi.disconnectable, info->scsi.aborting);
printk(" stats={ queues=%X removes=%X fins=%X reads=%X writes=%X miscs=%X\n"
- " disconnects=%X aborts=%X resets=%X }\n",
+ " disconnects=%X aborts=%X bus_resets=%X host_resets=%X}\n",
info->stats.queues, info->stats.removes, info->stats.fins,
info->stats.reads, info->stats.writes, info->stats.miscs,
- info->stats.disconnects, info->stats.aborts, info->stats.resets);
+ info->stats.disconnects, info->stats.aborts, info->stats.bus_resets,
+ info->stats.host_resets);
printk(" ifcfg={ clockrate=%X select_timeout=%X asyncperiod=%X sync_max_depth=%X }\n",
info->ifcfg.clockrate, info->ifcfg.select_timeout,
info->ifcfg.asyncperiod, info->ifcfg.sync_max_depth);
@@ -164,7 +167,7 @@ static void fas216_dumpinfo(FAS216_Info *info)
}
#ifdef CHECK_STRUCTURE
-static void fas216_checkmagic(FAS216_Info *info, const char *func)
+static void __fas216_checkmagic(FAS216_Info *info, const char *func)
{
int corruption = 0;
if (info->magic_start != MAGIC) {
@@ -180,8 +183,9 @@ static void fas216_checkmagic(FAS216_Info *info, const char *func)
panic("scsi memory space corrupted in %s", func);
}
}
+#define fas216_checkmagic(info) __fas216_checkmagic((info), __FUNCTION__)
#else
-#define fas216_checkmagic(info,func)
+#define fas216_checkmagic(info)
#endif
static const char *fas216_bus_phase(int stat)
@@ -312,7 +316,7 @@ fas216_syncperiod(FAS216_Info *info, int ns)
{
int value = (info->ifcfg.clockrate * ns) / 1000;
- fas216_checkmagic(info, "fas216_syncperiod");
+ fas216_checkmagic(info);
if (value < 4)
value = 4;
@@ -586,7 +590,7 @@ fas216_updateptrs(FAS216_Info *info, int bytes_transferred)
unsigned char *ptr;
unsigned int residual;
- fas216_checkmagic(info, "fas216_updateptrs");
+ fas216_checkmagic(info);
ptr = info->scsi.SCp.ptr;
residual = info->scsi.SCp.this_residual;
@@ -629,7 +633,7 @@ fas216_pio(FAS216_Info *info, fasdmadir_t direction)
unsigned int residual;
char *ptr;
- fas216_checkmagic(info, "fas216_pio");
+ fas216_checkmagic(info);
residual = info->scsi.SCp.this_residual;
ptr = info->scsi.SCp.ptr;
@@ -668,7 +672,7 @@ fas216_starttransfer(FAS216_Info *info, fasdmadir_t direction, int flush_fifo)
{
fasdmatype_t dmatype;
- fas216_checkmagic(info, "fas216_starttransfer");
+ fas216_checkmagic(info);
info->scsi.phase = (direction == DMA_OUT) ?
PHASE_DATAOUT : PHASE_DATAIN;
@@ -763,7 +767,7 @@ fas216_starttransfer(FAS216_Info *info, fasdmadir_t direction, int flush_fifo)
static void
fas216_stoptransfer(FAS216_Info *info)
{
- fas216_checkmagic(info, "fas216_stoptransfer");
+ fas216_checkmagic(info);
if (info->dma.transfer_type != fasdma_none &&
info->dma.transfer_type != fasdma_pio) {
@@ -797,7 +801,7 @@ fas216_stoptransfer(FAS216_Info *info)
static void
fas216_disconnect_intr(FAS216_Info *info)
{
- fas216_checkmagic(info, "fas216_disconnected_intr");
+ fas216_checkmagic(info);
#ifdef DEBUG_CONNECT
printk("scsi%d.%c: disconnect phase=%02X\n", info->host->host_no,
@@ -849,7 +853,7 @@ fas216_reselected_intr(FAS216_Info *info)
{
unsigned char target, identify_msg, ok;
- fas216_checkmagic(info, "fas216_reselected_intr");
+ fas216_checkmagic(info);
if ((info->scsi.phase == PHASE_SELECTION ||
info->scsi.phase == PHASE_SELSTEPS) && info->SCpnt) {
@@ -949,6 +953,7 @@ fas216_reselected_intr(FAS216_Info *info)
msgqueue_addmsg(&info->scsi.msgs, 1, ABORT);
info->scsi.phase = PHASE_MSGOUT_EXPECT;
}
+
outb(CMD_MSGACCEPTED, REG_CMD(info));
}
@@ -959,7 +964,7 @@ fas216_reselected_intr(FAS216_Info *info)
static void
fas216_finish_reconnect(FAS216_Info *info)
{
- fas216_checkmagic(info, "fas216_reconnect");
+ fas216_checkmagic(info);
#ifdef DEBUG_CONNECT
printk("Connected: %1X %1X %02X, reconnected: %1X %1X %02X\n",
@@ -1087,7 +1092,7 @@ static void fas216_message(FAS216_Info *info)
unsigned int msglen = 1, i;
int msgbyte = 0;
- fas216_checkmagic(info, "fas216_message");
+ fas216_checkmagic(info);
message[0] = inb(REG_FF(info));
@@ -1270,7 +1275,7 @@ static void fas216_send_command(FAS216_Info *info)
{
int i;
- fas216_checkmagic(info, "fas216_send_command");
+ fas216_checkmagic(info);
outb(CMD_NOP|CMD_WITHDMA, REG_CMD(info));
outb(CMD_FLUSHFIFO, REG_CMD(info));
@@ -1293,7 +1298,7 @@ static void fas216_send_messageout(FAS216_Info *info, int start)
{
unsigned int tot_msglen = msgqueue_msglength(&info->scsi.msgs);
- fas216_checkmagic(info, "fas216_send_messageout");
+ fas216_checkmagic(info);
outb(CMD_FLUSHFIFO, REG_CMD(info));
@@ -1326,7 +1331,7 @@ static void fas216_send_messageout(FAS216_Info *info, int start)
*/
static void fas216_busservice_intr(FAS216_Info *info, unsigned int stat, unsigned int ssr)
{
- fas216_checkmagic(info, "fas216_busservice_intr");
+ fas216_checkmagic(info);
#ifdef DEBUG_BUSSERVICE
printk("scsi%d.%c: bus service: stat=%02X ssr=%02X phase=%02X\n",
@@ -1520,7 +1525,7 @@ static void fas216_funcdone_intr(FAS216_Info *info, unsigned int stat, unsigned
{
int status, message;
- fas216_checkmagic(info, "fas216_funcdone_intr");
+ fas216_checkmagic(info);
#ifdef DEBUG_FUNCTIONDONE
printk("scsi%d.%c: function done: stat=%X ssr=%X phase=%02X\n",
@@ -1562,7 +1567,7 @@ void fas216_intr(struct Scsi_Host *instance)
FAS216_Info *info = (FAS216_Info *)instance->hostdata;
unsigned char isr, ssr, stat;
- fas216_checkmagic(info, "fas216_intr");
+ fas216_checkmagic(info);
stat = inb(REG_STAT(info));
ssr = inb(REG_IS(info));
@@ -1571,9 +1576,10 @@ void fas216_intr(struct Scsi_Host *instance)
add_debug_list(stat, ssr, isr, info->scsi.phase);
if (stat & STAT_INT) {
- if (isr & INST_BUSRESET)
+ if (isr & INST_BUSRESET) {
printk(KERN_DEBUG "scsi%d.H: bus reset detected\n", instance->host_no);
- else if (isr & INST_ILLEGALCMD) {
+ scsi_report_bus_reset(instance, 0);
+ } else if (isr & INST_ILLEGALCMD) {
printk(KERN_CRIT "scsi%d.H: illegal command given\n", instance->host_no);
fas216_dumpstate(info);
} else if (isr & INST_DISCONNECT)
@@ -1599,22 +1605,35 @@ void fas216_intr(struct Scsi_Host *instance)
*/
static void fas216_kick(FAS216_Info *info)
{
- Scsi_Cmnd *SCpnt;
- int tot_msglen, from_queue = 0;
+ Scsi_Cmnd *SCpnt = NULL;
+ int tot_msglen, from_queue = 0, disconnect_ok;
- fas216_checkmagic(info, "fas216_kick");
+ fas216_checkmagic(info);
- if (info->origSCpnt) {
- SCpnt = info->origSCpnt;
- info->origSCpnt = NULL;
- } else
- SCpnt = NULL;
+ /*
+ * Obtain the next command to process.
+ */
+ do {
+ if (info->reqSCpnt) {
+ SCpnt = info->reqSCpnt;
+ info->reqSCpnt = NULL;
+ break;
+ }
- /* retrieve next command */
- if (!SCpnt) {
- SCpnt = queue_remove_exclude(&info->queues.issue, info->busyluns);
- from_queue = 1;
- }
+ if (info->origSCpnt) {
+ SCpnt = info->origSCpnt;
+ info->origSCpnt = NULL;
+ break;
+ }
+
+ /* retrieve next command */
+ if (!SCpnt) {
+ SCpnt = queue_remove_exclude(&info->queues.issue,
+ info->busyluns);
+ from_queue = 1;
+ break;
+ }
+ } while (0);
if (!SCpnt) /* no command pending - just exit */
return;
@@ -1628,16 +1647,6 @@ static void fas216_kick(FAS216_Info *info)
}
/*
- * tagged queuing - allocate a new tag to this command
- */
- if (SCpnt->device->tagged_queue && SCpnt->cmnd[0] != REQUEST_SENSE) {
- SCpnt->device->current_tag += 1;
- if (SCpnt->device->current_tag == 0)
- SCpnt->device->current_tag = 1;
- SCpnt->tag = SCpnt->device->current_tag;
- }
-
- /*
* claim host busy
*/
info->scsi.phase = PHASE_SELECTION;
@@ -1653,6 +1662,9 @@ static void fas216_kick(FAS216_Info *info)
if (from_queue) {
#ifdef SCSI2_TAG
+ /*
+ * tagged queuing - allocate a new tag to this command
+ */
if (SCpnt->device->tagged_queue && SCpnt->cmnd[0] != REQUEST_SENSE &&
SCpnt->cmnd[0] != INQUIRY) {
SCpnt->device->current_tag += 1;
@@ -1681,41 +1693,48 @@ static void fas216_kick(FAS216_Info *info)
}
}
- /* build outgoing message bytes */
- msgqueue_flush(&info->scsi.msgs);
+ /*
+ * Don't allow request sense commands to disconnect.
+ */
+ disconnect_ok = SCpnt->cmnd[0] != REQUEST_SENSE &&
+ info->device[SCpnt->target].disconnect_ok;
- if (info->device[SCpnt->target].disconnect_ok)
- msgqueue_addmsg(&info->scsi.msgs, 1, IDENTIFY(1, SCpnt->lun));
- else
- msgqueue_addmsg(&info->scsi.msgs, 1, IDENTIFY(0, SCpnt->lun));
+ /*
+ * build outgoing message bytes
+ */
+ msgqueue_flush(&info->scsi.msgs);
+ msgqueue_addmsg(&info->scsi.msgs, 1, IDENTIFY(disconnect_ok, SCpnt->lun));
- /* add tag message if required */
+ /*
+ * add tag message if required
+ */
if (SCpnt->tag)
msgqueue_addmsg(&info->scsi.msgs, 2, SIMPLE_QUEUE_TAG, SCpnt->tag);
+ do {
#ifdef SCSI2_WIDE
- if (info->device[SCpnt->target].wide_state == neg_wait) {
- info->device[SCpnt->target].wide_state = neg_inprogress;
- msgqueue_addmsg(&info->scsi.msgs, 4,
- EXTENDED_MESSAGE, 2, EXTENDED_WDTR,
- info->ifcfg.wide_max_size);
- }
-#ifdef SCSI2_SYNC
- else
-#endif
+ if (info->device[SCpnt->target].wide_state == neg_wait) {
+ info->device[SCpnt->target].wide_state = neg_inprogress;
+ msgqueue_addmsg(&info->scsi.msgs, 4,
+ EXTENDED_MESSAGE, 2, EXTENDED_WDTR,
+ info->ifcfg.wide_max_size);
+ break;
+ }
#endif
#ifdef SCSI2_SYNC
- if ((info->device[SCpnt->target].sync_state == neg_wait ||
- info->device[SCpnt->target].sync_state == neg_complete) &&
- (SCpnt->cmnd[0] == REQUEST_SENSE ||
- SCpnt->cmnd[0] == INQUIRY)) {
- info->device[SCpnt->target].sync_state = neg_inprogress;
- msgqueue_addmsg(&info->scsi.msgs, 5,
- EXTENDED_MESSAGE, 3, EXTENDED_SDTR,
- 1000 / info->ifcfg.clockrate,
- info->ifcfg.sync_max_depth);
- }
+ if ((info->device[SCpnt->target].sync_state == neg_wait ||
+ info->device[SCpnt->target].sync_state == neg_complete) &&
+ (SCpnt->cmnd[0] == REQUEST_SENSE ||
+ SCpnt->cmnd[0] == INQUIRY)) {
+ info->device[SCpnt->target].sync_state = neg_inprogress;
+ msgqueue_addmsg(&info->scsi.msgs, 5,
+ EXTENDED_MESSAGE, 3, EXTENDED_SDTR,
+ 1000 / info->ifcfg.clockrate,
+ info->ifcfg.sync_max_depth);
+ break;
+ }
#endif
+ } while (0);
/* following what the ESP driver says */
outb(0, REG_STCL(info));
@@ -1780,18 +1799,156 @@ static void fas216_kick(FAS216_Info *info)
/* should now get either DISCONNECT or (FUNCTION DONE with BUS SERVICE) intr */
}
+/* Function: void fas216_rq_sns_done(info, SCpnt, result)
+ * Purpose : Finish processing automatic request sense command
+ * Params : info - interface that completed
+ * SCpnt - command that completed
+ * result - driver byte of result
+ */
+static void
+fas216_rq_sns_done(FAS216_Info *info, Scsi_Cmnd *SCpnt, unsigned int result)
+{
+#ifdef DEBUG_CONNECT
+ printk("scsi%d.%c: request sense complete, result=%04X%02X%02X\n",
+ info->host->host_no, '0' + SCpnt->target, result,
+ SCpnt->SCp.Message, SCpnt->SCp.Status);
+#endif
+
+ if (result != DID_OK || SCpnt->SCp.Status != GOOD)
+ /*
+ * Something went wrong. Make sure that we don't
+ * have valid data in the sense buffer that could
+ * confuse the higher levels.
+ */
+ memset(SCpnt->sense_buffer, 0, sizeof(SCpnt->sense_buffer));
+
+ /*
+ * Note that we don't set SCpnt->result, since that should
+ * reflect the status of the command that we were asked by
+ * the upper layers to process. This would have been set
+ * correctly by fas216_std_done.
+ */
+ SCpnt->scsi_done(SCpnt);
+}
+
+/* Function: void fas216_std_done(info, SCpnt, result)
+ * Purpose : Finish processing of standard command
+ * Params : info - interface that completed
+ * SCpnt - command that completed
+ * result - driver byte of result
+ */
+static void
+fas216_std_done(FAS216_Info *info, Scsi_Cmnd *SCpnt, unsigned int result)
+{
+ info->stats.fins += 1;
+
+ SCpnt->result = result << 16 | info->scsi.SCp.Message << 8 |
+ info->scsi.SCp.Status;
+
+#ifdef DEBUG_CONNECT
+ printk("scsi%d.%c: command complete, result=%08X, command=",
+ info->host->host_no, '0' + SCpnt->target, SCpnt->result);
+ print_command(SCpnt->cmnd);
+#endif
+
+ /*
+ * If the driver detected an error, or the command
+ * was request sense, then we're all done.
+ */
+ if (result != DID_OK || SCpnt->cmnd[0] == REQUEST_SENSE)
+ goto done;
+
+ /*
+ * If the command returned CHECK_CONDITION status,
+ * request the sense information.
+ */
+ if (info->scsi.SCp.Status == CHECK_CONDITION)
+ goto request_sense;
+
+ /*
+ * If the command did not complete with GOOD status,
+ * we are all done here.
+ */
+ if (info->scsi.SCp.Status != GOOD)
+ goto done;
+
+ /*
+ * We have successfully completed a command. Make sure that
+ * we do not have any buffers left to transfer. The world
+ * is not perfect, and we seem to occasionally hit this.
+ * It can be indicative of a buggy driver, target or the upper
+ * levels of the SCSI code.
+ */
+ if (info->scsi.SCp.ptr) {
+ switch (SCpnt->cmnd[0]) {
+ case INQUIRY:
+ case START_STOP:
+// case READ_CAPACITY:
+ case MODE_SENSE:
+ break;
+
+ default:
+ printk(KERN_ERR "scsi%d.%c: incomplete data transfer "
+ "detected: res=%08X ptr=%p len=%X command=",
+ info->host->host_no, '0' + SCpnt->target,
+ SCpnt->result, info->scsi.SCp.ptr,
+ info->scsi.SCp.this_residual);
+ print_command(SCpnt->cmnd);
+ }
+ }
+
+done: SCpnt->scsi_done(SCpnt);
+ return;
+
+request_sense:
+ memset(SCpnt->cmnd, 0, sizeof (SCpnt->cmnd));
+ SCpnt->cmnd[0] = REQUEST_SENSE;
+ SCpnt->cmnd[1] = SCpnt->lun << 5;
+ SCpnt->cmnd[4] = sizeof(SCpnt->sense_buffer);
+ SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
+ SCpnt->SCp.buffer = NULL;
+ SCpnt->SCp.buffers_residual = 0;
+ SCpnt->SCp.ptr = (char *)SCpnt->sense_buffer;
+ SCpnt->SCp.this_residual = sizeof(SCpnt->sense_buffer);
+ SCpnt->SCp.Message = 0;
+ SCpnt->SCp.Status = 0;
+ SCpnt->sc_data_direction = SCSI_DATA_READ;
+ SCpnt->use_sg = 0;
+ SCpnt->tag = 0;
+ SCpnt->host_scribble = (void *)fas216_rq_sns_done;
+
+ /*
+ * Place this command into the high priority "request
+ * sense" slot. This will be the very next command
+ * executed, unless a target connects to us.
+ */
+ if (info->reqSCpnt)
+ printk(KERN_WARNING "scsi%d.%c: loosing request command\n",
+ info->host->host_no, '0' + SCpnt->target);
+ info->reqSCpnt = SCpnt;
+}
+
/* Function: void fas216_done(FAS216_Info *info, unsigned int result)
- * Purpose : complete processing for command
+ * Purpose : complete processing for current command
* Params : info - interface that completed
* result - driver byte of result
*/
static void fas216_done(FAS216_Info *info, unsigned int result)
{
+ void (*fn)(FAS216_Info *, Scsi_Cmnd *, unsigned int);
Scsi_Cmnd *SCpnt;
- fas216_checkmagic(info, "fas216_done");
+ fas216_checkmagic(info);
+
+ if (!info->SCpnt)
+ goto no_command;
SCpnt = info->SCpnt;
+ info->SCpnt = NULL;
+ info->scsi.phase = PHASE_IDLE;
+
+ if (!SCpnt->scsi_done)
+ goto no_done;
if (info->scsi.aborting) {
printk("scsi%d.%c: uncaught abort - returning DID_ABORT\n",
@@ -1800,66 +1957,39 @@ static void fas216_done(FAS216_Info *info, unsigned int result)
info->scsi.aborting = 0;
}
- info->stats.fins += 1;
-
- if (SCpnt) {
- info->scsi.phase = PHASE_IDLE;
- info->SCpnt = NULL;
-
- SCpnt->result = result << 16 | info->scsi.SCp.Message << 8 |
- info->scsi.SCp.Status;
-
- /*
- * In theory, this should not happen, but just in case it does.
- */
- if (info->scsi.SCp.ptr &&
- info->scsi.SCp.this_residual &&
- result == DID_OK) {
- switch (SCpnt->cmnd[0]) {
- case INQUIRY:
- case START_STOP:
- case READ_CAPACITY:
- case TEST_UNIT_READY:
- case MODE_SENSE:
- case REQUEST_SENSE:
- break;
-
- default:
- switch (status_byte(SCpnt->result)) {
- case CHECK_CONDITION:
- case COMMAND_TERMINATED:
- case BUSY:
- case QUEUE_FULL:
- case RESERVATION_CONFLICT:
- break;
-
- default:
- printk(KERN_ERR "scsi%d.H: incomplete data transfer "
- "detected: res=%08X ptr=%p len=%X command=",
- info->host->host_no, SCpnt->result,
- info->scsi.SCp.ptr, info->scsi.SCp.this_residual);
- print_command(SCpnt->cmnd);
- }
- }
- }
-#ifdef DEBUG_CONNECT
- printk("scsi%d.%c: scsi command (%p) complete, result=%08X\n",
- info->host->host_no, fas216_target(info),
- SCpnt, SCpnt->result);
-#endif
-
- if (!SCpnt->scsi_done)
- panic("scsi%d.H: null scsi_done function in "
- "fas216_done", info->host->host_no);
+ /*
+ * Sanity check the completion - if we have zero bytes left
+ * to transfer, we should not have a valid pointer.
+ */
+ if (info->scsi.SCp.ptr && info->scsi.SCp.this_residual == 0) {
+ printk("scsi%d.%c: zero bytes left to transfer, but "
+ "buffer pointer still valid: ptr=%p len=%08x command=",
+ info->host->host_no, '0' + SCpnt->target,
+ info->scsi.SCp.ptr, info->scsi.SCp.this_residual);
+ info->scsi.SCp.ptr = NULL;
+ print_command(SCpnt->cmnd);
+ }
- clear_bit(SCpnt->target * 8 + SCpnt->lun, info->busyluns);
+ /*
+ * Clear down this command as completed. If we need to request
+ * the sense information, fas216_kick will re-assert the busy
+ * status.
+ */
+ clear_bit(SCpnt->target * 8 + SCpnt->lun, info->busyluns);
- SCpnt->scsi_done(SCpnt);
- } else
- panic("scsi%d.H: null command in fas216_done", info->host->host_no);
+ fn = (void (*)(FAS216_Info *, Scsi_Cmnd *, unsigned int))SCpnt->host_scribble;
+ fn(info, SCpnt, result);
if (info->scsi.irq != NO_IRQ)
fas216_kick(info);
+ return;
+
+no_command:
+ panic("scsi%d.H: null command in fas216_done",
+ info->host->host_no);
+no_done:
+ panic("scsi%d.H: null scsi_done function in fas216_done",
+ info->host->host_no);
}
/* Function: int fas216_queue_command(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
@@ -1867,13 +1997,14 @@ static void fas216_done(FAS216_Info *info, unsigned int result)
* Params : SCpnt - Command to queue
* done - done function to call once command is complete
* Returns : 0 - success, else error
+ * Notes : io_request_lock is held, interrupts are disabled.
*/
int fas216_queue_command(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
{
FAS216_Info *info = (FAS216_Info *)SCpnt->host->hostdata;
- unsigned long flags;
+ int result;
- fas216_checkmagic(info, "fas216_queue_command");
+ fas216_checkmagic(info);
#ifdef DEBUG_CONNECT
printk("scsi%d.%c: received queuable command (%p) %02X\n",
@@ -1882,7 +2013,7 @@ int fas216_queue_command(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
#endif
SCpnt->scsi_done = done;
- SCpnt->host_scribble = NULL;
+ SCpnt->host_scribble = (void *)fas216_std_done;
SCpnt->result = 0;
SCpnt->SCp.Message = 0;
SCpnt->SCp.Status = 0;
@@ -1896,10 +2027,16 @@ int fas216_queue_command(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
SCpnt->SCp.ptr = (char *) SCpnt->SCp.buffer->address;
SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length;
/*
- * Calculate correct buffer length
+ * Calculate correct buffer length. Some commands
+ * come in with the wrong request_bufflen.
*/
for (buf = 0; buf <= SCpnt->SCp.buffers_residual; buf++)
len += SCpnt->SCp.buffer[buf].length;
+
+ if (SCpnt->request_bufflen != len)
+ printk(KERN_WARNING "scsi%d.%c: bad request buffer "
+ "length %d, should be %ld\n", info->host->host_no,
+ '0' + SCpnt->target, SCpnt->request_bufflen, len);
SCpnt->request_bufflen = len;
} else {
SCpnt->SCp.buffer = NULL;
@@ -1908,22 +2045,36 @@ int fas216_queue_command(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
SCpnt->SCp.this_residual = SCpnt->request_bufflen;
}
+ /*
+ * If the upper SCSI layers pass a buffer, but zero length,
+ * we aren't interested in the buffer pointer.
+ */
+ if (SCpnt->SCp.this_residual == 0 && SCpnt->SCp.ptr) {
+#if 0
+ printk(KERN_WARNING "scsi%d.%c: zero length buffer passed for "
+ "command ", info->host->host_no, '0' + SCpnt->target);
+ print_command(SCpnt->cmnd);
+#endif
+ SCpnt->SCp.ptr = NULL;
+ }
+
info->stats.queues += 1;
SCpnt->tag = 0;
- /* add command into execute queue and let it complete under
+ /*
+ * Add command into execute queue and let it complete under
* whatever scheme we're using.
*/
- if (!queue_add_cmd_ordered(&info->queues.issue, SCpnt)) {
- SCpnt->result = DID_ERROR << 16;
- done(SCpnt);
- }
- save_flags_cli(flags);
- if (!info->SCpnt || info->scsi.disconnectable)
+ result = !queue_add_cmd_ordered(&info->queues.issue, SCpnt);
+
+ /*
+ * If we successfully added the command,
+ * kick the interface to get it moving.
+ */
+ if (result == 0 && (!info->SCpnt || info->scsi.disconnectable))
fas216_kick(info);
- restore_flags(flags);
- return 0;
+ return result;
}
/* Function: void fas216_internal_done(Scsi_Cmnd *SCpnt)
@@ -1934,7 +2085,7 @@ static void fas216_internal_done(Scsi_Cmnd *SCpnt)
{
FAS216_Info *info = (FAS216_Info *)SCpnt->host->hostdata;
- fas216_checkmagic(info, "fas216_internal_done");
+ fas216_checkmagic(info);
info->internal_done = 1;
}
@@ -1943,13 +2094,20 @@ static void fas216_internal_done(Scsi_Cmnd *SCpnt)
* Purpose : queue a command for adapter to process.
* Params : SCpnt - Command to queue
* Returns : scsi result code
+ * Notes : io_request_lock is held, interrupts are disabled.
*/
int fas216_command(Scsi_Cmnd *SCpnt)
{
FAS216_Info *info = (FAS216_Info *)SCpnt->host->hostdata;
- unsigned long flags;
- fas216_checkmagic(info, "fas216_command");
+ fas216_checkmagic(info);
+
+ /*
+ * We should only be using this if we don't have an interrupt.
+ * Provide some "incentive" to use the queueing code.
+ */
+ if (info->scsi.irq != NO_IRQ)
+ BUG();
info->internal_done = 0;
fas216_queue_command(SCpnt, fas216_internal_done);
@@ -1960,114 +2118,52 @@ int fas216_command(Scsi_Cmnd *SCpnt)
* However, we must re-enable interrupts, or else we'll be
* waiting forever.
*/
- save_flags(flags);
- sti();
+ spin_unlock_irq(&io_request_lock);
while (!info->internal_done) {
/*
- * If we don't have an IRQ, then we must
- * poll the card for it's interrupt, and
- * use that to call this driver's interrupt
- * routine. That way, we keep the command
- * progressing.
+ * If we don't have an IRQ, then we must poll the card for
+ * it's interrupt, and use that to call this driver's
+ * interrupt routine. That way, we keep the command
+ * progressing. Maybe we can add some inteligence here
+ * and go to sleep if we know that the device is going
+ * to be some time (eg, disconnected).
*/
- if (info->scsi.irq == NO_IRQ) {
- sti();
- while (!(inb(REG_STAT(info)) & STAT_INT));
- cli();
+ if (inb(REG_STAT(info)) & STAT_INT) {
+ spin_lock_irq(&io_request_lock);
fas216_intr(info->host);
+ spin_unlock_irq(&io_request_lock);
}
}
- restore_flags(flags);
+ spin_lock_irq(&io_request_lock);
return SCpnt->result;
}
-/* Prototype: void fas216_reportstatus(Scsi_Cmnd **SCpntp1,
- * Scsi_Cmnd **SCpntp2, int result, int no_report)
- * Purpose : pass a result to *SCpntp1, and check if *SCpntp1 = *SCpntp2
- * Params : SCpntp1 - pointer to command to return
- * SCpntp2 - pointer to command to check
- * result - result to pass back to mid-level done function
- * Returns : *SCpntp2 = NULL if *SCpntp1 is the same command
- * structure as *SCpntp2.
- */
-static void fas216_reportstatus(Scsi_Cmnd **SCpntp1, Scsi_Cmnd **SCpntp2,
- int result, int no_report)
-{
- Scsi_Cmnd *SCpnt = *SCpntp1;
-
- if (SCpnt) {
- *SCpntp1 = NULL;
-
- SCpnt->result = result;
- if (!no_report || SCpnt != *SCpntp2)
- SCpnt->scsi_done(SCpnt);
- }
-
- if (SCpnt == *SCpntp2)
- *SCpntp2 = NULL;
-}
-
-/* Function: int fas216_eh_abort(Scsi_Cmnd *SCpnt)
- * Purpose : abort this command
- * Params : SCpnt - command to abort
- * Returns : FAILED if unable to abort
- */
-int fas216_eh_abort(Scsi_Cmnd *SCpnt)
-{
- return FAILED;
-}
-
-/* Function: int fas216_eh_device_reset(Scsi_Cmnd *SCpnt)
- * Purpose : Reset the device associated with this command
- * Params : SCpnt - command specifing device to reset
- * Returns : FAILED if unable to reset
- */
-int fas216_eh_device_reset(Scsi_Cmnd *SCpnt)
-{
- return FAILED;
-}
-
-/* Function: int fas216_eh_bus_reset(Scsi_Cmnd *SCpnt)
- * Purpose : Reset the complete bus associated with this command
- * Params : SCpnt - command specifing bus to reset
- * Returns : FAILED if unable to reset
- */
-int fas216_eh_bus_reset(Scsi_Cmnd *SCpnt)
-{
- return FAILED;
-}
-
-/* Function: int fas216_eh_host_reset(Scsi_Cmnd *SCpnt)
- * Purpose : Reset the host associated with this command
- * Params : SCpnt - command specifing host to reset
- * Returns : FAILED if unable to reset
- */
-int fas216_eh_host_reset(Scsi_Cmnd *SCpnt)
-{
- return FAILED;
-}
-
-enum res_abort { res_not_running, res_success, res_success_clear, res_snooze };
+enum res_abort {
+ res_failed, /* unable to abort */
+ res_success, /* command on issue queue */
+ res_success_clear, /* command marked tgt/lun busy */
+ res_hw_abort /* command on disconnected dev */
+};
/*
* Prototype: enum res_abort fas216_do_abort(FAS216_Info *info, Scsi_Cmnd *SCpnt)
- * Purpose : abort a command on this host
+ * Purpose : decide how to abort a command
* Params : SCpnt - command to abort
* Returns : abort status
*/
static enum res_abort
fas216_do_abort(FAS216_Info *info, Scsi_Cmnd *SCpnt)
{
- enum res_abort res = res_not_running;
+ enum res_abort res = res_failed;
if (queue_removecmd(&info->queues.issue, SCpnt)) {
/*
* The command was on the issue queue, and has not been
* issued yet. We can remove the command from the queue,
- * and acknowledge the abort. Neither the devices nor the
+ * and acknowledge the abort. Neither the device nor the
* interface know about the command.
*/
printk("on issue queue ");
@@ -2075,54 +2171,32 @@ fas216_do_abort(FAS216_Info *info, Scsi_Cmnd *SCpnt)
res = res_success;
} else if (queue_removecmd(&info->queues.disconnected, SCpnt)) {
/*
- * The command was on the disconnected queue. Simply
- * acknowledge the abort condition, and when the target
- * reconnects, we will give it an ABORT message. The
- * target should then disconnect, and we will clear
- * the busylun bit.
+ * The command was on the disconnected queue. We must
+ * reconnect with the device if possible, and send it
+ * an abort message.
*/
printk("on disconnected queue ");
- res = res_success;
+ res = res_hw_abort;
} else if (info->SCpnt == SCpnt) {
- unsigned long flags;
-
printk("executing ");
- save_flags(flags);
- cli();
switch (info->scsi.phase) {
/*
* If the interface is idle, and the command is 'disconnectable',
- * then it is the same as on the disconnected queue. We simply
- * remove all traces of the command. When the target reconnects,
- * we will give it an ABORT message since the command could not
- * be found. When the target finally disconnects, we will clear
- * the busylun bit.
+ * then it is the same as on the disconnected queue.
*/
case PHASE_IDLE:
if (info->scsi.disconnectable) {
info->scsi.disconnectable = 0;
info->SCpnt = NULL;
- res = res_success;
+ res = res_hw_abort;
}
break;
- /*
- * If the command has connected and done nothing futher,
- * simply force a disconnect. We also need to clear the
- * busylun bit.
- */
- case PHASE_SELECTION:
-// info->SCpnt = NULL;
-// res = res_success_clear;
-// break;
-
default:
- res = res_snooze;
break;
}
- restore_flags(flags);
} else if (info->origSCpnt == SCpnt) {
/*
* The command will be executed next, but a command
@@ -2139,17 +2213,18 @@ fas216_do_abort(FAS216_Info *info, Scsi_Cmnd *SCpnt)
return res;
}
-/* Function: int fas216_abort(Scsi_Cmnd *SCpnt)
- * Purpose : abort a command if something horrible happens.
- * Params : SCpnt - Command that is believed to be causing a problem.
- * Returns : one of SCSI_ABORT_ macros.
+/* Function: int fas216_eh_abort(Scsi_Cmnd *SCpnt)
+ * Purpose : abort this command
+ * Params : SCpnt - command to abort
+ * Returns : FAILED if unable to abort
+ * Notes : io_request_lock is taken, and irqs are disabled
*/
-int fas216_abort(Scsi_Cmnd *SCpnt)
+int fas216_eh_abort(Scsi_Cmnd *SCpnt)
{
FAS216_Info *info = (FAS216_Info *)SCpnt->host->hostdata;
- int result = SCSI_ABORT_SNOOZE;
+ int result = FAILED;
- fas216_checkmagic(info, "fas216_abort");
+ fas216_checkmagic(info);
info->stats.aborts += 1;
@@ -2176,29 +2251,23 @@ int fas216_abort(Scsi_Cmnd *SCpnt)
*/
case res_success:
printk("success\n");
- SCpnt->result = DID_ABORT << 16;
- SCpnt->scsi_done(SCpnt);
- result = SCSI_ABORT_SUCCESS;
+ result = SUCCESS;
break;
/*
- * We did find the command, but unfortunately we couldn't
- * unhook it from ourselves. Wait some more, and if it
- * still doesn't complete, reset the interface.
+ * We need to reconnect to the target and send it an
+ * ABORT or ABORT_TAG message. We can only do this
+ * if the bus is free.
*/
- case res_snooze:
- printk("snooze\n");
- result = SCSI_ABORT_SNOOZE;
- break;
+ case res_hw_abort:
+
/*
- * The command could not be found (either because it completed,
- * or it got dropped.
+ * We are unable to abort the command for some reason.
*/
default:
- case res_not_running:
- result = SCSI_ABORT_SNOOZE;
- printk("not running\n");
+ case res_failed:
+ printk("failed\n");
break;
}
@@ -2214,7 +2283,7 @@ static void fas216_reset_state(FAS216_Info *info)
neg_t sync_state, wide_state;
int i;
- fas216_checkmagic(info, "fas216_reset_state");
+ fas216_checkmagic(info);
/*
* Clear out all stale info in our state structure
@@ -2257,6 +2326,80 @@ static void fas216_reset_state(FAS216_Info *info)
info->device[i].sof = 0;
info->device[i].wide_xfer = 0;
}
+
+ /*
+ * Drain all commands on disconnected queue
+ */
+ while (queue_remove(&info->queues.disconnected) != NULL);
+
+ /*
+ * Remove executing commands.
+ */
+ info->SCpnt = NULL;
+ info->reqSCpnt = NULL;
+ info->origSCpnt = NULL;
+}
+
+/* Function: int fas216_eh_device_reset(Scsi_Cmnd *SCpnt)
+ * Purpose : Reset the device associated with this command
+ * Params : SCpnt - command specifing device to reset
+ * Returns : FAILED if unable to reset
+ */
+int fas216_eh_device_reset(Scsi_Cmnd *SCpnt)
+{
+ FAS216_Info *info = (FAS216_Info *)SCpnt->host->hostdata;
+
+ printk("scsi%d.%c: "__FUNCTION__": called\n",
+ info->host->host_no, '0' + SCpnt->target);
+ return FAILED;
+}
+
+/* Function: int fas216_eh_bus_reset(Scsi_Cmnd *SCpnt)
+ * Purpose : Reset the bus associated with the command
+ * Params : SCpnt - command specifing bus to reset
+ * Returns : FAILED if unable to reset
+ * Notes : io_request_lock is taken, and irqs are disabled
+ */
+int fas216_eh_bus_reset(Scsi_Cmnd *SCpnt)
+{
+ FAS216_Info *info = (FAS216_Info *)SCpnt->host->hostdata;
+ int result = FAILED;
+
+ fas216_checkmagic(info);
+
+ info->stats.bus_resets += 1;
+
+ printk("scsi%d.%c: "__FUNCTION__": resetting bus\n",
+ info->host->host_no, '0' + SCpnt->target);
+
+ /*
+ * Attempt to stop all activity on this interface.
+ */
+ outb(info->scsi.cfg[2], REG_CNTL3(info));
+ fas216_stoptransfer(info);
+
+ /*
+ * Clear any pending interrupts
+ */
+ while (inb(REG_STAT(info)) & STAT_INT)
+ inb(REG_INST(info));
+
+ /*
+ * Reset the SCSI bus
+ */
+ outb(CMD_RESETSCSI, REG_CMD(info));
+ udelay(5);
+
+ /*
+ * Clear reset interrupt
+ */
+ if (inb(REG_STAT(info)) & STAT_INT &&
+ inb(REG_INST(info)) & INST_BUSRESET)
+ result = SUCCESS;
+
+ fas216_reset_state(info);
+
+ return result;
}
/* Function: void fas216_init_chip(FAS216_Info *info)
@@ -2265,8 +2408,6 @@ static void fas216_reset_state(FAS216_Info *info)
*/
static void fas216_init_chip(FAS216_Info *info)
{
- fas216_checkmagic(info, "fas216_init_chip");
-
outb(fas216_clockrate(info->ifcfg.clockrate), REG_CLKF(info));
outb(info->scsi.cfg[0], REG_CNTL1(info));
outb(info->scsi.cfg[1], REG_CNTL2(info));
@@ -2277,100 +2418,144 @@ static void fas216_init_chip(FAS216_Info *info)
outb(info->scsi.cfg[0], REG_CNTL1(info));
}
-/* Function: int fas216_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags)
- * Purpose : resets the adapter if something horrible happens.
- * Params : SCpnt - Command that is believed to be causing a problem.
- * reset_flags - flags indicating reset type that is believed
- * to be required.
- * Returns : one of SCSI_RESET_ macros, or'd with the SCSI_RESET_*_RESET
- * macros.
+/* Function: int fas216_eh_host_reset(Scsi_Cmnd *SCpnt)
+ * Purpose : Reset the host associated with this command
+ * Params : SCpnt - command specifing host to reset
+ * Returns : FAILED if unable to reset
+ * Notes : io_request_lock is taken, and irqs are disabled
*/
-int fas216_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags)
+int fas216_eh_host_reset(Scsi_Cmnd *SCpnt)
{
FAS216_Info *info = (FAS216_Info *)SCpnt->host->hostdata;
- Scsi_Cmnd *SCptr;
- int result = 0;
- int synchronous = reset_flags & SCSI_RESET_SYNCHRONOUS;
- fas216_checkmagic(info, "fas216_reset");
+ fas216_checkmagic(info);
+
+ printk("scsi%d.%c: "__FUNCTION__": resetting host\n",
+ info->host->host_no, '0' + SCpnt->target);
/*
- * Validate that command is actually on one of our queues if we're doing
- * an asynchronous reset
+ * Reset the SCSI chip.
*/
- if (reset_flags & SCSI_RESET_ASYNCHRONOUS &&
- SCpnt &&
- info->SCpnt != SCpnt &&
- info->origSCpnt != SCpnt &&
- !queue_cmdonqueue(&info->queues.disconnected, SCpnt) &&
- !queue_cmdonqueue(&info->queues.issue, SCpnt)) {
- printk("scsi%d: fas216_reset: asynchronous reset for unknown command\n",
- info->host->host_no);
- return SCSI_RESET_NOT_RUNNING;
- }
+ outb(CMD_RESETCHIP, REG_CMD(info));
- info->stats.resets += 1;
+ /*
+ * Ugly ugly ugly!
+ * We need to release the io_request_lock and enable
+ * IRQs if we sleep, but we must relock and disable
+ * IRQs after the sleep.
+ */
+ spin_unlock_irq(&io_request_lock);
+ scsi_sleep(5);
+ spin_lock_irq(&io_request_lock);
- print_debug_list();
- printk(KERN_WARNING "scsi%d: reset ", info->host->host_no);
- if (SCpnt)
- printk("for target %d ", SCpnt->target);
+ /*
+ * Release the SCSI reset.
+ */
+ outb(CMD_NOP, REG_CMD(info));
- printk("\n");
+ fas216_init_chip(info);
- outb(info->scsi.cfg[3], REG_CNTL3(info));
+ return SUCCESS;
+}
- fas216_stoptransfer(info);
+#define TYPE_UNKNOWN 0
+#define TYPE_NCR53C90 1
+#define TYPE_NCR53C90A 2
+#define TYPE_NCR53C9x 3
+#define TYPE_Am53CF94 4
+#define TYPE_EmFAS216 5
+#define TYPE_QLFAS216 6
+
+static char *chip_types[] = {
+ "unknown",
+ "NS NCR53C90",
+ "NS NCR53C90A",
+ "NS NCR53C9x",
+ "AMD Am53CF94",
+ "Emulex FAS216",
+ "QLogic FAS216"
+};
+
+static int fas216_detect_type(FAS216_Info *info)
+{
+ int family, rev;
- switch (reset_flags & (SCSI_RESET_SUGGEST_BUS_RESET | SCSI_RESET_SUGGEST_HOST_RESET)) {
- case SCSI_RESET_SUGGEST_BUS_RESET:
- outb(CMD_RESETSCSI, REG_CMD(info));
- outb(CMD_NOP, REG_CMD(info));
- result |= SCSI_RESET_BUS_RESET;
- break;
+ /*
+ * Reset the chip.
+ */
+ outb(CMD_RESETCHIP, REG_CMD(info));
+ udelay(50);
+ outb(CMD_NOP, REG_CMD(info));
- case SCSI_RESET_SUGGEST_HOST_RESET:
- outb(CMD_RESETCHIP, REG_CMD(info));
- outb(CMD_NOP, REG_CMD(info));
- result |= SCSI_RESET_HOST_RESET;
- break;
+ /*
+ * Check to see if control reg 2 is present.
+ */
+ outb(0, REG_CNTL3(info));
+ outb(CNTL2_S2FE, REG_CNTL2(info));
- default:
- outb(CMD_RESETCHIP, REG_CMD(info));
- outb(CMD_NOP, REG_CMD(info));
- outb(CMD_RESETSCSI, REG_CMD(info));
- result |= SCSI_RESET_HOST_RESET | SCSI_RESET_BUS_RESET;
- break;
- }
+ /*
+ * If we are unable to read back control reg 2
+ * correctly, it is not present, and we have a
+ * NCR53C90.
+ */
+ if ((inb(REG_CNTL2(info)) & (~0xe0)) != CNTL2_S2FE)
+ return TYPE_NCR53C90;
- udelay(300);
- fas216_reset_state(info);
- fas216_init_chip(info);
+ /*
+ * Now, check control register 3
+ */
+ outb(0, REG_CNTL2(info));
+ outb(0, REG_CNTL3(info));
+ outb(5, REG_CNTL3(info));
/*
- * Signal all commands in progress have been reset
+ * If we are unable to read the register back
+ * correctly, we have a NCR53C90A
*/
- fas216_reportstatus(&info->SCpnt, &SCpnt, DID_RESET << 16, synchronous);
+ if (inb(REG_CNTL3(info)) != 5)
+ return TYPE_NCR53C90A;
- while ((SCptr = queue_remove(&info->queues.disconnected)) != NULL)
- fas216_reportstatus(&SCptr, &SCpnt, DID_RESET << 16, synchronous);
+ /*
+ * Now read the ID from the chip.
+ */
+ outb(0, REG_CNTL3(info));
- if (SCpnt) {
- /*
- * Command not found on disconnected queue, nor currently
- * executing command - check pending commands
- */
- if (info->origSCpnt == SCpnt)
- info->origSCpnt = NULL;
+ outb(CNTL3_ADIDCHK, REG_CNTL3(info));
+ outb(0, REG_CNTL3(info));
- queue_removecmd(&info->queues.issue, SCpnt);
+ outb(CMD_RESETCHIP, REG_CMD(info));
+ udelay(5);
+ outb(CMD_WITHDMA | CMD_NOP, REG_CMD(info));
- SCpnt->result = DID_RESET << 16;
- if (!synchronous)
- SCpnt->scsi_done(SCpnt);
- }
+ outb(CNTL2_ENF, REG_CNTL2(info));
+ outb(CMD_RESETCHIP, REG_CMD(info));
+ udelay(5);
+ outb(CMD_NOP, REG_CMD(info));
+
+ rev = inb(REG1_ID(info));
+ family = rev >> 3;
+ rev &= 7;
+
+ switch (family) {
+ case 0x01:
+ if (rev == 4)
+ return TYPE_Am53CF94;
+ break;
+
+ case 0x02:
+ switch (rev) {
+ case 2:
+ return TYPE_EmFAS216;
+ case 3:
+ return TYPE_QLFAS216;
+ }
+ break;
- return result | SCSI_RESET_SUCCESS;
+ default:
+ break;
+ }
+ printk("family %x rev %x\n", family, rev);
+ return TYPE_NCR53C9x;
}
/* Function: int fas216_init(struct Scsi_Host *instance)
@@ -2381,19 +2566,14 @@ int fas216_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags)
int fas216_init(struct Scsi_Host *instance)
{
FAS216_Info *info = (FAS216_Info *)instance->hostdata;
- unsigned long flags;
- int target_jiffies;
+ int type;
info->magic_start = MAGIC;
- info->magic_end = MAGIC;
-
- info->host = instance;
+ info->magic_end = MAGIC;
+ info->host = instance;
info->scsi.cfg[0] = instance->this_id;
info->scsi.cfg[1] = CNTL2_ENF | CNTL2_S2FE;
info->scsi.cfg[2] = info->ifcfg.cntl3 | CNTL3_ADIDCHK | CNTL3_G2CB;
- info->scsi.type = "unknown";
- info->SCpnt = NULL;
- fas216_reset_state(info);
memset(&info->stats, 0, sizeof(info->stats));
@@ -2407,64 +2587,36 @@ int fas216_init(struct Scsi_Host *instance)
return 1;
}
- outb(CMD_RESETCHIP, REG_CMD(info));
-
- outb(0, REG_CNTL3(info));
- outb(CNTL2_S2FE, REG_CNTL2(info));
-
- if ((inb(REG_CNTL2(info)) & (~0xe0)) != CNTL2_S2FE) {
- info->scsi.type = "NCR53C90";
- } else {
- outb(0, REG_CNTL2(info));
- outb(0, REG_CNTL3(info));
- outb(5, REG_CNTL3(info));
- if (inb(REG_CNTL3(info)) != 5) {
- info->scsi.type = "NCR53C90A";
- } else {
- outb(0, REG_CNTL3(info));
- info->scsi.type = "NCR53C9x";
- }
- }
-
-
- outb(CNTL3_ADIDCHK, REG_CNTL3(info));
- outb(0, REG_CNTL3(info));
-
- outb(CMD_RESETCHIP, REG_CMD(info));
- outb(CMD_WITHDMA | CMD_NOP, REG_CMD(info));
- outb(CNTL2_ENF, REG_CNTL2(info));
- outb(CMD_RESETCHIP, REG_CMD(info));
- switch (inb(REG1_ID(info))) {
- case 12:
- info->scsi.type = "Am53CF94";
- break;
- default:
- break;
- }
+ fas216_reset_state(info);
+ type = fas216_detect_type(info);
+ info->scsi.type = chip_types[type];
udelay(300);
- /* now for the real initialisation */
+
+ /*
+ * Initialise the chip correctly.
+ */
fas216_init_chip(info);
+ /*
+ * Reset the SCSI bus. We don't want to see
+ * the resulting reset interrupt, so mask it
+ * out.
+ */
outb(info->scsi.cfg[0] | CNTL1_DISR, REG_CNTL1(info));
outb(CMD_RESETSCSI, REG_CMD(info));
- /* scsi standard says 250ms */
- target_jiffies = jiffies + (25 * HZ) / 100;
- save_flags(flags);
- sti();
-
- while (time_before(jiffies, target_jiffies)) barrier();
-
- restore_flags(flags);
+ /*
+ * scsi standard says wait 250ms
+ */
+ spin_unlock_irq(&io_request_lock);
+ scsi_sleep(5);
+ spin_lock_irq(&io_request_lock);
outb(info->scsi.cfg[0], REG_CNTL1(info));
inb(REG_INST(info));
- /* now for the real initialisation */
- fas216_init_chip(info);
-
- fas216_checkmagic(info, "fas216_init");
+ fas216_checkmagic(info);
return 0;
}
@@ -2479,7 +2631,7 @@ int fas216_release(struct Scsi_Host *instance)
{
FAS216_Info *info = (FAS216_Info *)instance->hostdata;
- fas216_checkmagic(info, "fas216_release");
+ fas216_checkmagic(info);
outb(CMD_RESETCHIP, REG_CMD(info));
queue_free(&info->queues.disconnected);
@@ -2488,19 +2640,67 @@ int fas216_release(struct Scsi_Host *instance)
return 0;
}
+/*
+ * Function: int fas216_info(FAS216_Info *info, char *buffer)
+ * Purpose : generate a string containing information about this
+ * host.
+ * Params : info - FAS216 host information
+ * buffer - string buffer to build string
+ * Returns : size of built string
+ */
+int fas216_info(FAS216_Info *info, char *buffer)
+{
+ char *p = buffer;
+
+ p += sprintf(p, "(%s) at port 0x%08lX ",
+ info->scsi.type, info->host->io_port);
+
+ if (info->host->irq != NO_IRQ)
+ p += sprintf(p, "irq %d ", info->host->irq);
+ else
+ p += sprintf(p, "no irq ");
+
+ if (info->host->dma_channel != NO_DMA)
+ p += sprintf(p, "dma %d ", info->host->dma_channel);
+ else
+ p += sprintf(p, "no dma ");
+
+ return p - buffer;
+}
+
+int fas216_print_host(FAS216_Info *info, char *buffer)
+{
+
+ return sprintf(buffer,
+ "\n"
+ "Chip : %s\n"
+ " Address: 0x%08lX\n"
+ " IRQ : %d\n"
+ " DMA : %d\n",
+ info->scsi.type, info->host->io_port,
+ info->host->irq, info->host->dma_channel);
+}
+
int fas216_print_stats(FAS216_Info *info, char *buffer)
{
return sprintf(buffer,
- "Queued commands: %-10u Issued commands: %-10u\n"
- "Done commands : %-10u Reads : %-10u\n"
- "Writes : %-10u Others : %-10u\n"
- "Disconnects : %-10u Aborts : %-10u\n"
- "Resets : %-10u\n",
+ "\n"
+ "Command Statistics:\n"
+ " Queued : %u\n"
+ " Issued : %u\n"
+ " Completed : %u\n"
+ " Reads : %u\n"
+ " Writes : %u\n"
+ " Others : %u\n"
+ " Disconnects: %u\n"
+ " Aborts : %u\n"
+ " Bus resets : %u\n"
+ " Host resets: %u\n",
info->stats.queues, info->stats.removes,
info->stats.fins, info->stats.reads,
info->stats.writes, info->stats.miscs,
info->stats.disconnects, info->stats.aborts,
- info->stats.resets);
+ info->stats.bus_resets, info->stats.host_resets);
}
int fas216_print_device(FAS216_Info *info, Scsi_Device *scd, char *buffer)
@@ -2531,9 +2731,8 @@ int fas216_print_device(FAS216_Info *info, Scsi_Device *scd, char *buffer)
return p - buffer;
}
+EXPORT_SYMBOL(fas216_info);
EXPORT_SYMBOL(fas216_init);
-EXPORT_SYMBOL(fas216_abort);
-EXPORT_SYMBOL(fas216_reset);
EXPORT_SYMBOL(fas216_queue_command);
EXPORT_SYMBOL(fas216_command);
EXPORT_SYMBOL(fas216_intr);
@@ -2542,6 +2741,7 @@ EXPORT_SYMBOL(fas216_eh_abort);
EXPORT_SYMBOL(fas216_eh_device_reset);
EXPORT_SYMBOL(fas216_eh_bus_reset);
EXPORT_SYMBOL(fas216_eh_host_reset);
+EXPORT_SYMBOL(fas216_print_host);
EXPORT_SYMBOL(fas216_print_stats);
EXPORT_SYMBOL(fas216_print_device);
diff --git a/drivers/acorn/scsi/fas216.h b/drivers/acorn/scsi/fas216.h
index dede53ba9..4381888fd 100644
--- a/drivers/acorn/scsi/fas216.h
+++ b/drivers/acorn/scsi/fas216.h
@@ -1,11 +1,7 @@
/*
* FAS216 generic driver
*
- * Copyright (C) 1997-1998 Russell King
- *
- * NOTE! This file should be viewed using a console with
- * >100 character width (since it uses 8-space tabs)
- * (it used to fit in 80-columns with 4 space)
+ * Copyright (C) 1997-2000 Russell King
*/
#ifndef FAS216_H
#define FAS216_H
@@ -215,6 +211,7 @@ typedef struct {
struct Scsi_Host *host; /* host */
Scsi_Cmnd *SCpnt; /* currently processing command */
Scsi_Cmnd *origSCpnt; /* original connecting command */
+ Scsi_Cmnd *reqSCpnt; /* request sense command */
/* driver information */
struct {
@@ -254,7 +251,8 @@ typedef struct {
unsigned int miscs;
unsigned int disconnects;
unsigned int aborts;
- unsigned int resets;
+ unsigned int bus_resets;
+ unsigned int host_resets;
} stats;
/* configuration information */
@@ -350,6 +348,8 @@ extern void fas216_intr (struct Scsi_Host *instance);
*/
extern int fas216_release (struct Scsi_Host *instance);
+extern int fas216_info(FAS216_Info *info, char *buffer);
+extern int fas216_print_host(FAS216_Info *info, char *buffer);
extern int fas216_print_stats(FAS216_Info *info, char *buffer);
extern int fas216_print_device(FAS216_Info *info, Scsi_Device *scd, char *buffer);
diff --git a/drivers/acorn/scsi/msgqueue.h b/drivers/acorn/scsi/msgqueue.h
index 8016dcf4e..25fa2796f 100644
--- a/drivers/acorn/scsi/msgqueue.h
+++ b/drivers/acorn/scsi/msgqueue.h
@@ -1,7 +1,7 @@
/*
* msgqueue.h: message queue handling
*
- * (c) 1997 Russell King
+ * Copyright (C) 1997 Russell King
*/
#ifndef MSGQUEUE_H
#define MSGQUEUE_H
diff --git a/drivers/acorn/scsi/powertec.c b/drivers/acorn/scsi/powertec.c
index 59d83dc1a..cd07f7da0 100644
--- a/drivers/acorn/scsi/powertec.c
+++ b/drivers/acorn/scsi/powertec.c
@@ -1,7 +1,7 @@
/*
* linux/arch/arm/drivers/scsi/powertec.c
*
- * Copyright (C) 1997-1998 Russell King
+ * Copyright (C) 1997-2000 Russell King
*
* This driver is based on experimentation. Hence, it may have made
* assumptions about the particular card that I have available, and
@@ -13,6 +13,7 @@
* 15-04-1998 RMK Only do PIO if FAS216 will allow it.
* 02-05-1998 RMK Moved DMA sg list into per-interface structure.
* 27-06-1998 RMK Changed asm/delay.h to linux/delay.h
+ * 02-04-2000 RMK Updated for new error handling code.
*/
#include <linux/module.h>
@@ -67,7 +68,7 @@
*/
#define VER_MAJOR 0
#define VER_MINOR 0
-#define VER_PATCH 2
+#define VER_PATCH 5
MODULE_AUTHOR("Russell King");
MODULE_DESCRIPTION("Powertec SCSI driver");
@@ -345,25 +346,11 @@ const char *powertecscsi_info(struct Scsi_Host *host)
static char string[100], *p;
p = string;
- p += sprintf(string, "%s at port %lX ",
- host->hostt->name, host->io_port);
-
- if (host->irq != NO_IRQ)
- p += sprintf(p, "irq %d ", host->irq);
- else
- p += sprintf(p, "NO IRQ ");
-
- if (host->dma_channel != NO_DMA)
- p += sprintf(p, "dma %d ", host->dma_channel);
- else
- p += sprintf(p, "NO DMA ");
-
- p += sprintf(p, "v%d.%d.%d scsi %s",
+ p += sprintf(p, "%s ", host->hostt->name);
+ p += fas216_info(&info->info, p);
+ p += sprintf(p, "v%d.%d.%d terminators o%s",
VER_MAJOR, VER_MINOR, VER_PATCH,
- info->info.scsi.type);
-
- p += sprintf(p, " terminators %s",
- info->control.terms ? "on" : "off");
+ info->control.terms ? "n" : "ff");
return string;
}
@@ -403,13 +390,13 @@ powertecscsi_set_proc_info(struct Scsi_Host *host, char *buffer, int length)
* int length, int host_no, int inout)
* Purpose : Return information about the driver to a user process accessing
* the /proc filesystem.
- * Params : buffer - a buffer to write information to
- * start - a pointer into this buffer set by this routine to the start
- * of the required information.
- * offset - offset into information that we have read upto.
- * length - length of buffer
+ * Params : buffer - a buffer to write information to
+ * start - a pointer into this buffer set by this routine to the start
+ * of the required information.
+ * offset - offset into information that we have read upto.
+ * length - length of buffer
* host_no - host number to return information for
- * inout - 0 for reading, 1 for writing.
+ * inout - 0 for reading, 1 for writing.
* Returns : length of data written to buffer.
*/
int powertecscsi_proc_info(char *buffer, char **start, off_t offset,
@@ -437,16 +424,14 @@ int powertecscsi_proc_info(char *buffer, char **start, off_t offset,
pos = sprintf(buffer,
"PowerTec SCSI driver version %d.%d.%d\n",
VER_MAJOR, VER_MINOR, VER_PATCH);
- pos += sprintf(buffer + pos,
- "Address: %08lX IRQ : %d DMA : %d\n"
- "FAS : %-10s TERM: %-3s\n\n"
- "Statistics:\n",
- host->io_port, host->irq, host->dma_channel,
- info->info.scsi.type, info->control.terms ? "on" : "off");
+
+ pos += fas216_print_host(&info->info, buffer + pos);
+ pos += sprintf(buffer + pos, "Term : o%s\n",
+ info->control.terms ? "n" : "ff");
pos += fas216_print_stats(&info->info, buffer + pos);
- pos += sprintf (buffer+pos, "\nAttached devices:\n");
+ pos += sprintf(buffer+pos, "\nAttached devices:\n");
for (scd = host->host_queue; scd; scd = scd->next) {
pos += fas216_print_device(&info->info, scd, buffer + pos);
diff --git a/drivers/acorn/scsi/powertec.h b/drivers/acorn/scsi/powertec.h
index bf9a8afc8..4b0387b89 100644
--- a/drivers/acorn/scsi/powertec.h
+++ b/drivers/acorn/scsi/powertec.h
@@ -1,7 +1,7 @@
/*
* PowerTec SCSI driver
*
- * Copyright (C) 1997-1998 Russell King
+ * Copyright (C) 1997-2000 Russell King
*/
#ifndef POWERTECSCSI_H
#define POWERTECSCSI_H
@@ -38,28 +38,25 @@ extern int powertecscsi_proc_info (char *buffer, char **start, off_t offset,
#include "fas216.h"
-#define POWERTECSCSI { \
-proc_info: powertecscsi_proc_info, \
-name: "PowerTec SCSI", \
-detect: powertecscsi_detect, /* detect */ \
-release: powertecscsi_release, /* release */ \
-info: powertecscsi_info, /* info */ \
-command: fas216_command, /* command */ \
-queuecommand: fas216_queue_command, /* queuecommand */ \
-abort: fas216_abort, /* abort */ \
-reset: fas216_reset, /* reset */ \
-bios_param: scsicam_bios_param, /* biosparam */ \
-can_queue: CAN_QUEUE, /* can queue */ \
-this_id: SCSI_ID, /* scsi host id */ \
-sg_tablesize: SG_ALL, /* sg_tablesize */ \
-cmd_per_lun: CMD_PER_LUN, /* cmd per lun */ \
-use_clustering: ENABLE_CLUSTERING, \
-eh_strategy_handler: NULL, \
-eh_host_reset_handler: fas216_eh_host_reset, \
-eh_bus_reset_handler: fas216_eh_bus_reset, \
-eh_device_reset_handler: fas216_eh_device_reset, \
-eh_abort_handler: fas216_eh_abort, \
-use_new_eh_code: 0 \
+#define POWERTECSCSI { \
+proc_info: powertecscsi_proc_info, \
+name: "PowerTec SCSI", \
+detect: powertecscsi_detect, \
+release: powertecscsi_release, \
+info: powertecscsi_info, \
+bios_param: scsicam_bios_param, \
+can_queue: CAN_QUEUE, \
+this_id: SCSI_ID, \
+sg_tablesize: SG_ALL, \
+cmd_per_lun: CMD_PER_LUN, \
+use_clustering: ENABLE_CLUSTERING, \
+command: fas216_command, \
+queuecommand: fas216_queue_command, \
+eh_host_reset_handler: fas216_eh_host_reset, \
+eh_bus_reset_handler: fas216_eh_bus_reset, \
+eh_device_reset_handler: fas216_eh_device_reset, \
+eh_abort_handler: fas216_eh_abort, \
+use_new_eh_code: 1 \
}
#ifndef HOSTS_C
diff --git a/drivers/acorn/scsi/queue.h b/drivers/acorn/scsi/queue.h
index f39816ccb..961a3f268 100644
--- a/drivers/acorn/scsi/queue.h
+++ b/drivers/acorn/scsi/queue.h
@@ -1,7 +1,7 @@
/*
* queue.h: queue handling
*
- * (c) 1997 Russell King
+ * Copyright (C) 1997 Russell King
*/
#ifndef QUEUE_H
#define QUEUE_H