diff --git a/[refs] b/[refs]
index 57d5e41b2b19..f90688669610 100644
--- a/[refs]
+++ b/[refs]
@@ -1,2 +1,2 @@
---
-refs/heads/master: 0b61a2ba5dfd1620731e717d686e6ade657fd975
+refs/heads/master: 7fce084a0b3e2bb8caef919f8f36065953655bb5
diff --git a/trunk/Documentation/DocBook/scsi.tmpl b/trunk/Documentation/DocBook/scsi.tmpl
index 10a150ae2a7e..f299ab182bbe 100644
--- a/trunk/Documentation/DocBook/scsi.tmpl
+++ b/trunk/Documentation/DocBook/scsi.tmpl
@@ -12,7 +12,7 @@
Bottomley
- James.Bottomley@hansenpartnership.com
+ James.Bottomley@steeleye.com
diff --git a/trunk/Documentation/scsi/ChangeLog.arcmsr b/trunk/Documentation/scsi/ChangeLog.arcmsr
index de2bcacfa870..cd8403a33ee6 100644
--- a/trunk/Documentation/scsi/ChangeLog.arcmsr
+++ b/trunk/Documentation/scsi/ChangeLog.arcmsr
@@ -68,45 +68,4 @@
** 2. modify the arcmsr_pci_slot_reset function
** 3. modify the arcmsr_pci_ers_disconnect_forepart function
** 4. modify the arcmsr_pci_ers_need_reset_forepart function
-** 1.20.00.15 09/27/2007 Erich Chen & Nick Cheng
-** 1. add arcmsr_enable_eoi_mode() on adapter Type B
-** 2. add readl(reg->iop2drv_doorbell_reg) in arcmsr_handle_hbb_isr()
-** in case of the doorbell interrupt clearance is cached
-** 1.20.00.15 10/01/2007 Erich Chen & Nick Cheng
-** 1. modify acb->devstate[i][j]
-** as ARECA_RAID_GOOD instead of
-** ARECA_RAID_GONE in arcmsr_alloc_ccb_pool
-** 1.20.00.15 11/06/2007 Erich Chen & Nick Cheng
-** 1. add conditional declaration for
-** arcmsr_pci_error_detected() and
-** arcmsr_pci_slot_reset
-** 1.20.00.15 11/23/2007 Erich Chen & Nick Cheng
-** 1.check if the sg list member number
-** exceeds arcmsr default limit in arcmsr_build_ccb()
-** 2.change the returned value type of arcmsr_build_ccb()
-** from "void" to "int"
-** 3.add the conditional check if arcmsr_build_ccb()
-** returns FAILED
-** 1.20.00.15 12/04/2007 Erich Chen & Nick Cheng
-** 1. modify arcmsr_drain_donequeue() to ignore unknown
-** command and let kernel process command timeout.
-** This could handle IO request violating max. segments
-** while Linux XFS over DM-CRYPT.
-** Thanks to Milan Broz's comments
-** 1.20.00.15 12/24/2007 Erich Chen & Nick Cheng
-** 1.fix the portability problems
-** 2.fix type B where we should _not_ iounmap() acb->pmu;
-** it's not ioremapped.
-** 3.add return -ENOMEM if ioremap() fails
-** 4.transfer IS_SG64_ADDR w/ cpu_to_le32()
-** in arcmsr_build_ccb
-** 5. modify acb->devstate[i][j] as ARECA_RAID_GONE instead of
-** ARECA_RAID_GOOD in arcmsr_alloc_ccb_pool()
-** 6.fix arcmsr_cdb->Context as (unsigned long)arcmsr_cdb
-** 7.add the checking state of
-** (outbound_intstatus & ARCMSR_MU_OUTBOUND_HANDLE_INT) == 0
-** in arcmsr_handle_hba_isr
-** 8.replace pci_alloc_consistent()/pci_free_consistent() with kmalloc()/kfree() in arcmsr_iop_message_xfer()
-** 9. fix the release of dma memory for type B in arcmsr_free_ccb_pool()
-** 10.fix the arcmsr_polling_hbb_ccbdone()
**************************************************************************
diff --git a/trunk/Documentation/scsi/scsi_mid_low_api.txt b/trunk/Documentation/scsi/scsi_mid_low_api.txt
index a6d5354639b2..6f70f2b9327e 100644
--- a/trunk/Documentation/scsi/scsi_mid_low_api.txt
+++ b/trunk/Documentation/scsi/scsi_mid_low_api.txt
@@ -1407,7 +1407,7 @@ Credits
=======
The following people have contributed to this document:
Mike Anderson
- James Bottomley
+ James Bottomley
Patrick Mansfield
Christoph Hellwig
Doug Ledford
diff --git a/trunk/Documentation/vm/slabinfo.c b/trunk/Documentation/vm/slabinfo.c
index 7123fee708ca..488c1f31b992 100644
--- a/trunk/Documentation/vm/slabinfo.c
+++ b/trunk/Documentation/vm/slabinfo.c
@@ -32,13 +32,6 @@ struct slabinfo {
int sanity_checks, slab_size, store_user, trace;
int order, poison, reclaim_account, red_zone;
unsigned long partial, objects, slabs;
- unsigned long alloc_fastpath, alloc_slowpath;
- unsigned long free_fastpath, free_slowpath;
- unsigned long free_frozen, free_add_partial, free_remove_partial;
- unsigned long alloc_from_partial, alloc_slab, free_slab, alloc_refill;
- unsigned long cpuslab_flush, deactivate_full, deactivate_empty;
- unsigned long deactivate_to_head, deactivate_to_tail;
- unsigned long deactivate_remote_frees;
int numa[MAX_NODES];
int numa_partial[MAX_NODES];
} slabinfo[MAX_SLABS];
@@ -71,10 +64,8 @@ int show_inverted = 0;
int show_single_ref = 0;
int show_totals = 0;
int sort_size = 0;
-int sort_active = 0;
int set_debug = 0;
int show_ops = 0;
-int show_activity = 0;
/* Debug options */
int sanity = 0;
@@ -102,10 +93,8 @@ void usage(void)
printf("slabinfo 5/7/2007. (c) 2007 sgi. clameter@sgi.com\n\n"
"slabinfo [-ahnpvtsz] [-d debugopts] [slab-regexp]\n"
"-a|--aliases Show aliases\n"
- "-A|--activity Most active slabs first\n"
"-d|--debug= Set/Clear Debug options\n"
- "-D|--display-active Switch line format to activity\n"
- "-e|--empty Show empty slabs\n"
+ "-e|--empty Show empty slabs\n"
"-f|--first-alias Show first alias\n"
"-h|--help Show usage information\n"
"-i|--inverted Inverted list\n"
@@ -292,11 +281,8 @@ int line = 0;
void first_line(void)
{
- if (show_activity)
- printf("Name Objects Alloc Free %%Fast\n");
- else
- printf("Name Objects Objsize Space "
- "Slabs/Part/Cpu O/S O %%Fr %%Ef Flg\n");
+ printf("Name Objects Objsize Space "
+ "Slabs/Part/Cpu O/S O %%Fr %%Ef Flg\n");
}
/*
@@ -323,12 +309,6 @@ unsigned long slab_size(struct slabinfo *s)
return s->slabs * (page_size << s->order);
}
-unsigned long slab_activity(struct slabinfo *s)
-{
- return s->alloc_fastpath + s->free_fastpath +
- s->alloc_slowpath + s->free_slowpath;
-}
-
void slab_numa(struct slabinfo *s, int mode)
{
int node;
@@ -412,71 +392,6 @@ const char *onoff(int x)
return "Off";
}
-void slab_stats(struct slabinfo *s)
-{
- unsigned long total_alloc;
- unsigned long total_free;
- unsigned long total;
-
- if (!s->alloc_slab)
- return;
-
- total_alloc = s->alloc_fastpath + s->alloc_slowpath;
- total_free = s->free_fastpath + s->free_slowpath;
-
- if (!total_alloc)
- return;
-
- printf("\n");
- printf("Slab Perf Counter Alloc Free %%Al %%Fr\n");
- printf("--------------------------------------------------\n");
- printf("Fastpath %8lu %8lu %3lu %3lu\n",
- s->alloc_fastpath, s->free_fastpath,
- s->alloc_fastpath * 100 / total_alloc,
- s->free_fastpath * 100 / total_free);
- printf("Slowpath %8lu %8lu %3lu %3lu\n",
- total_alloc - s->alloc_fastpath, s->free_slowpath,
- (total_alloc - s->alloc_fastpath) * 100 / total_alloc,
- s->free_slowpath * 100 / total_free);
- printf("Page Alloc %8lu %8lu %3lu %3lu\n",
- s->alloc_slab, s->free_slab,
- s->alloc_slab * 100 / total_alloc,
- s->free_slab * 100 / total_free);
- printf("Add partial %8lu %8lu %3lu %3lu\n",
- s->deactivate_to_head + s->deactivate_to_tail,
- s->free_add_partial,
- (s->deactivate_to_head + s->deactivate_to_tail) * 100 / total_alloc,
- s->free_add_partial * 100 / total_free);
- printf("Remove partial %8lu %8lu %3lu %3lu\n",
- s->alloc_from_partial, s->free_remove_partial,
- s->alloc_from_partial * 100 / total_alloc,
- s->free_remove_partial * 100 / total_free);
-
- printf("RemoteObj/SlabFrozen %8lu %8lu %3lu %3lu\n",
- s->deactivate_remote_frees, s->free_frozen,
- s->deactivate_remote_frees * 100 / total_alloc,
- s->free_frozen * 100 / total_free);
-
- printf("Total %8lu %8lu\n\n", total_alloc, total_free);
-
- if (s->cpuslab_flush)
- printf("Flushes %8lu\n", s->cpuslab_flush);
-
- if (s->alloc_refill)
- printf("Refill %8lu\n", s->alloc_refill);
-
- total = s->deactivate_full + s->deactivate_empty +
- s->deactivate_to_head + s->deactivate_to_tail;
-
- if (total)
- printf("Deactivate Full=%lu(%lu%%) Empty=%lu(%lu%%) "
- "ToHead=%lu(%lu%%) ToTail=%lu(%lu%%)\n",
- s->deactivate_full, (s->deactivate_full * 100) / total,
- s->deactivate_empty, (s->deactivate_empty * 100) / total,
- s->deactivate_to_head, (s->deactivate_to_head * 100) / total,
- s->deactivate_to_tail, (s->deactivate_to_tail * 100) / total);
-}
-
void report(struct slabinfo *s)
{
if (strcmp(s->name, "*") == 0)
@@ -515,7 +430,6 @@ void report(struct slabinfo *s)
ops(s);
show_tracking(s);
slab_numa(s, 1);
- slab_stats(s);
}
void slabcache(struct slabinfo *s)
@@ -565,27 +479,13 @@ void slabcache(struct slabinfo *s)
*p++ = 'T';
*p = 0;
- if (show_activity) {
- unsigned long total_alloc;
- unsigned long total_free;
-
- total_alloc = s->alloc_fastpath + s->alloc_slowpath;
- total_free = s->free_fastpath + s->free_slowpath;
-
- printf("%-21s %8ld %8ld %8ld %3ld %3ld \n",
- s->name, s->objects,
- total_alloc, total_free,
- total_alloc ? (s->alloc_fastpath * 100 / total_alloc) : 0,
- total_free ? (s->free_fastpath * 100 / total_free) : 0);
- }
- else
- printf("%-21s %8ld %7d %8s %14s %4d %1d %3ld %3ld %s\n",
- s->name, s->objects, s->object_size, size_str, dist_str,
- s->objs_per_slab, s->order,
- s->slabs ? (s->partial * 100) / s->slabs : 100,
- s->slabs ? (s->objects * s->object_size * 100) /
- (s->slabs * (page_size << s->order)) : 100,
- flags);
+ printf("%-21s %8ld %7d %8s %14s %4d %1d %3ld %3ld %s\n",
+ s->name, s->objects, s->object_size, size_str, dist_str,
+ s->objs_per_slab, s->order,
+ s->slabs ? (s->partial * 100) / s->slabs : 100,
+ s->slabs ? (s->objects * s->object_size * 100) /
+ (s->slabs * (page_size << s->order)) : 100,
+ flags);
}
/*
@@ -992,8 +892,6 @@ void sort_slabs(void)
if (sort_size)
result = slab_size(s1) < slab_size(s2);
- else if (sort_active)
- result = slab_activity(s1) < slab_activity(s2);
else
result = strcasecmp(s1->name, s2->name);
@@ -1176,23 +1074,6 @@ void read_slab_dir(void)
free(t);
slab->store_user = get_obj("store_user");
slab->trace = get_obj("trace");
- slab->alloc_fastpath = get_obj("alloc_fastpath");
- slab->alloc_slowpath = get_obj("alloc_slowpath");
- slab->free_fastpath = get_obj("free_fastpath");
- slab->free_slowpath = get_obj("free_slowpath");
- slab->free_frozen= get_obj("free_frozen");
- slab->free_add_partial = get_obj("free_add_partial");
- slab->free_remove_partial = get_obj("free_remove_partial");
- slab->alloc_from_partial = get_obj("alloc_from_partial");
- slab->alloc_slab = get_obj("alloc_slab");
- slab->alloc_refill = get_obj("alloc_refill");
- slab->free_slab = get_obj("free_slab");
- slab->cpuslab_flush = get_obj("cpuslab_flush");
- slab->deactivate_full = get_obj("deactivate_full");
- slab->deactivate_empty = get_obj("deactivate_empty");
- slab->deactivate_to_head = get_obj("deactivate_to_head");
- slab->deactivate_to_tail = get_obj("deactivate_to_tail");
- slab->deactivate_remote_frees = get_obj("deactivate_remote_frees");
chdir("..");
if (slab->name[0] == ':')
alias_targets++;
@@ -1243,9 +1124,7 @@ void output_slabs(void)
struct option opts[] = {
{ "aliases", 0, NULL, 'a' },
- { "activity", 0, NULL, 'A' },
{ "debug", 2, NULL, 'd' },
- { "display-activity", 0, NULL, 'D' },
{ "empty", 0, NULL, 'e' },
{ "first-alias", 0, NULL, 'f' },
{ "help", 0, NULL, 'h' },
@@ -1270,7 +1149,7 @@ int main(int argc, char *argv[])
page_size = getpagesize();
- while ((c = getopt_long(argc, argv, "aAd::Defhil1noprstvzTS",
+ while ((c = getopt_long(argc, argv, "ad::efhil1noprstvzTS",
opts, NULL)) != -1)
switch (c) {
case '1':
@@ -1279,17 +1158,11 @@ int main(int argc, char *argv[])
case 'a':
show_alias = 1;
break;
- case 'A':
- sort_active = 1;
- break;
case 'd':
set_debug = 1;
if (!debug_opt_scan(optarg))
fatal("Invalid debug option '%s'\n", optarg);
break;
- case 'D':
- show_activity = 1;
- break;
case 'e':
show_empty = 1;
break;
diff --git a/trunk/MAINTAINERS b/trunk/MAINTAINERS
index 2cdb591ac080..aefd23f892ba 100644
--- a/trunk/MAINTAINERS
+++ b/trunk/MAINTAINERS
@@ -2150,14 +2150,6 @@ M: acme@ghostprotocols.net
L: netdev@vger.kernel.org
S: Maintained
-IPWIRELES DRIVER
-P: Jiri Kosina
-M: jkosina@suse.cz
-P: David Sterba
-M: dsterba@suse.cz
-S: Maintained
-T: git://git.kernel.org/pub/scm/linux/kernel/git/jikos/ipwireless_cs.git
-
IRDA SUBSYSTEM
P: Samuel Ortiz
M: samuel@sortiz.org
diff --git a/trunk/arch/m68k/kernel/process.c b/trunk/arch/m68k/kernel/process.c
index f85b928ffac4..3ee918695215 100644
--- a/trunk/arch/m68k/kernel/process.c
+++ b/trunk/arch/m68k/kernel/process.c
@@ -335,7 +335,7 @@ void dump_thread(struct pt_regs * regs, struct user * dump)
if (dump->start_stack < TASK_SIZE)
dump->u_ssize = ((unsigned long) (TASK_SIZE - dump->start_stack)) >> PAGE_SHIFT;
- dump->u_ar0 = offsetof(struct user, regs);
+ dump->u_ar0 = (struct user_regs_struct *)((int)&dump->regs - (int)dump);
sw = ((struct switch_stack *)regs) - 1;
dump->regs.d1 = regs->d1;
dump->regs.d2 = regs->d2;
diff --git a/trunk/arch/powerpc/kernel/asm-offsets.c b/trunk/arch/powerpc/kernel/asm-offsets.c
index 4b749c416464..e6e49289f788 100644
--- a/trunk/arch/powerpc/kernel/asm-offsets.c
+++ b/trunk/arch/powerpc/kernel/asm-offsets.c
@@ -313,7 +313,7 @@ int main(void)
DEFINE(CLOCK_REALTIME, CLOCK_REALTIME);
DEFINE(CLOCK_MONOTONIC, CLOCK_MONOTONIC);
DEFINE(NSEC_PER_SEC, NSEC_PER_SEC);
- DEFINE(CLOCK_REALTIME_RES, MONOTONIC_RES_NSEC);
+ DEFINE(CLOCK_REALTIME_RES, (KTIME_MONOTONIC_RES).tv64);
#ifdef CONFIG_BUG
DEFINE(BUG_ENTRY_SIZE, sizeof(struct bug_entry));
diff --git a/trunk/arch/x86/Kconfig b/trunk/arch/x86/Kconfig
index 9d0acedf5f3f..c95482b6b6dd 100644
--- a/trunk/arch/x86/Kconfig
+++ b/trunk/arch/x86/Kconfig
@@ -52,10 +52,6 @@ config HAVE_LATENCYTOP_SUPPORT
config SEMAPHORE_SLEEPERS
def_bool y
-config FAST_CMPXCHG_LOCAL
- bool
- default y
-
config MMU
def_bool y
diff --git a/trunk/drivers/char/pcmcia/Kconfig b/trunk/drivers/char/pcmcia/Kconfig
index 00b8a84b0319..f25facd97bb4 100644
--- a/trunk/drivers/char/pcmcia/Kconfig
+++ b/trunk/drivers/char/pcmcia/Kconfig
@@ -43,14 +43,5 @@ config CARDMAN_4040
(http://www.omnikey.com/), or a current development version of OpenCT
(http://www.opensc.org/).
-config IPWIRELESS
- tristate "IPWireless 3G UMTS PCMCIA card support"
- depends on PCMCIA
- select PPP
- help
- This is a driver for 3G UMTS PCMCIA card from IPWireless company. In
- some countries (for example Czech Republic, T-Mobile ISP) this card
- is shipped for service called UMTS 4G.
-
endmenu
diff --git a/trunk/drivers/char/pcmcia/Makefile b/trunk/drivers/char/pcmcia/Makefile
index be8f287aa398..0aae20985d57 100644
--- a/trunk/drivers/char/pcmcia/Makefile
+++ b/trunk/drivers/char/pcmcia/Makefile
@@ -4,8 +4,6 @@
# Makefile for the Linux PCMCIA char device drivers.
#
-obj-y += ipwireless/
-
obj-$(CONFIG_SYNCLINK_CS) += synclink_cs.o
obj-$(CONFIG_CARDMAN_4000) += cm4000_cs.o
obj-$(CONFIG_CARDMAN_4040) += cm4040_cs.o
diff --git a/trunk/drivers/char/pcmcia/ipwireless/Makefile b/trunk/drivers/char/pcmcia/ipwireless/Makefile
deleted file mode 100644
index b71eb593643d..000000000000
--- a/trunk/drivers/char/pcmcia/ipwireless/Makefile
+++ /dev/null
@@ -1,10 +0,0 @@
-#
-# drivers/char/pcmcia/ipwireless/Makefile
-#
-# Makefile for the IPWireless driver
-#
-
-obj-$(CONFIG_IPWIRELESS) += ipwireless.o
-
-ipwireless-objs := hardware.o main.o network.o tty.o
-
diff --git a/trunk/drivers/char/pcmcia/ipwireless/hardware.c b/trunk/drivers/char/pcmcia/ipwireless/hardware.c
deleted file mode 100644
index 1f978ff87fa8..000000000000
--- a/trunk/drivers/char/pcmcia/ipwireless/hardware.c
+++ /dev/null
@@ -1,1787 +0,0 @@
-/*
- * IPWireless 3G PCMCIA Network Driver
- *
- * Original code
- * by Stephen Blackheath ,
- * Ben Martel
- *
- * Copyrighted as follows:
- * Copyright (C) 2004 by Symmetric Systems Ltd (NZ)
- *
- * Various driver changes and rewrites, port to new kernels
- * Copyright (C) 2006-2007 Jiri Kosina
- *
- * Misc code cleanups and updates
- * Copyright (C) 2007 David Sterba
- */
-
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include "hardware.h"
-#include "setup_protocol.h"
-#include "network.h"
-#include "main.h"
-
-static void ipw_send_setup_packet(struct ipw_hardware *hw);
-static void handle_received_SETUP_packet(struct ipw_hardware *ipw,
- unsigned int address,
- unsigned char *data, int len,
- int is_last);
-static void ipwireless_setup_timer(unsigned long data);
-static void handle_received_CTRL_packet(struct ipw_hardware *hw,
- unsigned int channel_idx, unsigned char *data, int len);
-
-/*#define TIMING_DIAGNOSTICS*/
-
-#ifdef TIMING_DIAGNOSTICS
-
-static struct timing_stats {
- unsigned long last_report_time;
- unsigned long read_time;
- unsigned long write_time;
- unsigned long read_bytes;
- unsigned long write_bytes;
- unsigned long start_time;
-};
-
-static void start_timing(void)
-{
- timing_stats.start_time = jiffies;
-}
-
-static void end_read_timing(unsigned length)
-{
- timing_stats.read_time += (jiffies - start_time);
- timing_stats.read_bytes += length + 2;
- report_timing();
-}
-
-static void end_write_timing(unsigned length)
-{
- timing_stats.write_time += (jiffies - start_time);
- timing_stats.write_bytes += length + 2;
- report_timing();
-}
-
-static void report_timing(void)
-{
- unsigned long since = jiffies - timing_stats.last_report_time;
-
- /* If it's been more than one second... */
- if (since >= HZ) {
- int first = (timing_stats.last_report_time == 0);
-
- timing_stats.last_report_time = jiffies;
- if (!first)
- printk(KERN_INFO IPWIRELESS_PCCARD_NAME
- ": %u us elapsed - read %lu bytes in %u us, "
- "wrote %lu bytes in %u us\n",
- jiffies_to_usecs(since),
- timing_stats.read_bytes,
- jiffies_to_usecs(timing_stats.read_time),
- timing_stats.write_bytes,
- jiffies_to_usecs(timing_stats.write_time));
-
- timing_stats.read_time = 0;
- timing_stats.write_time = 0;
- timing_stats.read_bytes = 0;
- timing_stats.write_bytes = 0;
- }
-}
-#else
-static void start_timing(void) { }
-static void end_read_timing(unsigned length) { }
-static void end_write_timing(unsigned length) { }
-#endif
-
-/* Imported IPW definitions */
-
-#define LL_MTU_V1 318
-#define LL_MTU_V2 250
-#define LL_MTU_MAX (LL_MTU_V1 > LL_MTU_V2 ? LL_MTU_V1 : LL_MTU_V2)
-
-#define PRIO_DATA 2
-#define PRIO_CTRL 1
-#define PRIO_SETUP 0
-
-/* Addresses */
-#define ADDR_SETUP_PROT 0
-
-/* Protocol ids */
-enum {
- /* Identifier for the Com Data protocol */
- TL_PROTOCOLID_COM_DATA = 0,
-
- /* Identifier for the Com Control protocol */
- TL_PROTOCOLID_COM_CTRL = 1,
-
- /* Identifier for the Setup protocol */
- TL_PROTOCOLID_SETUP = 2
-};
-
-/* Number of bytes in NL packet header (cannot do
- * sizeof(nl_packet_header) since it's a bitfield) */
-#define NL_FIRST_PACKET_HEADER_SIZE 3
-
-/* Number of bytes in NL packet header (cannot do
- * sizeof(nl_packet_header) since it's a bitfield) */
-#define NL_FOLLOWING_PACKET_HEADER_SIZE 1
-
-struct nl_first_packet_header {
-#if defined(__BIG_ENDIAN_BITFIELD)
- unsigned char packet_rank:2;
- unsigned char address:3;
- unsigned char protocol:3;
-#else
- unsigned char protocol:3;
- unsigned char address:3;
- unsigned char packet_rank:2;
-#endif
- unsigned char length_lsb;
- unsigned char length_msb;
-};
-
-struct nl_packet_header {
-#if defined(__BIG_ENDIAN_BITFIELD)
- unsigned char packet_rank:2;
- unsigned char address:3;
- unsigned char protocol:3;
-#else
- unsigned char protocol:3;
- unsigned char address:3;
- unsigned char packet_rank:2;
-#endif
-};
-
-/* Value of 'packet_rank' above */
-#define NL_INTERMEDIATE_PACKET 0x0
-#define NL_LAST_PACKET 0x1
-#define NL_FIRST_PACKET 0x2
-
-union nl_packet {
- /* Network packet header of the first packet (a special case) */
- struct nl_first_packet_header hdr_first;
- /* Network packet header of the following packets (if any) */
- struct nl_packet_header hdr;
- /* Complete network packet (header + data) */
- unsigned char rawpkt[LL_MTU_MAX];
-} __attribute__ ((__packed__));
-
-#define HW_VERSION_UNKNOWN -1
-#define HW_VERSION_1 1
-#define HW_VERSION_2 2
-
-/* IPW I/O ports */
-#define IOIER 0x00 /* Interrupt Enable Register */
-#define IOIR 0x02 /* Interrupt Source/ACK register */
-#define IODCR 0x04 /* Data Control Register */
-#define IODRR 0x06 /* Data Read Register */
-#define IODWR 0x08 /* Data Write Register */
-#define IOESR 0x0A /* Embedded Driver Status Register */
-#define IORXR 0x0C /* Rx Fifo Register (Host to Embedded) */
-#define IOTXR 0x0E /* Tx Fifo Register (Embedded to Host) */
-
-/* I/O ports and bit definitions for version 1 of the hardware */
-
-/* IER bits*/
-#define IER_RXENABLED 0x1
-#define IER_TXENABLED 0x2
-
-/* ISR bits */
-#define IR_RXINTR 0x1
-#define IR_TXINTR 0x2
-
-/* DCR bits */
-#define DCR_RXDONE 0x1
-#define DCR_TXDONE 0x2
-#define DCR_RXRESET 0x4
-#define DCR_TXRESET 0x8
-
-/* I/O ports and bit definitions for version 2 of the hardware */
-
-struct MEMCCR {
- unsigned short reg_config_option; /* PCCOR: Configuration Option Register */
- unsigned short reg_config_and_status; /* PCCSR: Configuration and Status Register */
- unsigned short reg_pin_replacement; /* PCPRR: Pin Replacemant Register */
- unsigned short reg_socket_and_copy; /* PCSCR: Socket and Copy Register */
- unsigned short reg_ext_status; /* PCESR: Extendend Status Register */
- unsigned short reg_io_base; /* PCIOB: I/O Base Register */
-};
-
-struct MEMINFREG {
- unsigned short memreg_tx_old; /* TX Register (R/W) */
- unsigned short pad1;
- unsigned short memreg_rx_done; /* RXDone Register (R/W) */
- unsigned short pad2;
- unsigned short memreg_rx; /* RX Register (R/W) */
- unsigned short pad3;
- unsigned short memreg_pc_interrupt_ack; /* PC intr Ack Register (W) */
- unsigned short pad4;
- unsigned long memreg_card_present;/* Mask for Host to check (R) for
- * CARD_PRESENT_VALUE */
- unsigned short memreg_tx_new; /* TX2 (new) Register (R/W) */
-};
-
-#define IODMADPR 0x00 /* DMA Data Port Register (R/W) */
-
-#define CARD_PRESENT_VALUE (0xBEEFCAFEUL)
-
-#define MEMTX_TX 0x0001
-#define MEMRX_RX 0x0001
-#define MEMRX_RX_DONE 0x0001
-#define MEMRX_PCINTACKK 0x0001
-#define MEMRX_MEMSPURIOUSINT 0x0001
-
-#define NL_NUM_OF_PRIORITIES 3
-#define NL_NUM_OF_PROTOCOLS 3
-#define NL_NUM_OF_ADDRESSES NO_OF_IPW_CHANNELS
-
-struct ipw_hardware {
- unsigned int base_port;
- short hw_version;
- unsigned short ll_mtu;
- spinlock_t spinlock;
-
- int initializing;
- int init_loops;
- struct timer_list setup_timer;
-
- int tx_ready;
- struct list_head tx_queue[NL_NUM_OF_PRIORITIES];
- /* True if any packets are queued for transmission */
- int tx_queued;
-
- int rx_bytes_queued;
- struct list_head rx_queue;
- /* Pool of rx_packet structures that are not currently used. */
- struct list_head rx_pool;
- int rx_pool_size;
- /* True if reception of data is blocked while userspace processes it. */
- int blocking_rx;
- /* True if there is RX data ready on the hardware. */
- int rx_ready;
- unsigned short last_memtx_serial;
- /*
- * Newer versions of the V2 card firmware send serial numbers in the
- * MemTX register. 'serial_number_detected' is set true when we detect
- * a non-zero serial number (indicating the new firmware). Thereafter,
- * the driver can safely ignore the Timer Recovery re-sends to avoid
- * out-of-sync problems.
- */
- int serial_number_detected;
- struct work_struct work_rx;
-
- /* True if we are to send the set-up data to the hardware. */
- int to_setup;
-
- /* Card has been removed */
- int removed;
- /* Saved irq value when we disable the interrupt. */
- int irq;
- /* True if this driver is shutting down. */
- int shutting_down;
- /* Modem control lines */
- unsigned int control_lines[NL_NUM_OF_ADDRESSES];
- struct ipw_rx_packet *packet_assembler[NL_NUM_OF_ADDRESSES];
-
- struct tasklet_struct tasklet;
-
- /* The handle for the network layer, for the sending of events to it. */
- struct ipw_network *network;
- struct MEMINFREG __iomem *memory_info_regs;
- struct MEMCCR __iomem *memregs_CCR;
- void (*reboot_callback) (void *data);
- void *reboot_callback_data;
-
- unsigned short __iomem *memreg_tx;
-};
-
-/*
- * Packet info structure for tx packets.
- * Note: not all the fields defined here are required for all protocols
- */
-struct ipw_tx_packet {
- struct list_head queue;
- /* channel idx + 1 */
- unsigned char dest_addr;
- /* SETUP, CTRL or DATA */
- unsigned char protocol;
- /* Length of data block, which starts at the end of this structure */
- unsigned short length;
- /* Sending state */
- /* Offset of where we've sent up to so far */
- unsigned long offset;
- /* Count of packet fragments, starting at 0 */
- int fragment_count;
-
- /* Called after packet is sent and before is freed */
- void (*packet_callback) (void *cb_data, unsigned int packet_length);
- void *callback_data;
-};
-
-/* Signals from DTE */
-#define COMCTRL_RTS 0
-#define COMCTRL_DTR 1
-
-/* Signals from DCE */
-#define COMCTRL_CTS 2
-#define COMCTRL_DCD 3
-#define COMCTRL_DSR 4
-#define COMCTRL_RI 5
-
-struct ipw_control_packet_body {
- /* DTE signal or DCE signal */
- unsigned char sig_no;
- /* 0: set signal, 1: clear signal */
- unsigned char value;
-} __attribute__ ((__packed__));
-
-struct ipw_control_packet {
- struct ipw_tx_packet header;
- struct ipw_control_packet_body body;
-};
-
-struct ipw_rx_packet {
- struct list_head queue;
- unsigned int capacity;
- unsigned int length;
- unsigned int protocol;
- unsigned int channel_idx;
-};
-
-#ifdef IPWIRELESS_STATE_DEBUG
-int ipwireless_dump_hardware_state(char *p, size_t limit,
- struct ipw_hardware *hw)
-{
- return snprintf(p, limit,
- "debug: initializing=%d\n"
- "debug: tx_ready=%d\n"
- "debug: tx_queued=%d\n"
- "debug: rx_ready=%d\n"
- "debug: rx_bytes_queued=%d\n"
- "debug: blocking_rx=%d\n"
- "debug: removed=%d\n"
- "debug: hardware.shutting_down=%d\n"
- "debug: to_setup=%d\n",
- hw->initializing,
- hw->tx_ready,
- hw->tx_queued,
- hw->rx_ready,
- hw->rx_bytes_queued,
- hw->blocking_rx,
- hw->removed,
- hw->shutting_down,
- hw->to_setup);
-}
-#endif
-
-static char *data_type(const unsigned char *buf, unsigned length)
-{
- struct nl_packet_header *hdr = (struct nl_packet_header *) buf;
-
- if (length == 0)
- return " ";
-
- if (hdr->packet_rank & NL_FIRST_PACKET) {
- switch (hdr->protocol) {
- case TL_PROTOCOLID_COM_DATA: return "DATA ";
- case TL_PROTOCOLID_COM_CTRL: return "CTRL ";
- case TL_PROTOCOLID_SETUP: return "SETUP";
- default: return "???? ";
- }
- } else
- return " ";
-}
-
-#define DUMP_MAX_BYTES 64
-
-static void dump_data_bytes(const char *type, const unsigned char *data,
- unsigned length)
-{
- char prefix[56];
-
- sprintf(prefix, IPWIRELESS_PCCARD_NAME ": %s %s ",
- type, data_type(data, length));
- print_hex_dump_bytes(prefix, 0, (void *)data,
- length < DUMP_MAX_BYTES ? length : DUMP_MAX_BYTES);
-}
-
-static int do_send_fragment(struct ipw_hardware *hw, const unsigned char *data,
- unsigned length)
-{
- int i;
- unsigned long flags;
-
- start_timing();
-
- if (length == 0)
- return 0;
-
- if (length > hw->ll_mtu)
- return -1;
-
- if (ipwireless_debug)
- dump_data_bytes("send", data, length);
-
- spin_lock_irqsave(&hw->spinlock, flags);
-
- if (hw->hw_version == HW_VERSION_1) {
- outw((unsigned short) length, hw->base_port + IODWR);
-
- for (i = 0; i < length; i += 2) {
- unsigned short d = data[i];
- __le16 raw_data;
-
- if (likely(i + 1 < length))
- d |= data[i + 1] << 8;
- raw_data = cpu_to_le16(d);
- outw(raw_data, hw->base_port + IODWR);
- }
-
- outw(DCR_TXDONE, hw->base_port + IODCR);
- } else if (hw->hw_version == HW_VERSION_2) {
- outw((unsigned short) length, hw->base_port + IODMADPR);
-
- for (i = 0; i < length; i += 2) {
- unsigned short d = data[i];
- __le16 raw_data;
-
- if ((i + 1 < length))
- d |= data[i + 1] << 8;
- raw_data = cpu_to_le16(d);
- outw(raw_data, hw->base_port + IODMADPR);
- }
- while ((i & 3) != 2) {
- outw((unsigned short) 0xDEAD, hw->base_port + IODMADPR);
- i += 2;
- }
- writew(MEMRX_RX, &hw->memory_info_regs->memreg_rx);
- }
-
- spin_unlock_irqrestore(&hw->spinlock, flags);
-
- end_write_timing(length);
-
- return 0;
-}
-
-static int do_send_packet(struct ipw_hardware *hw, struct ipw_tx_packet *packet)
-{
- unsigned short fragment_data_len;
- unsigned short data_left = packet->length - packet->offset;
- unsigned short header_size;
- union nl_packet pkt;
-
- header_size =
- (packet->fragment_count == 0)
- ? NL_FIRST_PACKET_HEADER_SIZE
- : NL_FOLLOWING_PACKET_HEADER_SIZE;
- fragment_data_len = hw->ll_mtu - header_size;
- if (data_left < fragment_data_len)
- fragment_data_len = data_left;
-
- pkt.hdr_first.protocol = packet->protocol;
- pkt.hdr_first.address = packet->dest_addr;
- pkt.hdr_first.packet_rank = 0;
-
- /* First packet? */
- if (packet->fragment_count == 0) {
- pkt.hdr_first.packet_rank |= NL_FIRST_PACKET;
- pkt.hdr_first.length_lsb = (unsigned char) packet->length;
- pkt.hdr_first.length_msb =
- (unsigned char) (packet->length >> 8);
- }
-
- memcpy(pkt.rawpkt + header_size,
- ((unsigned char *) packet) + sizeof(struct ipw_tx_packet) +
- packet->offset, fragment_data_len);
- packet->offset += fragment_data_len;
- packet->fragment_count++;
-
- /* Last packet? (May also be first packet.) */
- if (packet->offset == packet->length)
- pkt.hdr_first.packet_rank |= NL_LAST_PACKET;
- do_send_fragment(hw, pkt.rawpkt, header_size + fragment_data_len);
-
- /* If this packet has unsent data, then re-queue it. */
- if (packet->offset < packet->length) {
- /*
- * Re-queue it at the head of the highest priority queue so
- * it goes before all other packets
- */
- unsigned long flags;
-
- spin_lock_irqsave(&hw->spinlock, flags);
- list_add(&packet->queue, &hw->tx_queue[0]);
- spin_unlock_irqrestore(&hw->spinlock, flags);
- } else {
- if (packet->packet_callback)
- packet->packet_callback(packet->callback_data,
- packet->length);
- kfree(packet);
- }
-
- return 0;
-}
-
-static void ipw_setup_hardware(struct ipw_hardware *hw)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&hw->spinlock, flags);
- if (hw->hw_version == HW_VERSION_1) {
- /* Reset RX FIFO */
- outw(DCR_RXRESET, hw->base_port + IODCR);
- /* SB: Reset TX FIFO */
- outw(DCR_TXRESET, hw->base_port + IODCR);
-
- /* Enable TX and RX interrupts. */
- outw(IER_TXENABLED | IER_RXENABLED, hw->base_port + IOIER);
- } else {
- /*
- * Set INTRACK bit (bit 0), which means we must explicitly
- * acknowledge interrupts by clearing bit 2 of reg_config_and_status.
- */
- unsigned short csr = readw(&hw->memregs_CCR->reg_config_and_status);
-
- csr |= 1;
- writew(csr, &hw->memregs_CCR->reg_config_and_status);
- }
- spin_unlock_irqrestore(&hw->spinlock, flags);
-}
-
-/*
- * If 'packet' is NULL, then this function allocates a new packet, setting its
- * length to 0 and ensuring it has the specified minimum amount of free space.
- *
- * If 'packet' is not NULL, then this function enlarges it if it doesn't
- * have the specified minimum amount of free space.
- *
- */
-static struct ipw_rx_packet *pool_allocate(struct ipw_hardware *hw,
- struct ipw_rx_packet *packet,
- int minimum_free_space)
-{
-
- if (!packet) {
- unsigned long flags;
-
- /*
- * If this is the first fragment, then we will need to fetch a
- * packet to put it in.
- */
- spin_lock_irqsave(&hw->spinlock, flags);
- /* If we have one in our pool, then pull it out. */
- if (!list_empty(&hw->rx_pool)) {
- packet = list_first_entry(&hw->rx_pool,
- struct ipw_rx_packet, queue);
- list_del(&packet->queue);
- hw->rx_pool_size--;
- spin_unlock_irqrestore(&hw->spinlock, flags);
- } else {
- /* Otherwise allocate a new one. */
- static int min_capacity = 256;
- int new_capacity;
-
- spin_unlock_irqrestore(&hw->spinlock, flags);
- new_capacity =
- minimum_free_space > min_capacity
- ? minimum_free_space
- : min_capacity;
- packet = kmalloc(sizeof(struct ipw_rx_packet)
- + new_capacity, GFP_ATOMIC);
- if (!packet)
- return NULL;
- packet->capacity = new_capacity;
- }
- packet->length = 0;
- }
-
- /*
- * If this packet does not have sufficient capacity for the data we
- * want to add, then make it bigger.
- */
- if (packet->length + minimum_free_space > packet->capacity) {
- struct ipw_rx_packet *old_packet = packet;
-
- packet = kmalloc(sizeof(struct ipw_rx_packet) +
- old_packet->length + minimum_free_space,
- GFP_ATOMIC);
- if (!packet)
- return NULL;
- memcpy(packet, old_packet,
- sizeof(struct ipw_rx_packet)
- + old_packet->length);
- packet->capacity = old_packet->length + minimum_free_space;
- kfree(old_packet);
- }
-
- return packet;
-}
-
-static void pool_free(struct ipw_hardware *hw, struct ipw_rx_packet *packet)
-{
- if (hw->rx_pool_size > 6)
- kfree(packet);
- else {
- hw->rx_pool_size++;
- list_add_tail(&packet->queue, &hw->rx_pool);
- }
-}
-
-static void queue_received_packet(struct ipw_hardware *hw,
- unsigned int protocol, unsigned int address,
- unsigned char *data, int length, int is_last)
-{
- unsigned int channel_idx = address - 1;
- struct ipw_rx_packet *packet = NULL;
- unsigned long flags;
-
- /* Discard packet if channel index is out of range. */
- if (channel_idx >= NL_NUM_OF_ADDRESSES) {
- printk(KERN_INFO IPWIRELESS_PCCARD_NAME
- ": data packet has bad address %u\n", address);
- return;
- }
-
- /*
- * ->packet_assembler is safe to touch unlocked, this is the only place
- */
- if (protocol == TL_PROTOCOLID_COM_DATA) {
- struct ipw_rx_packet **assem =
- &hw->packet_assembler[channel_idx];
-
- /*
- * Create a new packet, or assembler already contains one
- * enlarge it by 'length' bytes.
- */
- (*assem) = pool_allocate(hw, *assem, length);
- if (!(*assem)) {
- printk(KERN_ERR IPWIRELESS_PCCARD_NAME
- ": no memory for incomming data packet, dropped!\n");
- return;
- }
- (*assem)->protocol = protocol;
- (*assem)->channel_idx = channel_idx;
-
- /* Append this packet data onto existing data. */
- memcpy((unsigned char *)(*assem) +
- sizeof(struct ipw_rx_packet)
- + (*assem)->length, data, length);
- (*assem)->length += length;
- if (is_last) {
- packet = *assem;
- *assem = NULL;
- /* Count queued DATA bytes only */
- spin_lock_irqsave(&hw->spinlock, flags);
- hw->rx_bytes_queued += packet->length;
- spin_unlock_irqrestore(&hw->spinlock, flags);
- }
- } else {
- /* If it's a CTRL packet, don't assemble, just queue it. */
- packet = pool_allocate(hw, NULL, length);
- if (!packet) {
- printk(KERN_ERR IPWIRELESS_PCCARD_NAME
- ": no memory for incomming ctrl packet, dropped!\n");
- return;
- }
- packet->protocol = protocol;
- packet->channel_idx = channel_idx;
- memcpy((unsigned char *)packet + sizeof(struct ipw_rx_packet),
- data, length);
- packet->length = length;
- }
-
- /*
- * If this is the last packet, then send the assembled packet on to the
- * network layer.
- */
- if (packet) {
- spin_lock_irqsave(&hw->spinlock, flags);
- list_add_tail(&packet->queue, &hw->rx_queue);
- /* Block reception of incoming packets if queue is full. */
- hw->blocking_rx =
- hw->rx_bytes_queued >= IPWIRELESS_RX_QUEUE_SIZE;
-
- spin_unlock_irqrestore(&hw->spinlock, flags);
- schedule_work(&hw->work_rx);
- }
-}
-
-/*
- * Workqueue callback
- */
-static void ipw_receive_data_work(struct work_struct *work_rx)
-{
- struct ipw_hardware *hw =
- container_of(work_rx, struct ipw_hardware, work_rx);
- unsigned long flags;
-
- spin_lock_irqsave(&hw->spinlock, flags);
- while (!list_empty(&hw->rx_queue)) {
- struct ipw_rx_packet *packet =
- list_first_entry(&hw->rx_queue,
- struct ipw_rx_packet, queue);
-
- if (hw->shutting_down)
- break;
- list_del(&packet->queue);
-
- /*
- * Note: ipwireless_network_packet_received must be called in a
- * process context (i.e. via schedule_work) because the tty
- * output code can sleep in the tty_flip_buffer_push call.
- */
- if (packet->protocol == TL_PROTOCOLID_COM_DATA) {
- if (hw->network != NULL) {
- /* If the network hasn't been disconnected. */
- spin_unlock_irqrestore(&hw->spinlock, flags);
- /*
- * This must run unlocked due to tty processing
- * and mutex locking
- */
- ipwireless_network_packet_received(
- hw->network,
- packet->channel_idx,
- (unsigned char *)packet
- + sizeof(struct ipw_rx_packet),
- packet->length);
- spin_lock_irqsave(&hw->spinlock, flags);
- }
- /* Count queued DATA bytes only */
- hw->rx_bytes_queued -= packet->length;
- } else {
- /*
- * This is safe to be called locked, callchain does
- * not block
- */
- handle_received_CTRL_packet(hw, packet->channel_idx,
- (unsigned char *)packet
- + sizeof(struct ipw_rx_packet),
- packet->length);
- }
- pool_free(hw, packet);
- /*
- * Unblock reception of incoming packets if queue is no longer
- * full.
- */
- hw->blocking_rx =
- hw->rx_bytes_queued >= IPWIRELESS_RX_QUEUE_SIZE;
- if (hw->shutting_down)
- break;
- }
- spin_unlock_irqrestore(&hw->spinlock, flags);
-}
-
-static void handle_received_CTRL_packet(struct ipw_hardware *hw,
- unsigned int channel_idx,
- unsigned char *data, int len)
-{
- struct ipw_control_packet_body *body =
- (struct ipw_control_packet_body *) data;
- unsigned int changed_mask;
-
- if (len != sizeof(struct ipw_control_packet_body)) {
- printk(KERN_INFO IPWIRELESS_PCCARD_NAME
- ": control packet was %d bytes - wrong size!\n",
- len);
- return;
- }
-
- switch (body->sig_no) {
- case COMCTRL_CTS:
- changed_mask = IPW_CONTROL_LINE_CTS;
- break;
- case COMCTRL_DCD:
- changed_mask = IPW_CONTROL_LINE_DCD;
- break;
- case COMCTRL_DSR:
- changed_mask = IPW_CONTROL_LINE_DSR;
- break;
- case COMCTRL_RI:
- changed_mask = IPW_CONTROL_LINE_RI;
- break;
- default:
- changed_mask = 0;
- }
-
- if (changed_mask != 0) {
- if (body->value)
- hw->control_lines[channel_idx] |= changed_mask;
- else
- hw->control_lines[channel_idx] &= ~changed_mask;
- if (hw->network)
- ipwireless_network_notify_control_line_change(
- hw->network,
- channel_idx,
- hw->control_lines[channel_idx],
- changed_mask);
- }
-}
-
-static void handle_received_packet(struct ipw_hardware *hw,
- union nl_packet *packet,
- unsigned short len)
-{
- unsigned int protocol = packet->hdr.protocol;
- unsigned int address = packet->hdr.address;
- unsigned int header_length;
- unsigned char *data;
- unsigned int data_len;
- int is_last = packet->hdr.packet_rank & NL_LAST_PACKET;
-
- if (packet->hdr.packet_rank & NL_FIRST_PACKET)
- header_length = NL_FIRST_PACKET_HEADER_SIZE;
- else
- header_length = NL_FOLLOWING_PACKET_HEADER_SIZE;
-
- data = packet->rawpkt + header_length;
- data_len = len - header_length;
- switch (protocol) {
- case TL_PROTOCOLID_COM_DATA:
- case TL_PROTOCOLID_COM_CTRL:
- queue_received_packet(hw, protocol, address, data, data_len,
- is_last);
- break;
- case TL_PROTOCOLID_SETUP:
- handle_received_SETUP_packet(hw, address, data, data_len,
- is_last);
- break;
- }
-}
-
-static void acknowledge_data_read(struct ipw_hardware *hw)
-{
- if (hw->hw_version == HW_VERSION_1)
- outw(DCR_RXDONE, hw->base_port + IODCR);
- else
- writew(MEMRX_PCINTACKK,
- &hw->memory_info_regs->memreg_pc_interrupt_ack);
-}
-
-/*
- * Retrieve a packet from the IPW hardware.
- */
-static void do_receive_packet(struct ipw_hardware *hw)
-{
- unsigned len;
- unsigned int i;
- unsigned char pkt[LL_MTU_MAX];
-
- start_timing();
-
- if (hw->hw_version == HW_VERSION_1) {
- len = inw(hw->base_port + IODRR);
- if (len > hw->ll_mtu) {
- printk(KERN_INFO IPWIRELESS_PCCARD_NAME
- ": received a packet of %u bytes - "
- "longer than the MTU!\n", len);
- outw(DCR_RXDONE | DCR_RXRESET, hw->base_port + IODCR);
- return;
- }
-
- for (i = 0; i < len; i += 2) {
- __le16 raw_data = inw(hw->base_port + IODRR);
- unsigned short data = le16_to_cpu(raw_data);
-
- pkt[i] = (unsigned char) data;
- pkt[i + 1] = (unsigned char) (data >> 8);
- }
- } else {
- len = inw(hw->base_port + IODMADPR);
- if (len > hw->ll_mtu) {
- printk(KERN_INFO IPWIRELESS_PCCARD_NAME
- ": received a packet of %u bytes - "
- "longer than the MTU!\n", len);
- writew(MEMRX_PCINTACKK,
- &hw->memory_info_regs->memreg_pc_interrupt_ack);
- return;
- }
-
- for (i = 0; i < len; i += 2) {
- __le16 raw_data = inw(hw->base_port + IODMADPR);
- unsigned short data = le16_to_cpu(raw_data);
-
- pkt[i] = (unsigned char) data;
- pkt[i + 1] = (unsigned char) (data >> 8);
- }
-
- while ((i & 3) != 2) {
- inw(hw->base_port + IODMADPR);
- i += 2;
- }
- }
-
- acknowledge_data_read(hw);
-
- if (ipwireless_debug)
- dump_data_bytes("recv", pkt, len);
-
- handle_received_packet(hw, (union nl_packet *) pkt, len);
-
- end_read_timing(len);
-}
-
-static int get_current_packet_priority(struct ipw_hardware *hw)
-{
- /*
- * If we're initializing, don't send anything of higher priority than
- * PRIO_SETUP. The network layer therefore need not care about
- * hardware initialization - any of its stuff will simply be queued
- * until setup is complete.
- */
- return (hw->to_setup || hw->initializing
- ? PRIO_SETUP + 1 :
- NL_NUM_OF_PRIORITIES);
-}
-
-/*
- * return 1 if something has been received from hw
- */
-static int get_packets_from_hw(struct ipw_hardware *hw)
-{
- int received = 0;
- unsigned long flags;
-
- spin_lock_irqsave(&hw->spinlock, flags);
- while (hw->rx_ready && !hw->blocking_rx) {
- received = 1;
- hw->rx_ready--;
- spin_unlock_irqrestore(&hw->spinlock, flags);
-
- do_receive_packet(hw);
-
- spin_lock_irqsave(&hw->spinlock, flags);
- }
- spin_unlock_irqrestore(&hw->spinlock, flags);
-
- return received;
-}
-
-/*
- * Send pending packet up to given priority, prioritize SETUP data until
- * hardware is fully setup.
- *
- * return 1 if more packets can be sent
- */
-static int send_pending_packet(struct ipw_hardware *hw, int priority_limit)
-{
- int more_to_send = 0;
- unsigned long flags;
-
- spin_lock_irqsave(&hw->spinlock, flags);
- if (hw->tx_queued && hw->tx_ready != 0) {
- int priority;
- struct ipw_tx_packet *packet = NULL;
-
- hw->tx_ready--;
-
- /* Pick a packet */
- for (priority = 0; priority < priority_limit; priority++) {
- if (!list_empty(&hw->tx_queue[priority])) {
- packet = list_first_entry(
- &hw->tx_queue[priority],
- struct ipw_tx_packet,
- queue);
-
- list_del(&packet->queue);
-
- break;
- }
- }
- if (!packet) {
- hw->tx_queued = 0;
- spin_unlock_irqrestore(&hw->spinlock, flags);
- return 0;
- }
- spin_unlock_irqrestore(&hw->spinlock, flags);
-
- /* Send */
- do_send_packet(hw, packet);
-
- /* Check if more to send */
- spin_lock_irqsave(&hw->spinlock, flags);
- for (priority = 0; priority < priority_limit; priority++)
- if (!list_empty(&hw->tx_queue[priority])) {
- more_to_send = 1;
- break;
- }
-
- if (!more_to_send)
- hw->tx_queued = 0;
- }
- spin_unlock_irqrestore(&hw->spinlock, flags);
-
- return more_to_send;
-}
-
-/*
- * Send and receive all queued packets.
- */
-static void ipwireless_do_tasklet(unsigned long hw_)
-{
- struct ipw_hardware *hw = (struct ipw_hardware *) hw_;
- unsigned long flags;
-
- spin_lock_irqsave(&hw->spinlock, flags);
- if (hw->shutting_down) {
- spin_unlock_irqrestore(&hw->spinlock, flags);
- return;
- }
-
- if (hw->to_setup == 1) {
- /*
- * Initial setup data sent to hardware
- */
- hw->to_setup = 2;
- spin_unlock_irqrestore(&hw->spinlock, flags);
-
- ipw_setup_hardware(hw);
- ipw_send_setup_packet(hw);
-
- send_pending_packet(hw, PRIO_SETUP + 1);
- get_packets_from_hw(hw);
- } else {
- int priority_limit = get_current_packet_priority(hw);
- int again;
-
- spin_unlock_irqrestore(&hw->spinlock, flags);
-
- do {
- again = send_pending_packet(hw, priority_limit);
- again |= get_packets_from_hw(hw);
- } while (again);
- }
-}
-
-/*
- * return true if the card is physically present.
- */
-static int is_card_present(struct ipw_hardware *hw)
-{
- if (hw->hw_version == HW_VERSION_1)
- return inw(hw->base_port + IOIR) != 0xFFFF;
- else
- return readl(&hw->memory_info_regs->memreg_card_present) ==
- CARD_PRESENT_VALUE;
-}
-
-static irqreturn_t ipwireless_handle_v1_interrupt(int irq,
- struct ipw_hardware *hw)
-{
- unsigned short irqn;
-
- irqn = inw(hw->base_port + IOIR);
-
- /* Check if card is present */
- if (irqn == 0xFFFF)
- return IRQ_NONE;
- else if (irqn != 0) {
- unsigned short ack = 0;
- unsigned long flags;
-
- /* Transmit complete. */
- if (irqn & IR_TXINTR) {
- ack |= IR_TXINTR;
- spin_lock_irqsave(&hw->spinlock, flags);
- hw->tx_ready++;
- spin_unlock_irqrestore(&hw->spinlock, flags);
- }
- /* Received data */
- if (irqn & IR_RXINTR) {
- ack |= IR_RXINTR;
- spin_lock_irqsave(&hw->spinlock, flags);
- hw->rx_ready++;
- spin_unlock_irqrestore(&hw->spinlock, flags);
- }
- if (ack != 0) {
- outw(ack, hw->base_port + IOIR);
- tasklet_schedule(&hw->tasklet);
- }
- return IRQ_HANDLED;
- }
- return IRQ_NONE;
-}
-
-static void acknowledge_pcmcia_interrupt(struct ipw_hardware *hw)
-{
- unsigned short csr = readw(&hw->memregs_CCR->reg_config_and_status);
-
- csr &= 0xfffd;
- writew(csr, &hw->memregs_CCR->reg_config_and_status);
-}
-
-static irqreturn_t ipwireless_handle_v2_v3_interrupt(int irq,
- struct ipw_hardware *hw)
-{
- int tx = 0;
- int rx = 0;
- int rx_repeat = 0;
- int try_mem_tx_old;
- unsigned long flags;
-
- do {
-
- unsigned short memtx = readw(hw->memreg_tx);
- unsigned short memtx_serial;
- unsigned short memrxdone =
- readw(&hw->memory_info_regs->memreg_rx_done);
-
- try_mem_tx_old = 0;
-
- /* check whether the interrupt was generated by ipwireless card */
- if (!(memtx & MEMTX_TX) && !(memrxdone & MEMRX_RX_DONE)) {
-
- /* check if the card uses memreg_tx_old register */
- if (hw->memreg_tx == &hw->memory_info_regs->memreg_tx_new) {
- memtx = readw(&hw->memory_info_regs->memreg_tx_old);
- if (memtx & MEMTX_TX) {
- printk(KERN_INFO IPWIRELESS_PCCARD_NAME
- ": Using memreg_tx_old\n");
- hw->memreg_tx =
- &hw->memory_info_regs->memreg_tx_old;
- } else {
- return IRQ_NONE;
- }
- } else {
- return IRQ_NONE;
- }
- }
-
- /*
- * See if the card is physically present. Note that while it is
- * powering up, it appears not to be present.
- */
- if (!is_card_present(hw)) {
- acknowledge_pcmcia_interrupt(hw);
- return IRQ_HANDLED;
- }
-
- memtx_serial = memtx & (unsigned short) 0xff00;
- if (memtx & MEMTX_TX) {
- writew(memtx_serial, hw->memreg_tx);
-
- if (hw->serial_number_detected) {
- if (memtx_serial != hw->last_memtx_serial) {
- hw->last_memtx_serial = memtx_serial;
- spin_lock_irqsave(&hw->spinlock, flags);
- hw->rx_ready++;
- spin_unlock_irqrestore(&hw->spinlock, flags);
- rx = 1;
- } else
- /* Ignore 'Timer Recovery' duplicates. */
- rx_repeat = 1;
- } else {
- /*
- * If a non-zero serial number is seen, then enable
- * serial number checking.
- */
- if (memtx_serial != 0) {
- hw->serial_number_detected = 1;
- printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME
- ": memreg_tx serial num detected\n");
-
- spin_lock_irqsave(&hw->spinlock, flags);
- hw->rx_ready++;
- spin_unlock_irqrestore(&hw->spinlock, flags);
- }
- rx = 1;
- }
- }
- if (memrxdone & MEMRX_RX_DONE) {
- writew(0, &hw->memory_info_regs->memreg_rx_done);
- spin_lock_irqsave(&hw->spinlock, flags);
- hw->tx_ready++;
- spin_unlock_irqrestore(&hw->spinlock, flags);
- tx = 1;
- }
- if (tx)
- writew(MEMRX_PCINTACKK,
- &hw->memory_info_regs->memreg_pc_interrupt_ack);
-
- acknowledge_pcmcia_interrupt(hw);
-
- if (tx || rx)
- tasklet_schedule(&hw->tasklet);
- else if (!rx_repeat) {
- if (hw->memreg_tx == &hw->memory_info_regs->memreg_tx_new) {
- if (hw->serial_number_detected)
- printk(KERN_WARNING IPWIRELESS_PCCARD_NAME
- ": spurious interrupt - new_tx mode\n");
- else {
- printk(KERN_WARNING IPWIRELESS_PCCARD_NAME
- ": no valid memreg_tx value - "
- "switching to the old memreg_tx\n");
- hw->memreg_tx =
- &hw->memory_info_regs->memreg_tx_old;
- try_mem_tx_old = 1;
- }
- } else
- printk(KERN_WARNING IPWIRELESS_PCCARD_NAME
- ": spurious interrupt - old_tx mode\n");
- }
-
- } while (try_mem_tx_old == 1);
-
- return IRQ_HANDLED;
-}
-
-irqreturn_t ipwireless_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
- struct ipw_hardware *hw = dev_id;
-
- if (hw->hw_version == HW_VERSION_1)
- return ipwireless_handle_v1_interrupt(irq, hw);
- else
- return ipwireless_handle_v2_v3_interrupt(irq, hw);
-}
-
-static void flush_packets_to_hw(struct ipw_hardware *hw)
-{
- int priority_limit;
- unsigned long flags;
-
- spin_lock_irqsave(&hw->spinlock, flags);
- priority_limit = get_current_packet_priority(hw);
- spin_unlock_irqrestore(&hw->spinlock, flags);
-
- while (send_pending_packet(hw, priority_limit));
-}
-
-static void send_packet(struct ipw_hardware *hw, int priority,
- struct ipw_tx_packet *packet)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&hw->spinlock, flags);
- list_add_tail(&packet->queue, &hw->tx_queue[priority]);
- hw->tx_queued = 1;
- spin_unlock_irqrestore(&hw->spinlock, flags);
-
- flush_packets_to_hw(hw);
-}
-
-/* Create data packet, non-atomic allocation */
-static void *alloc_data_packet(int data_size,
- unsigned char dest_addr,
- unsigned char protocol)
-{
- struct ipw_tx_packet *packet = kzalloc(
- sizeof(struct ipw_tx_packet) + data_size,
- GFP_ATOMIC);
-
- if (!packet)
- return NULL;
-
- INIT_LIST_HEAD(&packet->queue);
- packet->dest_addr = dest_addr;
- packet->protocol = protocol;
- packet->length = data_size;
-
- return packet;
-}
-
-static void *alloc_ctrl_packet(int header_size,
- unsigned char dest_addr,
- unsigned char protocol,
- unsigned char sig_no)
-{
- /*
- * sig_no is located right after ipw_tx_packet struct in every
- * CTRL or SETUP packets, we can use ipw_control_packet as a
- * common struct
- */
- struct ipw_control_packet *packet = kzalloc(header_size, GFP_ATOMIC);
-
- if (!packet)
- return NULL;
-
- INIT_LIST_HEAD(&packet->header.queue);
- packet->header.dest_addr = dest_addr;
- packet->header.protocol = protocol;
- packet->header.length = header_size - sizeof(struct ipw_tx_packet);
- packet->body.sig_no = sig_no;
-
- return packet;
-}
-
-int ipwireless_send_packet(struct ipw_hardware *hw, unsigned int channel_idx,
- unsigned char *data, unsigned int length,
- void (*callback) (void *cb, unsigned int length),
- void *callback_data)
-{
- struct ipw_tx_packet *packet;
-
- packet = alloc_data_packet(length,
- (unsigned char) (channel_idx + 1),
- TL_PROTOCOLID_COM_DATA);
- if (!packet)
- return -ENOMEM;
- packet->packet_callback = callback;
- packet->callback_data = callback_data;
- memcpy((unsigned char *) packet +
- sizeof(struct ipw_tx_packet), data, length);
-
- send_packet(hw, PRIO_DATA, packet);
- return 0;
-}
-
-static int set_control_line(struct ipw_hardware *hw, int prio,
- unsigned int channel_idx, int line, int state)
-{
- struct ipw_control_packet *packet;
- int protocolid = TL_PROTOCOLID_COM_CTRL;
-
- if (prio == PRIO_SETUP)
- protocolid = TL_PROTOCOLID_SETUP;
-
- packet = alloc_ctrl_packet(sizeof(struct ipw_control_packet),
- (unsigned char) (channel_idx + 1),
- protocolid, line);
- if (!packet)
- return -ENOMEM;
- packet->header.length = sizeof(struct ipw_control_packet_body);
- packet->body.value = (unsigned char) (state == 0 ? 0 : 1);
- send_packet(hw, prio, &packet->header);
- return 0;
-}
-
-
-static int set_DTR(struct ipw_hardware *hw, int priority,
- unsigned int channel_idx, int state)
-{
- if (state != 0)
- hw->control_lines[channel_idx] |= IPW_CONTROL_LINE_DTR;
- else
- hw->control_lines[channel_idx] &= ~IPW_CONTROL_LINE_DTR;
-
- return set_control_line(hw, priority, channel_idx, COMCTRL_DTR, state);
-}
-
-static int set_RTS(struct ipw_hardware *hw, int priority,
- unsigned int channel_idx, int state)
-{
- if (state != 0)
- hw->control_lines[channel_idx] |= IPW_CONTROL_LINE_RTS;
- else
- hw->control_lines[channel_idx] &= ~IPW_CONTROL_LINE_RTS;
-
- return set_control_line(hw, priority, channel_idx, COMCTRL_RTS, state);
-}
-
-int ipwireless_set_DTR(struct ipw_hardware *hw, unsigned int channel_idx,
- int state)
-{
- return set_DTR(hw, PRIO_CTRL, channel_idx, state);
-}
-
-int ipwireless_set_RTS(struct ipw_hardware *hw, unsigned int channel_idx,
- int state)
-{
- return set_RTS(hw, PRIO_CTRL, channel_idx, state);
-}
-
-struct ipw_setup_get_version_query_packet {
- struct ipw_tx_packet header;
- struct tl_setup_get_version_qry body;
-};
-
-struct ipw_setup_config_packet {
- struct ipw_tx_packet header;
- struct tl_setup_config_msg body;
-};
-
-struct ipw_setup_config_done_packet {
- struct ipw_tx_packet header;
- struct tl_setup_config_done_msg body;
-};
-
-struct ipw_setup_open_packet {
- struct ipw_tx_packet header;
- struct tl_setup_open_msg body;
-};
-
-struct ipw_setup_info_packet {
- struct ipw_tx_packet header;
- struct tl_setup_info_msg body;
-};
-
-struct ipw_setup_reboot_msg_ack {
- struct ipw_tx_packet header;
- struct TlSetupRebootMsgAck body;
-};
-
-/* This handles the actual initialization of the card */
-static void __handle_setup_get_version_rsp(struct ipw_hardware *hw)
-{
- struct ipw_setup_config_packet *config_packet;
- struct ipw_setup_config_done_packet *config_done_packet;
- struct ipw_setup_open_packet *open_packet;
- struct ipw_setup_info_packet *info_packet;
- int port;
- unsigned int channel_idx;
-
- /* generate config packet */
- for (port = 1; port <= NL_NUM_OF_ADDRESSES; port++) {
- config_packet = alloc_ctrl_packet(
- sizeof(struct ipw_setup_config_packet),
- ADDR_SETUP_PROT,
- TL_PROTOCOLID_SETUP,
- TL_SETUP_SIGNO_CONFIG_MSG);
- if (!config_packet)
- goto exit_nomem;
- config_packet->header.length = sizeof(struct tl_setup_config_msg);
- config_packet->body.port_no = port;
- config_packet->body.prio_data = PRIO_DATA;
- config_packet->body.prio_ctrl = PRIO_CTRL;
- send_packet(hw, PRIO_SETUP, &config_packet->header);
- }
- config_done_packet = alloc_ctrl_packet(
- sizeof(struct ipw_setup_config_done_packet),
- ADDR_SETUP_PROT,
- TL_PROTOCOLID_SETUP,
- TL_SETUP_SIGNO_CONFIG_DONE_MSG);
- if (!config_done_packet)
- goto exit_nomem;
- config_done_packet->header.length = sizeof(struct tl_setup_config_done_msg);
- send_packet(hw, PRIO_SETUP, &config_done_packet->header);
-
- /* generate open packet */
- for (port = 1; port <= NL_NUM_OF_ADDRESSES; port++) {
- open_packet = alloc_ctrl_packet(
- sizeof(struct ipw_setup_open_packet),
- ADDR_SETUP_PROT,
- TL_PROTOCOLID_SETUP,
- TL_SETUP_SIGNO_OPEN_MSG);
- if (!open_packet)
- goto exit_nomem;
- open_packet->header.length = sizeof(struct tl_setup_open_msg);
- open_packet->body.port_no = port;
- send_packet(hw, PRIO_SETUP, &open_packet->header);
- }
- for (channel_idx = 0;
- channel_idx < NL_NUM_OF_ADDRESSES; channel_idx++) {
- int ret;
-
- ret = set_DTR(hw, PRIO_SETUP, channel_idx,
- (hw->control_lines[channel_idx] &
- IPW_CONTROL_LINE_DTR) != 0);
- if (ret) {
- printk(KERN_ERR IPWIRELESS_PCCARD_NAME
- ": error setting DTR (%d)\n", ret);
- return;
- }
-
- set_RTS(hw, PRIO_SETUP, channel_idx,
- (hw->control_lines [channel_idx] &
- IPW_CONTROL_LINE_RTS) != 0);
- if (ret) {
- printk(KERN_ERR IPWIRELESS_PCCARD_NAME
- ": error setting RTS (%d)\n", ret);
- return;
- }
- }
- /*
- * For NDIS we assume that we are using sync PPP frames, for COM async.
- * This driver uses NDIS mode too. We don't bother with translation
- * from async -> sync PPP.
- */
- info_packet = alloc_ctrl_packet(sizeof(struct ipw_setup_info_packet),
- ADDR_SETUP_PROT,
- TL_PROTOCOLID_SETUP,
- TL_SETUP_SIGNO_INFO_MSG);
- if (!info_packet)
- goto exit_nomem;
- info_packet->header.length = sizeof(struct tl_setup_info_msg);
- info_packet->body.driver_type = NDISWAN_DRIVER;
- info_packet->body.major_version = NDISWAN_DRIVER_MAJOR_VERSION;
- info_packet->body.minor_version = NDISWAN_DRIVER_MINOR_VERSION;
- send_packet(hw, PRIO_SETUP, &info_packet->header);
-
- /* Initialization is now complete, so we clear the 'to_setup' flag */
- hw->to_setup = 0;
-
- return;
-
-exit_nomem:
- printk(KERN_ERR IPWIRELESS_PCCARD_NAME
- ": not enough memory to alloc control packet\n");
- hw->to_setup = -1;
-}
-
-static void handle_setup_get_version_rsp(struct ipw_hardware *hw,
- unsigned char vers_no)
-{
- del_timer(&hw->setup_timer);
- hw->initializing = 0;
- printk(KERN_INFO IPWIRELESS_PCCARD_NAME ": card is ready.\n");
-
- if (vers_no == TL_SETUP_VERSION)
- __handle_setup_get_version_rsp(hw);
- else
- printk(KERN_ERR
- IPWIRELESS_PCCARD_NAME
- ": invalid hardware version no %u\n",
- (unsigned int) vers_no);
-}
-
-static void ipw_send_setup_packet(struct ipw_hardware *hw)
-{
- struct ipw_setup_get_version_query_packet *ver_packet;
-
- ver_packet = alloc_ctrl_packet(
- sizeof(struct ipw_setup_get_version_query_packet),
- ADDR_SETUP_PROT, TL_PROTOCOLID_SETUP,
- TL_SETUP_SIGNO_GET_VERSION_QRY);
- ver_packet->header.length = sizeof(struct tl_setup_get_version_qry);
-
- /*
- * Response is handled in handle_received_SETUP_packet
- */
- send_packet(hw, PRIO_SETUP, &ver_packet->header);
-}
-
-static void handle_received_SETUP_packet(struct ipw_hardware *hw,
- unsigned int address,
- unsigned char *data, int len,
- int is_last)
-{
- union ipw_setup_rx_msg *rx_msg = (union ipw_setup_rx_msg *) data;
-
- if (address != ADDR_SETUP_PROT) {
- printk(KERN_INFO IPWIRELESS_PCCARD_NAME
- ": setup packet has bad address %d\n", address);
- return;
- }
-
- switch (rx_msg->sig_no) {
- case TL_SETUP_SIGNO_GET_VERSION_RSP:
- if (hw->to_setup)
- handle_setup_get_version_rsp(hw,
- rx_msg->version_rsp_msg.version);
- break;
-
- case TL_SETUP_SIGNO_OPEN_MSG:
- if (ipwireless_debug) {
- unsigned int channel_idx = rx_msg->open_msg.port_no - 1;
-
- printk(KERN_INFO IPWIRELESS_PCCARD_NAME
- ": OPEN_MSG [channel %u] reply received\n",
- channel_idx);
- }
- break;
-
- case TL_SETUP_SIGNO_INFO_MSG_ACK:
- if (ipwireless_debug)
- printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME
- ": card successfully configured as NDISWAN\n");
- break;
-
- case TL_SETUP_SIGNO_REBOOT_MSG:
- if (hw->to_setup)
- printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME
- ": Setup not completed - ignoring reboot msg\n");
- else {
- struct ipw_setup_reboot_msg_ack *packet;
-
- printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME
- ": Acknowledging REBOOT message\n");
- packet = alloc_ctrl_packet(
- sizeof(struct ipw_setup_reboot_msg_ack),
- ADDR_SETUP_PROT, TL_PROTOCOLID_SETUP,
- TL_SETUP_SIGNO_REBOOT_MSG_ACK);
- packet->header.length =
- sizeof(struct TlSetupRebootMsgAck);
- send_packet(hw, PRIO_SETUP, &packet->header);
- if (hw->reboot_callback)
- hw->reboot_callback(hw->reboot_callback_data);
- }
- break;
-
- default:
- printk(KERN_INFO IPWIRELESS_PCCARD_NAME
- ": unknown setup message %u received\n",
- (unsigned int) rx_msg->sig_no);
- }
-}
-
-static void do_close_hardware(struct ipw_hardware *hw)
-{
- unsigned int irqn;
-
- if (hw->hw_version == HW_VERSION_1) {
- /* Disable TX and RX interrupts. */
- outw(0, hw->base_port + IOIER);
-
- /* Acknowledge any outstanding interrupt requests */
- irqn = inw(hw->base_port + IOIR);
- if (irqn & IR_TXINTR)
- outw(IR_TXINTR, hw->base_port + IOIR);
- if (irqn & IR_RXINTR)
- outw(IR_RXINTR, hw->base_port + IOIR);
-
- synchronize_irq(hw->irq);
- }
-}
-
-struct ipw_hardware *ipwireless_hardware_create(void)
-{
- int i;
- struct ipw_hardware *hw =
- kzalloc(sizeof(struct ipw_hardware), GFP_KERNEL);
-
- if (!hw)
- return NULL;
-
- hw->irq = -1;
- hw->initializing = 1;
- hw->tx_ready = 1;
- hw->rx_bytes_queued = 0;
- hw->rx_pool_size = 0;
- hw->last_memtx_serial = (unsigned short) 0xffff;
- for (i = 0; i < NL_NUM_OF_PRIORITIES; i++)
- INIT_LIST_HEAD(&hw->tx_queue[i]);
-
- INIT_LIST_HEAD(&hw->rx_queue);
- INIT_LIST_HEAD(&hw->rx_pool);
- spin_lock_init(&hw->spinlock);
- tasklet_init(&hw->tasklet, ipwireless_do_tasklet, (unsigned long) hw);
- INIT_WORK(&hw->work_rx, ipw_receive_data_work);
- setup_timer(&hw->setup_timer, ipwireless_setup_timer,
- (unsigned long) hw);
-
- return hw;
-}
-
-void ipwireless_init_hardware_v1(struct ipw_hardware *hw,
- unsigned int base_port,
- void __iomem *attr_memory,
- void __iomem *common_memory,
- int is_v2_card,
- void (*reboot_callback) (void *data),
- void *reboot_callback_data)
-{
- if (hw->removed) {
- hw->removed = 0;
- enable_irq(hw->irq);
- }
- hw->base_port = base_port;
- hw->hw_version = is_v2_card ? HW_VERSION_2 : HW_VERSION_1;
- hw->ll_mtu = hw->hw_version == HW_VERSION_1 ? LL_MTU_V1 : LL_MTU_V2;
- hw->memregs_CCR = (struct MEMCCR __iomem *)
- ((unsigned short __iomem *) attr_memory + 0x200);
- hw->memory_info_regs = (struct MEMINFREG __iomem *) common_memory;
- hw->memreg_tx = &hw->memory_info_regs->memreg_tx_new;
- hw->reboot_callback = reboot_callback;
- hw->reboot_callback_data = reboot_callback_data;
-}
-
-void ipwireless_init_hardware_v2_v3(struct ipw_hardware *hw)
-{
- hw->initializing = 1;
- hw->init_loops = 0;
- printk(KERN_INFO IPWIRELESS_PCCARD_NAME
- ": waiting for card to start up...\n");
- ipwireless_setup_timer((unsigned long) hw);
-}
-
-static void ipwireless_setup_timer(unsigned long data)
-{
- struct ipw_hardware *hw = (struct ipw_hardware *) data;
-
- hw->init_loops++;
-
- if (hw->init_loops == TL_SETUP_MAX_VERSION_QRY &&
- hw->hw_version == HW_VERSION_2 &&
- hw->memreg_tx == &hw->memory_info_regs->memreg_tx_new) {
- printk(KERN_INFO IPWIRELESS_PCCARD_NAME
- ": failed to startup using TX2, trying TX\n");
-
- hw->memreg_tx = &hw->memory_info_regs->memreg_tx_old;
- hw->init_loops = 0;
- }
- /* Give up after a certain number of retries */
- if (hw->init_loops == TL_SETUP_MAX_VERSION_QRY) {
- printk(KERN_INFO IPWIRELESS_PCCARD_NAME
- ": card failed to start up!\n");
- hw->initializing = 0;
- } else {
- /* Do not attempt to write to the board if it is not present. */
- if (is_card_present(hw)) {
- unsigned long flags;
-
- spin_lock_irqsave(&hw->spinlock, flags);
- hw->to_setup = 1;
- hw->tx_ready = 1;
- spin_unlock_irqrestore(&hw->spinlock, flags);
- tasklet_schedule(&hw->tasklet);
- }
-
- mod_timer(&hw->setup_timer,
- jiffies + msecs_to_jiffies(TL_SETUP_VERSION_QRY_TMO));
- }
-}
-
-/*
- * Stop any interrupts from executing so that, once this function returns,
- * other layers of the driver can be sure they won't get any more callbacks.
- * Thus must be called on a proper process context.
- */
-void ipwireless_stop_interrupts(struct ipw_hardware *hw)
-{
- if (!hw->shutting_down) {
- /* Tell everyone we are going down. */
- hw->shutting_down = 1;
- del_timer(&hw->setup_timer);
-
- /* Prevent the hardware from sending any more interrupts */
- do_close_hardware(hw);
- }
-}
-
-void ipwireless_hardware_free(struct ipw_hardware *hw)
-{
- int i;
- struct ipw_rx_packet *rp, *rq;
- struct ipw_tx_packet *tp, *tq;
-
- ipwireless_stop_interrupts(hw);
-
- flush_scheduled_work();
-
- for (i = 0; i < NL_NUM_OF_ADDRESSES; i++)
- if (hw->packet_assembler[i] != NULL)
- kfree(hw->packet_assembler[i]);
-
- for (i = 0; i < NL_NUM_OF_PRIORITIES; i++)
- list_for_each_entry_safe(tp, tq, &hw->tx_queue[i], queue) {
- list_del(&tp->queue);
- kfree(tp);
- }
-
- list_for_each_entry_safe(rp, rq, &hw->rx_queue, queue) {
- list_del(&rp->queue);
- kfree(rp);
- }
-
- list_for_each_entry_safe(rp, rq, &hw->rx_pool, queue) {
- list_del(&rp->queue);
- kfree(rp);
- }
- kfree(hw);
-}
-
-/*
- * Associate the specified network with this hardware, so it will receive events
- * from it.
- */
-void ipwireless_associate_network(struct ipw_hardware *hw,
- struct ipw_network *network)
-{
- hw->network = network;
-}
diff --git a/trunk/drivers/char/pcmcia/ipwireless/hardware.h b/trunk/drivers/char/pcmcia/ipwireless/hardware.h
deleted file mode 100644
index c83190ffb0e7..000000000000
--- a/trunk/drivers/char/pcmcia/ipwireless/hardware.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * IPWireless 3G PCMCIA Network Driver
- *
- * Original code
- * by Stephen Blackheath ,
- * Ben Martel
- *
- * Copyrighted as follows:
- * Copyright (C) 2004 by Symmetric Systems Ltd (NZ)
- *
- * Various driver changes and rewrites, port to new kernels
- * Copyright (C) 2006-2007 Jiri Kosina
- *
- * Misc code cleanups and updates
- * Copyright (C) 2007 David Sterba
- */
-
-#ifndef _IPWIRELESS_CS_HARDWARE_H_
-#define _IPWIRELESS_CS_HARDWARE_H_
-
-#include
-#include
-#include
-
-#define IPW_CONTROL_LINE_CTS 0x0001
-#define IPW_CONTROL_LINE_DCD 0x0002
-#define IPW_CONTROL_LINE_DSR 0x0004
-#define IPW_CONTROL_LINE_RI 0x0008
-#define IPW_CONTROL_LINE_DTR 0x0010
-#define IPW_CONTROL_LINE_RTS 0x0020
-
-struct ipw_hardware;
-struct ipw_network;
-
-struct ipw_hardware *ipwireless_hardware_create(void);
-void ipwireless_hardware_free(struct ipw_hardware *hw);
-irqreturn_t ipwireless_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-int ipwireless_set_DTR(struct ipw_hardware *hw, unsigned int channel_idx,
- int state);
-int ipwireless_set_RTS(struct ipw_hardware *hw, unsigned int channel_idx,
- int state);
-int ipwireless_send_packet(struct ipw_hardware *hw,
- unsigned int channel_idx,
- unsigned char *data,
- unsigned int length,
- void (*packet_sent_callback) (void *cb,
- unsigned int length),
- void *sent_cb_data);
-void ipwireless_associate_network(struct ipw_hardware *hw,
- struct ipw_network *net);
-void ipwireless_stop_interrupts(struct ipw_hardware *hw);
-void ipwireless_init_hardware_v1(struct ipw_hardware *hw,
- unsigned int base_port,
- void __iomem *attr_memory,
- void __iomem *common_memory,
- int is_v2_card,
- void (*reboot_cb) (void *data),
- void *reboot_cb_data);
-void ipwireless_init_hardware_v2_v3(struct ipw_hardware *hw);
-void ipwireless_sleep(unsigned int tenths);
-int ipwireless_dump_hardware_state(char *p, size_t limit,
- struct ipw_hardware *hw);
-
-#endif
diff --git a/trunk/drivers/char/pcmcia/ipwireless/main.c b/trunk/drivers/char/pcmcia/ipwireless/main.c
deleted file mode 100644
index 00c7f8407e3e..000000000000
--- a/trunk/drivers/char/pcmcia/ipwireless/main.c
+++ /dev/null
@@ -1,501 +0,0 @@
-/*
- * IPWireless 3G PCMCIA Network Driver
- *
- * Original code
- * by Stephen Blackheath ,
- * Ben Martel
- *
- * Copyrighted as follows:
- * Copyright (C) 2004 by Symmetric Systems Ltd (NZ)
- *
- * Various driver changes and rewrites, port to new kernels
- * Copyright (C) 2006-2007 Jiri Kosina
- *
- * Misc code cleanups and updates
- * Copyright (C) 2007 David Sterba
- */
-
-#include "hardware.h"
-#include "network.h"
-#include "main.h"
-#include "tty.h"
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include
-#include
-#include
-#include
-#include
-#include
-
-static struct pcmcia_device_id ipw_ids[] = {
- PCMCIA_DEVICE_MANF_CARD(0x02f2, 0x0100),
- PCMCIA_DEVICE_MANF_CARD(0x02f2, 0x0200),
- PCMCIA_DEVICE_NULL
-};
-MODULE_DEVICE_TABLE(pcmcia, ipw_ids);
-
-static void ipwireless_detach(struct pcmcia_device *link);
-
-/*
- * Module params
- */
-/* Debug mode: more verbose, print sent/recv bytes */
-int ipwireless_debug;
-int ipwireless_loopback;
-int ipwireless_out_queue = 1;
-
-module_param_named(debug, ipwireless_debug, int, 0);
-module_param_named(loopback, ipwireless_loopback, int, 0);
-module_param_named(out_queue, ipwireless_out_queue, int, 0);
-MODULE_PARM_DESC(debug, "switch on debug messages [0]");
-MODULE_PARM_DESC(loopback,
- "debug: enable ras_raw channel [0]");
-MODULE_PARM_DESC(out_queue, "debug: set size of outgoing queue [1]");
-
-/* Executes in process context. */
-static void signalled_reboot_work(struct work_struct *work_reboot)
-{
- struct ipw_dev *ipw = container_of(work_reboot, struct ipw_dev,
- work_reboot);
- struct pcmcia_device *link = ipw->link;
- int ret = pccard_reset_card(link->socket);
-
- if (ret != CS_SUCCESS)
- cs_error(link, ResetCard, ret);
-}
-
-static void signalled_reboot_callback(void *callback_data)
-{
- struct ipw_dev *ipw = (struct ipw_dev *) callback_data;
-
- /* Delegate to process context. */
- schedule_work(&ipw->work_reboot);
-}
-
-static int config_ipwireless(struct ipw_dev *ipw)
-{
- struct pcmcia_device *link = ipw->link;
- int ret;
- config_info_t conf;
- tuple_t tuple;
- unsigned short buf[64];
- cisparse_t parse;
- unsigned short cor_value;
- win_req_t request_attr_memory;
- win_req_t request_common_memory;
- memreq_t memreq_attr_memory;
- memreq_t memreq_common_memory;
-
- ipw->is_v2_card = 0;
-
- tuple.Attributes = 0;
- tuple.TupleData = (cisdata_t *) buf;
- tuple.TupleDataMax = sizeof(buf);
- tuple.TupleOffset = 0;
-
- tuple.DesiredTuple = RETURN_FIRST_TUPLE;
-
- ret = pcmcia_get_first_tuple(link, &tuple);
-
- while (ret == 0) {
- ret = pcmcia_get_tuple_data(link, &tuple);
-
- if (ret != CS_SUCCESS) {
- cs_error(link, GetTupleData, ret);
- goto exit0;
- }
- ret = pcmcia_get_next_tuple(link, &tuple);
- }
-
- tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-
- ret = pcmcia_get_first_tuple(link, &tuple);
-
- if (ret != CS_SUCCESS) {
- cs_error(link, GetFirstTuple, ret);
- goto exit0;
- }
-
- ret = pcmcia_get_tuple_data(link, &tuple);
-
- if (ret != CS_SUCCESS) {
- cs_error(link, GetTupleData, ret);
- goto exit0;
- }
-
- ret = pcmcia_parse_tuple(link, &tuple, &parse);
-
- if (ret != CS_SUCCESS) {
- cs_error(link, ParseTuple, ret);
- goto exit0;
- }
-
- link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
- link->io.BasePort1 = parse.cftable_entry.io.win[0].base;
- link->io.NumPorts1 = parse.cftable_entry.io.win[0].len;
- link->io.IOAddrLines = 16;
-
- link->irq.IRQInfo1 = parse.cftable_entry.irq.IRQInfo1;
-
- /* 0x40 causes it to generate level mode interrupts. */
- /* 0x04 enables IREQ pin. */
- cor_value = parse.cftable_entry.index | 0x44;
- link->conf.ConfigIndex = cor_value;
-
- /* IRQ and I/O settings */
- tuple.DesiredTuple = CISTPL_CONFIG;
-
- ret = pcmcia_get_first_tuple(link, &tuple);
-
- if (ret != CS_SUCCESS) {
- cs_error(link, GetFirstTuple, ret);
- goto exit0;
- }
-
- ret = pcmcia_get_tuple_data(link, &tuple);
-
- if (ret != CS_SUCCESS) {
- cs_error(link, GetTupleData, ret);
- goto exit0;
- }
-
- ret = pcmcia_parse_tuple(link, &tuple, &parse);
-
- if (ret != CS_SUCCESS) {
- cs_error(link, GetTupleData, ret);
- goto exit0;
- }
- link->conf.Attributes = CONF_ENABLE_IRQ;
- link->conf.ConfigBase = parse.config.base;
- link->conf.Present = parse.config.rmask[0];
- link->conf.IntType = INT_MEMORY_AND_IO;
-
- link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT;
- link->irq.Handler = ipwireless_interrupt;
- link->irq.Instance = ipw->hardware;
-
- ret = pcmcia_request_io(link, &link->io);
-
- if (ret != CS_SUCCESS) {
- cs_error(link, RequestIO, ret);
- goto exit0;
- }
-
- /* memory settings */
-
- tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-
- ret = pcmcia_get_first_tuple(link, &tuple);
-
- if (ret != CS_SUCCESS) {
- cs_error(link, GetFirstTuple, ret);
- goto exit1;
- }
-
- ret = pcmcia_get_tuple_data(link, &tuple);
-
- if (ret != CS_SUCCESS) {
- cs_error(link, GetTupleData, ret);
- goto exit1;
- }
-
- ret = pcmcia_parse_tuple(link, &tuple, &parse);
-
- if (ret != CS_SUCCESS) {
- cs_error(link, ParseTuple, ret);
- goto exit1;
- }
-
- if (parse.cftable_entry.mem.nwin > 0) {
- request_common_memory.Attributes =
- WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_CM | WIN_ENABLE;
- request_common_memory.Base =
- parse.cftable_entry.mem.win[0].host_addr;
- request_common_memory.Size = parse.cftable_entry.mem.win[0].len;
- if (request_common_memory.Size < 0x1000)
- request_common_memory.Size = 0x1000;
- request_common_memory.AccessSpeed = 0;
-
- ret = pcmcia_request_window(&link, &request_common_memory,
- &ipw->handle_common_memory);
-
- if (ret != CS_SUCCESS) {
- cs_error(link, RequestWindow, ret);
- goto exit1;
- }
-
- memreq_common_memory.CardOffset =
- parse.cftable_entry.mem.win[0].card_addr;
- memreq_common_memory.Page = 0;
-
- ret = pcmcia_map_mem_page(ipw->handle_common_memory,
- &memreq_common_memory);
-
- if (ret != CS_SUCCESS) {
- cs_error(link, MapMemPage, ret);
- goto exit1;
- }
-
- ipw->is_v2_card =
- parse.cftable_entry.mem.win[0].len == 0x100;
-
- ipw->common_memory = ioremap(request_common_memory.Base,
- request_common_memory.Size);
-
- request_attr_memory.Attributes =
- WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_AM | WIN_ENABLE;
- request_attr_memory.Base = 0;
- request_attr_memory.Size = 0; /* this used to be 0x1000 */
- request_attr_memory.AccessSpeed = 0;
-
- ret = pcmcia_request_window(&link, &request_attr_memory,
- &ipw->handle_attr_memory);
-
- if (ret != CS_SUCCESS) {
- cs_error(link, RequestWindow, ret);
- goto exit2;
- }
-
- memreq_attr_memory.CardOffset = 0;
- memreq_attr_memory.Page = 0;
-
- ret = pcmcia_map_mem_page(ipw->handle_attr_memory,
- &memreq_attr_memory);
-
- if (ret != CS_SUCCESS) {
- cs_error(link, MapMemPage, ret);
- goto exit2;
- }
-
- ipw->attr_memory = ioremap(request_attr_memory.Base,
- request_attr_memory.Size);
- }
-
- INIT_WORK(&ipw->work_reboot, signalled_reboot_work);
-
- ipwireless_init_hardware_v1(ipw->hardware, link->io.BasePort1,
- ipw->attr_memory, ipw->common_memory,
- ipw->is_v2_card, signalled_reboot_callback,
- ipw);
-
- ret = pcmcia_request_irq(link, &link->irq);
-
- if (ret != CS_SUCCESS) {
- cs_error(link, RequestIRQ, ret);
- goto exit3;
- }
-
- /* Look up current Vcc */
-
- ret = pcmcia_get_configuration_info(link, &conf);
-
- if (ret != CS_SUCCESS) {
- cs_error(link, GetConfigurationInfo, ret);
- goto exit4;
- }
-
- printk(KERN_INFO IPWIRELESS_PCCARD_NAME ": Card type %s\n",
- ipw->is_v2_card ? "V2/V3" : "V1");
- printk(KERN_INFO IPWIRELESS_PCCARD_NAME
- ": I/O ports 0x%04x-0x%04x, irq %d\n",
- (unsigned int) link->io.BasePort1,
- (unsigned int) (link->io.BasePort1 +
- link->io.NumPorts1 - 1),
- (unsigned int) link->irq.AssignedIRQ);
- if (ipw->attr_memory && ipw->common_memory)
- printk(KERN_INFO IPWIRELESS_PCCARD_NAME
- ": attr memory 0x%08lx-0x%08lx, "
- "common memory 0x%08lx-0x%08lx\n",
- request_attr_memory.Base,
- request_attr_memory.Base
- + request_attr_memory.Size - 1,
- request_common_memory.Base,
- request_common_memory.Base
- + request_common_memory.Size - 1);
-
- ipw->network = ipwireless_network_create(ipw->hardware);
- if (!ipw->network)
- goto exit3;
-
- ipw->tty = ipwireless_tty_create(ipw->hardware, ipw->network,
- ipw->nodes);
- if (!ipw->tty)
- goto exit3;
-
- ipwireless_init_hardware_v2_v3(ipw->hardware);
-
- /*
- * Do the RequestConfiguration last, because it enables interrupts.
- * Then we don't get any interrupts before we're ready for them.
- */
- ret = pcmcia_request_configuration(link, &link->conf);
-
- if (ret != CS_SUCCESS) {
- cs_error(link, RequestConfiguration, ret);
- goto exit4;
- }
-
- link->dev_node = &ipw->nodes[0];
-
- return 0;
-
-exit4:
- pcmcia_disable_device(link);
-exit3:
- if (ipw->attr_memory) {
- iounmap(ipw->attr_memory);
- pcmcia_release_window(ipw->handle_attr_memory);
- pcmcia_disable_device(link);
- }
-exit2:
- if (ipw->common_memory) {
- iounmap(ipw->common_memory);
- pcmcia_release_window(ipw->handle_common_memory);
- }
-exit1:
- pcmcia_disable_device(link);
-exit0:
- return -1;
-}
-
-static void release_ipwireless(struct ipw_dev *ipw)
-{
- struct pcmcia_device *link = ipw->link;
-
- pcmcia_disable_device(link);
-
- if (ipw->common_memory)
- iounmap(ipw->common_memory);
- if (ipw->attr_memory)
- iounmap(ipw->attr_memory);
- if (ipw->common_memory)
- pcmcia_release_window(ipw->handle_common_memory);
- if (ipw->attr_memory)
- pcmcia_release_window(ipw->handle_attr_memory);
- pcmcia_disable_device(link);
-}
-
-/*
- * ipwireless_attach() creates an "instance" of the driver, allocating
- * local data structures for one device (one interface). The device
- * is registered with Card Services.
- *
- * The pcmcia_device structure is initialized, but we don't actually
- * configure the card at this point -- we wait until we receive a
- * card insertion event.
- */
-static int ipwireless_attach(struct pcmcia_device *link)
-{
- struct ipw_dev *ipw;
- int ret;
-
- ipw = kzalloc(sizeof(struct ipw_dev), GFP_KERNEL);
- if (!ipw)
- return -ENOMEM;
-
- ipw->link = link;
- link->priv = ipw;
- link->irq.Instance = ipw;
-
- /* Link this device into our device list. */
- link->dev_node = &ipw->nodes[0];
-
- ipw->hardware = ipwireless_hardware_create();
- if (!ipw->hardware) {
- kfree(ipw);
- return -ENOMEM;
- }
- /* RegisterClient will call config_ipwireless */
-
- ret = config_ipwireless(ipw);
-
- if (ret != 0) {
- cs_error(link, RegisterClient, ret);
- ipwireless_detach(link);
- return ret;
- }
-
- return 0;
-}
-
-/*
- * This deletes a driver "instance". The device is de-registered with
- * Card Services. If it has been released, all local data structures
- * are freed. Otherwise, the structures will be freed when the device
- * is released.
- */
-static void ipwireless_detach(struct pcmcia_device *link)
-{
- struct ipw_dev *ipw = link->priv;
-
- release_ipwireless(ipw);
-
- /* Break the link with Card Services */
- if (link)
- pcmcia_disable_device(link);
-
- if (ipw->tty != NULL)
- ipwireless_tty_free(ipw->tty);
- if (ipw->network != NULL)
- ipwireless_network_free(ipw->network);
- if (ipw->hardware != NULL)
- ipwireless_hardware_free(ipw->hardware);
- kfree(ipw);
-}
-
-static struct pcmcia_driver me = {
- .owner = THIS_MODULE,
- .probe = ipwireless_attach,
- .remove = ipwireless_detach,
- .drv = { .name = IPWIRELESS_PCCARD_NAME },
- .id_table = ipw_ids
-};
-
-/*
- * Module insertion : initialisation of the module.
- * Register the card with cardmgr...
- */
-static int __init init_ipwireless(void)
-{
- int ret;
-
- printk(KERN_INFO IPWIRELESS_PCCARD_NAME " "
- IPWIRELESS_PCMCIA_VERSION " by " IPWIRELESS_PCMCIA_AUTHOR "\n");
-
- ret = ipwireless_tty_init();
- if (ret != 0)
- return ret;
-
- ret = pcmcia_register_driver(&me);
- if (ret != 0)
- ipwireless_tty_release();
-
- return ret;
-}
-
-/*
- * Module removal
- */
-static void __exit exit_ipwireless(void)
-{
- printk(KERN_INFO IPWIRELESS_PCCARD_NAME " "
- IPWIRELESS_PCMCIA_VERSION " removed\n");
-
- pcmcia_unregister_driver(&me);
- ipwireless_tty_release();
-}
-
-module_init(init_ipwireless);
-module_exit(exit_ipwireless);
-
-MODULE_AUTHOR(IPWIRELESS_PCMCIA_AUTHOR);
-MODULE_DESCRIPTION(IPWIRELESS_PCCARD_NAME " " IPWIRELESS_PCMCIA_VERSION);
-MODULE_LICENSE("GPL");
diff --git a/trunk/drivers/char/pcmcia/ipwireless/main.h b/trunk/drivers/char/pcmcia/ipwireless/main.h
deleted file mode 100644
index 1bfdcc8d47d6..000000000000
--- a/trunk/drivers/char/pcmcia/ipwireless/main.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * IPWireless 3G PCMCIA Network Driver
- *
- * Original code
- * by Stephen Blackheath ,
- * Ben Martel
- *
- * Copyrighted as follows:
- * Copyright (C) 2004 by Symmetric Systems Ltd (NZ)
- *
- * Various driver changes and rewrites, port to new kernels
- * Copyright (C) 2006-2007 Jiri Kosina
- *
- * Misc code cleanups and updates
- * Copyright (C) 2007 David Sterba
- */
-
-#ifndef _IPWIRELESS_CS_H_
-#define _IPWIRELESS_CS_H_
-
-#include
-#include
-
-#include
-#include
-#include
-#include
-
-#include "hardware.h"
-
-#define IPWIRELESS_PCCARD_NAME "ipwireless"
-#define IPWIRELESS_PCMCIA_VERSION "1.1"
-#define IPWIRELESS_PCMCIA_AUTHOR \
- "Stephen Blackheath, Ben Martel, Jiri Kosina and David Sterba"
-
-#define IPWIRELESS_TX_QUEUE_SIZE 262144
-#define IPWIRELESS_RX_QUEUE_SIZE 262144
-
-#define IPWIRELESS_STATE_DEBUG
-
-struct ipw_hardware;
-struct ipw_network;
-struct ipw_tty;
-
-struct ipw_dev {
- struct pcmcia_device *link;
- int is_v2_card;
- window_handle_t handle_attr_memory;
- void __iomem *attr_memory;
- window_handle_t handle_common_memory;
- void __iomem *common_memory;
- dev_node_t nodes[2];
- /* Reference to attribute memory, containing CIS data */
- void *attribute_memory;
-
- /* Hardware context */
- struct ipw_hardware *hardware;
- /* Network layer context */
- struct ipw_network *network;
- /* TTY device context */
- struct ipw_tty *tty;
- struct work_struct work_reboot;
-};
-
-/* Module parametres */
-extern int ipwireless_debug;
-extern int ipwireless_loopback;
-extern int ipwireless_out_queue;
-
-#endif
diff --git a/trunk/drivers/char/pcmcia/ipwireless/network.c b/trunk/drivers/char/pcmcia/ipwireless/network.c
deleted file mode 100644
index ff35230058d3..000000000000
--- a/trunk/drivers/char/pcmcia/ipwireless/network.c
+++ /dev/null
@@ -1,512 +0,0 @@
-/*
- * IPWireless 3G PCMCIA Network Driver
- *
- * Original code
- * by Stephen Blackheath ,
- * Ben Martel
- *
- * Copyrighted as follows:
- * Copyright (C) 2004 by Symmetric Systems Ltd (NZ)
- *
- * Various driver changes and rewrites, port to new kernels
- * Copyright (C) 2006-2007 Jiri Kosina
- *
- * Misc code cleanups and updates
- * Copyright (C) 2007 David Sterba
- */
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include "network.h"
-#include "hardware.h"
-#include "main.h"
-#include "tty.h"
-
-#define MAX_OUTGOING_PACKETS_QUEUED ipwireless_out_queue
-#define MAX_ASSOCIATED_TTYS 2
-
-#define SC_RCV_BITS (SC_RCV_B7_1|SC_RCV_B7_0|SC_RCV_ODDP|SC_RCV_EVNP)
-
-struct ipw_network {
- /* Hardware context, used for calls to hardware layer. */
- struct ipw_hardware *hardware;
- /* Context for kernel 'generic_ppp' functionality */
- struct ppp_channel *ppp_channel;
- /* tty context connected with IPW console */
- struct ipw_tty *associated_ttys[NO_OF_IPW_CHANNELS][MAX_ASSOCIATED_TTYS];
- /* True if ppp needs waking up once we're ready to xmit */
- int ppp_blocked;
- /* Number of packets queued up in hardware module. */
- int outgoing_packets_queued;
- /* Spinlock to avoid interrupts during shutdown */
- spinlock_t spinlock;
- struct mutex close_lock;
-
- /* PPP ioctl data, not actually used anywere */
- unsigned int flags;
- unsigned int rbits;
- u32 xaccm[8];
- u32 raccm;
- int mru;
-
- int shutting_down;
- unsigned int ras_control_lines;
-
- struct work_struct work_go_online;
- struct work_struct work_go_offline;
-};
-
-
-#ifdef IPWIRELESS_STATE_DEBUG
-int ipwireless_dump_network_state(char *p, size_t limit,
- struct ipw_network *network)
-{
- return snprintf(p, limit,
- "debug: ppp_blocked=%d\n"
- "debug: outgoing_packets_queued=%d\n"
- "debug: network.shutting_down=%d\n",
- network->ppp_blocked,
- network->outgoing_packets_queued,
- network->shutting_down);
-}
-#endif
-
-static void notify_packet_sent(void *callback_data, unsigned int packet_length)
-{
- struct ipw_network *network = callback_data;
- unsigned long flags;
-
- spin_lock_irqsave(&network->spinlock, flags);
- network->outgoing_packets_queued--;
- if (network->ppp_channel != NULL) {
- if (network->ppp_blocked) {
- network->ppp_blocked = 0;
- spin_unlock_irqrestore(&network->spinlock, flags);
- ppp_output_wakeup(network->ppp_channel);
- if (ipwireless_debug)
- printk(KERN_INFO IPWIRELESS_PCCARD_NAME
- ": ppp unblocked\n");
- } else
- spin_unlock_irqrestore(&network->spinlock, flags);
- } else
- spin_unlock_irqrestore(&network->spinlock, flags);
-}
-
-/*
- * Called by the ppp system when it has a packet to send to the hardware.
- */
-static int ipwireless_ppp_start_xmit(struct ppp_channel *ppp_channel,
- struct sk_buff *skb)
-{
- struct ipw_network *network = ppp_channel->private;
- unsigned long flags;
-
- spin_lock_irqsave(&network->spinlock, flags);
- if (network->outgoing_packets_queued < MAX_OUTGOING_PACKETS_QUEUED) {
- unsigned char *buf;
- static unsigned char header[] = {
- PPP_ALLSTATIONS, /* 0xff */
- PPP_UI, /* 0x03 */
- };
- int ret;
-
- network->outgoing_packets_queued++;
- spin_unlock_irqrestore(&network->spinlock, flags);
-
- /*
- * If we have the requested amount of headroom in the skb we
- * were handed, then we can add the header efficiently.
- */
- if (skb_headroom(skb) >= 2) {
- memcpy(skb_push(skb, 2), header, 2);
- ret = ipwireless_send_packet(network->hardware,
- IPW_CHANNEL_RAS, skb->data,
- skb->len,
- notify_packet_sent,
- network);
- if (ret == -1) {
- skb_pull(skb, 2);
- return 0;
- }
- } else {
- /* Otherwise (rarely) we do it inefficiently. */
- buf = kmalloc(skb->len + 2, GFP_ATOMIC);
- if (!buf)
- return 0;
- memcpy(buf + 2, skb->data, skb->len);
- memcpy(buf, header, 2);
- ret = ipwireless_send_packet(network->hardware,
- IPW_CHANNEL_RAS, buf,
- skb->len + 2,
- notify_packet_sent,
- network);
- kfree(buf);
- if (ret == -1)
- return 0;
- }
- kfree_skb(skb);
- return 1;
- } else {
- /*
- * Otherwise reject the packet, and flag that the ppp system
- * needs to be unblocked once we are ready to send.
- */
- network->ppp_blocked = 1;
- spin_unlock_irqrestore(&network->spinlock, flags);
- return 0;
- }
-}
-
-/* Handle an ioctl call that has come in via ppp. (copy of ppp_async_ioctl() */
-static int ipwireless_ppp_ioctl(struct ppp_channel *ppp_channel,
- unsigned int cmd, unsigned long arg)
-{
- struct ipw_network *network = ppp_channel->private;
- int err, val;
- u32 accm[8];
- int __user *user_arg = (int __user *) arg;
-
- err = -EFAULT;
- switch (cmd) {
- case PPPIOCGFLAGS:
- val = network->flags | network->rbits;
- if (put_user(val, user_arg))
- break;
- err = 0;
- break;
-
- case PPPIOCSFLAGS:
- if (get_user(val, user_arg))
- break;
- network->flags = val & ~SC_RCV_BITS;
- network->rbits = val & SC_RCV_BITS;
- err = 0;
- break;
-
- case PPPIOCGASYNCMAP:
- if (put_user(network->xaccm[0], user_arg))
- break;
- err = 0;
- break;
-
- case PPPIOCSASYNCMAP:
- if (get_user(network->xaccm[0], user_arg))
- break;
- err = 0;
- break;
-
- case PPPIOCGRASYNCMAP:
- if (put_user(network->raccm, user_arg))
- break;
- err = 0;
- break;
-
- case PPPIOCSRASYNCMAP:
- if (get_user(network->raccm, user_arg))
- break;
- err = 0;
- break;
-
- case PPPIOCGXASYNCMAP:
- if (copy_to_user((void __user *) arg, network->xaccm,
- sizeof(network->xaccm)))
- break;
- err = 0;
- break;
-
- case PPPIOCSXASYNCMAP:
- if (copy_from_user(accm, (void __user *) arg, sizeof(accm)))
- break;
- accm[2] &= ~0x40000000U; /* can't escape 0x5e */
- accm[3] |= 0x60000000U; /* must escape 0x7d, 0x7e */
- memcpy(network->xaccm, accm, sizeof(network->xaccm));
- err = 0;
- break;
-
- case PPPIOCGMRU:
- if (put_user(network->mru, user_arg))
- break;
- err = 0;
- break;
-
- case PPPIOCSMRU:
- if (get_user(val, user_arg))
- break;
- if (val < PPP_MRU)
- val = PPP_MRU;
- network->mru = val;
- err = 0;
- break;
-
- default:
- err = -ENOTTY;
- }
-
- return err;
-}
-
-static struct ppp_channel_ops ipwireless_ppp_channel_ops = {
- .start_xmit = ipwireless_ppp_start_xmit,
- .ioctl = ipwireless_ppp_ioctl
-};
-
-static void do_go_online(struct work_struct *work_go_online)
-{
- struct ipw_network *network =
- container_of(work_go_online, struct ipw_network,
- work_go_online);
- unsigned long flags;
-
- spin_lock_irqsave(&network->spinlock, flags);
- if (!network->ppp_channel) {
- struct ppp_channel *channel;
-
- spin_unlock_irqrestore(&network->spinlock, flags);
- channel = kzalloc(sizeof(struct ppp_channel), GFP_KERNEL);
- if (!channel) {
- printk(KERN_ERR IPWIRELESS_PCCARD_NAME
- ": unable to allocate PPP channel\n");
- return;
- }
- channel->private = network;
- channel->mtu = 16384; /* Wild guess */
- channel->hdrlen = 2;
- channel->ops = &ipwireless_ppp_channel_ops;
-
- network->flags = 0;
- network->rbits = 0;
- network->mru = PPP_MRU;
- memset(network->xaccm, 0, sizeof(network->xaccm));
- network->xaccm[0] = ~0U;
- network->xaccm[3] = 0x60000000U;
- network->raccm = ~0U;
- ppp_register_channel(channel);
- spin_lock_irqsave(&network->spinlock, flags);
- network->ppp_channel = channel;
- }
- spin_unlock_irqrestore(&network->spinlock, flags);
-}
-
-static void do_go_offline(struct work_struct *work_go_offline)
-{
- struct ipw_network *network =
- container_of(work_go_offline, struct ipw_network,
- work_go_offline);
- unsigned long flags;
-
- mutex_lock(&network->close_lock);
- spin_lock_irqsave(&network->spinlock, flags);
- if (network->ppp_channel != NULL) {
- struct ppp_channel *channel = network->ppp_channel;
-
- network->ppp_channel = NULL;
- spin_unlock_irqrestore(&network->spinlock, flags);
- mutex_unlock(&network->close_lock);
- ppp_unregister_channel(channel);
- } else {
- spin_unlock_irqrestore(&network->spinlock, flags);
- mutex_unlock(&network->close_lock);
- }
-}
-
-void ipwireless_network_notify_control_line_change(struct ipw_network *network,
- unsigned int channel_idx,
- unsigned int control_lines,
- unsigned int changed_mask)
-{
- int i;
-
- if (channel_idx == IPW_CHANNEL_RAS)
- network->ras_control_lines = control_lines;
-
- for (i = 0; i < MAX_ASSOCIATED_TTYS; i++) {
- struct ipw_tty *tty =
- network->associated_ttys[channel_idx][i];
-
- /*
- * If it's associated with a tty (other than the RAS channel
- * when we're online), then send the data to that tty. The RAS
- * channel's data is handled above - it always goes through
- * ppp_generic.
- */
- if (tty)
- ipwireless_tty_notify_control_line_change(tty,
- channel_idx,
- control_lines,
- changed_mask);
- }
-}
-
-/*
- * Some versions of firmware stuff packets with 0xff 0x03 (PPP: ALLSTATIONS, UI)
- * bytes, which are required on sent packet, but not always present on received
- * packets
- */
-static struct sk_buff *ipw_packet_received_skb(unsigned char *data,
- unsigned int length)
-{
- struct sk_buff *skb;
-
- if (length > 2 && data[0] == PPP_ALLSTATIONS && data[1] == PPP_UI) {
- length -= 2;
- data += 2;
- }
-
- skb = dev_alloc_skb(length + 4);
- skb_reserve(skb, 2);
- memcpy(skb_put(skb, length), data, length);
-
- return skb;
-}
-
-void ipwireless_network_packet_received(struct ipw_network *network,
- unsigned int channel_idx,
- unsigned char *data,
- unsigned int length)
-{
- int i;
- unsigned long flags;
-
- for (i = 0; i < MAX_ASSOCIATED_TTYS; i++) {
- struct ipw_tty *tty = network->associated_ttys[channel_idx][i];
-
- /*
- * If it's associated with a tty (other than the RAS channel
- * when we're online), then send the data to that tty. The RAS
- * channel's data is handled above - it always goes through
- * ppp_generic.
- */
- if (tty && channel_idx == IPW_CHANNEL_RAS
- && (network->ras_control_lines &
- IPW_CONTROL_LINE_DCD) != 0
- && ipwireless_tty_is_modem(tty)) {
- /*
- * If data came in on the RAS channel and this tty is
- * the modem tty, and we are online, then we send it to
- * the PPP layer.
- */
- mutex_lock(&network->close_lock);
- spin_lock_irqsave(&network->spinlock, flags);
- if (network->ppp_channel != NULL) {
- struct sk_buff *skb;
-
- spin_unlock_irqrestore(&network->spinlock,
- flags);
-
- /* Send the data to the ppp_generic module. */
- skb = ipw_packet_received_skb(data, length);
- ppp_input(network->ppp_channel, skb);
- } else
- spin_unlock_irqrestore(&network->spinlock,
- flags);
- mutex_unlock(&network->close_lock);
- }
- /* Otherwise we send it out the tty. */
- else
- ipwireless_tty_received(tty, data, length);
- }
-}
-
-struct ipw_network *ipwireless_network_create(struct ipw_hardware *hw)
-{
- struct ipw_network *network =
- kzalloc(sizeof(struct ipw_network), GFP_ATOMIC);
-
- if (!network)
- return NULL;
-
- spin_lock_init(&network->spinlock);
- mutex_init(&network->close_lock);
-
- network->hardware = hw;
-
- INIT_WORK(&network->work_go_online, do_go_online);
- INIT_WORK(&network->work_go_offline, do_go_offline);
-
- ipwireless_associate_network(hw, network);
-
- return network;
-}
-
-void ipwireless_network_free(struct ipw_network *network)
-{
- network->shutting_down = 1;
-
- ipwireless_ppp_close(network);
- flush_scheduled_work();
-
- ipwireless_stop_interrupts(network->hardware);
- ipwireless_associate_network(network->hardware, NULL);
-
- kfree(network);
-}
-
-void ipwireless_associate_network_tty(struct ipw_network *network,
- unsigned int channel_idx,
- struct ipw_tty *tty)
-{
- int i;
-
- for (i = 0; i < MAX_ASSOCIATED_TTYS; i++)
- if (network->associated_ttys[channel_idx][i] == NULL) {
- network->associated_ttys[channel_idx][i] = tty;
- break;
- }
-}
-
-void ipwireless_disassociate_network_ttys(struct ipw_network *network,
- unsigned int channel_idx)
-{
- int i;
-
- for (i = 0; i < MAX_ASSOCIATED_TTYS; i++)
- network->associated_ttys[channel_idx][i] = NULL;
-}
-
-void ipwireless_ppp_open(struct ipw_network *network)
-{
- if (ipwireless_debug)
- printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME ": online\n");
- schedule_work(&network->work_go_online);
-}
-
-void ipwireless_ppp_close(struct ipw_network *network)
-{
- /* Disconnect from the wireless network. */
- if (ipwireless_debug)
- printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME ": offline\n");
- schedule_work(&network->work_go_offline);
-}
-
-int ipwireless_ppp_channel_index(struct ipw_network *network)
-{
- int ret = -1;
- unsigned long flags;
-
- spin_lock_irqsave(&network->spinlock, flags);
- if (network->ppp_channel != NULL)
- ret = ppp_channel_index(network->ppp_channel);
- spin_unlock_irqrestore(&network->spinlock, flags);
-
- return ret;
-}
-
-int ipwireless_ppp_unit_number(struct ipw_network *network)
-{
- int ret = -1;
- unsigned long flags;
-
- spin_lock_irqsave(&network->spinlock, flags);
- if (network->ppp_channel != NULL)
- ret = ppp_unit_number(network->ppp_channel);
- spin_unlock_irqrestore(&network->spinlock, flags);
-
- return ret;
-}
diff --git a/trunk/drivers/char/pcmcia/ipwireless/network.h b/trunk/drivers/char/pcmcia/ipwireless/network.h
deleted file mode 100644
index b0e1e952fd14..000000000000
--- a/trunk/drivers/char/pcmcia/ipwireless/network.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * IPWireless 3G PCMCIA Network Driver
- *
- * Original code
- * by Stephen Blackheath ,
- * Ben Martel
- *
- * Copyrighted as follows:
- * Copyright (C) 2004 by Symmetric Systems Ltd (NZ)
- *
- * Various driver changes and rewrites, port to new kernels
- * Copyright (C) 2006-2007 Jiri Kosina
- *
- * Misc code cleanups and updates
- * Copyright (C) 2007 David Sterba
- */
-
-#ifndef _IPWIRELESS_CS_NETWORK_H_
-#define _IPWIRELESS_CS_NETWORK_H_
-
-#include
-
-struct ipw_network;
-struct ipw_tty;
-struct ipw_hardware;
-
-/* Definitions of the different channels on the PCMCIA UE */
-#define IPW_CHANNEL_RAS 0
-#define IPW_CHANNEL_DIALLER 1
-#define IPW_CHANNEL_CONSOLE 2
-#define NO_OF_IPW_CHANNELS 5
-
-void ipwireless_network_notify_control_line_change(struct ipw_network *net,
- unsigned int channel_idx, unsigned int control_lines,
- unsigned int control_mask);
-void ipwireless_network_packet_received(struct ipw_network *net,
- unsigned int channel_idx, unsigned char *data,
- unsigned int length);
-struct ipw_network *ipwireless_network_create(struct ipw_hardware *hw);
-void ipwireless_network_free(struct ipw_network *net);
-void ipwireless_associate_network_tty(struct ipw_network *net,
- unsigned int channel_idx, struct ipw_tty *tty);
-void ipwireless_disassociate_network_ttys(struct ipw_network *net,
- unsigned int channel_idx);
-
-void ipwireless_ppp_open(struct ipw_network *net);
-
-void ipwireless_ppp_close(struct ipw_network *net);
-int ipwireless_ppp_channel_index(struct ipw_network *net);
-int ipwireless_ppp_unit_number(struct ipw_network *net);
-
-int ipwireless_dump_network_state(char *p, size_t limit,
- struct ipw_network *net);
-
-#endif
diff --git a/trunk/drivers/char/pcmcia/ipwireless/setup_protocol.h b/trunk/drivers/char/pcmcia/ipwireless/setup_protocol.h
deleted file mode 100644
index 9d6bcc77c73c..000000000000
--- a/trunk/drivers/char/pcmcia/ipwireless/setup_protocol.h
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * IPWireless 3G PCMCIA Network Driver
- *
- * Original code
- * by Stephen Blackheath ,
- * Ben Martel
- *
- * Copyrighted as follows:
- * Copyright (C) 2004 by Symmetric Systems Ltd (NZ)
- *
- * Various driver changes and rewrites, port to new kernels
- * Copyright (C) 2006-2007 Jiri Kosina
- *
- * Misc code cleanups and updates
- * Copyright (C) 2007 David Sterba
- */
-
-#ifndef _IPWIRELESS_CS_SETUP_PROTOCOL_H_
-#define _IPWIRELESS_CS_SETUP_PROTOCOL_H_
-
-/* Version of the setup protocol and transport protocols */
-#define TL_SETUP_VERSION 1
-
-#define TL_SETUP_VERSION_QRY_TMO 1000
-#define TL_SETUP_MAX_VERSION_QRY 30
-
-/* Message numbers 0-9 are obsoleted and must not be reused! */
-#define TL_SETUP_SIGNO_GET_VERSION_QRY 10
-#define TL_SETUP_SIGNO_GET_VERSION_RSP 11
-#define TL_SETUP_SIGNO_CONFIG_MSG 12
-#define TL_SETUP_SIGNO_CONFIG_DONE_MSG 13
-#define TL_SETUP_SIGNO_OPEN_MSG 14
-#define TL_SETUP_SIGNO_CLOSE_MSG 15
-
-#define TL_SETUP_SIGNO_INFO_MSG 20
-#define TL_SETUP_SIGNO_INFO_MSG_ACK 21
-
-#define TL_SETUP_SIGNO_REBOOT_MSG 22
-#define TL_SETUP_SIGNO_REBOOT_MSG_ACK 23
-
-/* Synchronous start-messages */
-struct tl_setup_get_version_qry {
- unsigned char sig_no; /* TL_SETUP_SIGNO_GET_VERSION_QRY */
-} __attribute__ ((__packed__));
-
-struct tl_setup_get_version_rsp {
- unsigned char sig_no; /* TL_SETUP_SIGNO_GET_VERSION_RSP */
- unsigned char version; /* TL_SETUP_VERSION */
-} __attribute__ ((__packed__));
-
-struct tl_setup_config_msg {
- unsigned char sig_no; /* TL_SETUP_SIGNO_CONFIG_MSG */
- unsigned char port_no;
- unsigned char prio_data;
- unsigned char prio_ctrl;
-} __attribute__ ((__packed__));
-
-struct tl_setup_config_done_msg {
- unsigned char sig_no; /* TL_SETUP_SIGNO_CONFIG_DONE_MSG */
-} __attribute__ ((__packed__));
-
-/* Asyncronous messages */
-struct tl_setup_open_msg {
- unsigned char sig_no; /* TL_SETUP_SIGNO_OPEN_MSG */
- unsigned char port_no;
-} __attribute__ ((__packed__));
-
-struct tl_setup_close_msg {
- unsigned char sig_no; /* TL_SETUP_SIGNO_CLOSE_MSG */
- unsigned char port_no;
-} __attribute__ ((__packed__));
-
-/* Driver type - for use in tl_setup_info_msg.driver_type */
-#define COMM_DRIVER 0
-#define NDISWAN_DRIVER 1
-#define NDISWAN_DRIVER_MAJOR_VERSION 2
-#define NDISWAN_DRIVER_MINOR_VERSION 0
-
-/*
- * It should not matter when this message comes over as we just store the
- * results and send the ACK.
- */
-struct tl_setup_info_msg {
- unsigned char sig_no; /* TL_SETUP_SIGNO_INFO_MSG */
- unsigned char driver_type;
- unsigned char major_version;
- unsigned char minor_version;
-} __attribute__ ((__packed__));
-
-struct tl_setup_info_msgAck {
- unsigned char sig_no; /* TL_SETUP_SIGNO_INFO_MSG_ACK */
-} __attribute__ ((__packed__));
-
-struct TlSetupRebootMsgAck {
- unsigned char sig_no; /* TL_SETUP_SIGNO_REBOOT_MSG_ACK */
-} __attribute__ ((__packed__));
-
-/* Define a union of all the msgs that the driver can receive from the card.*/
-union ipw_setup_rx_msg {
- unsigned char sig_no;
- struct tl_setup_get_version_rsp version_rsp_msg;
- struct tl_setup_open_msg open_msg;
- struct tl_setup_close_msg close_msg;
- struct tl_setup_info_msg InfoMsg;
- struct tl_setup_info_msgAck info_msg_ack;
-} __attribute__ ((__packed__));
-
-#endif /* _IPWIRELESS_CS_SETUP_PROTOCOL_H_ */
diff --git a/trunk/drivers/char/pcmcia/ipwireless/tty.c b/trunk/drivers/char/pcmcia/ipwireless/tty.c
deleted file mode 100644
index 42f3815c5ce3..000000000000
--- a/trunk/drivers/char/pcmcia/ipwireless/tty.c
+++ /dev/null
@@ -1,688 +0,0 @@
-/*
- * IPWireless 3G PCMCIA Network Driver
- *
- * Original code
- * by Stephen Blackheath ,
- * Ben Martel
- *
- * Copyrighted as follows:
- * Copyright (C) 2004 by Symmetric Systems Ltd (NZ)
- *
- * Various driver changes and rewrites, port to new kernels
- * Copyright (C) 2006-2007 Jiri Kosina
- *
- * Misc code cleanups and updates
- * Copyright (C) 2007 David Sterba
- */
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include "tty.h"
-#include "network.h"
-#include "hardware.h"
-#include "main.h"
-
-#define IPWIRELESS_PCMCIA_START (0)
-#define IPWIRELESS_PCMCIA_MINORS (24)
-#define IPWIRELESS_PCMCIA_MINOR_RANGE (8)
-
-#define TTYTYPE_MODEM (0)
-#define TTYTYPE_MONITOR (1)
-#define TTYTYPE_RAS_RAW (2)
-
-struct ipw_tty {
- int index;
- struct ipw_hardware *hardware;
- unsigned int channel_idx;
- unsigned int secondary_channel_idx;
- int tty_type;
- struct ipw_network *network;
- struct tty_struct *linux_tty;
- int open_count;
- unsigned int control_lines;
- struct mutex ipw_tty_mutex;
- int tx_bytes_queued;
- int closing;
-};
-
-static struct ipw_tty *ttys[IPWIRELESS_PCMCIA_MINORS];
-
-static struct tty_driver *ipw_tty_driver;
-
-static char *tty_type_name(int tty_type)
-{
- static char *channel_names[] = {
- "modem",
- "monitor",
- "RAS-raw"
- };
-
- return channel_names[tty_type];
-}
-
-static void report_registering(struct ipw_tty *tty)
-{
- char *iftype = tty_type_name(tty->tty_type);
-
- printk(KERN_INFO IPWIRELESS_PCCARD_NAME
- ": registering %s device ttyIPWp%d\n", iftype, tty->index);
-}
-
-static void report_deregistering(struct ipw_tty *tty)
-{
- char *iftype = tty_type_name(tty->tty_type);
-
- printk(KERN_INFO IPWIRELESS_PCCARD_NAME
- ": deregistering %s device ttyIPWp%d\n", iftype,
- tty->index);
-}
-
-static struct ipw_tty *get_tty(int minor)
-{
- if (minor < ipw_tty_driver->minor_start
- || minor >= ipw_tty_driver->minor_start +
- IPWIRELESS_PCMCIA_MINORS)
- return NULL;
- else {
- int minor_offset = minor - ipw_tty_driver->minor_start;
-
- /*
- * The 'ras_raw' channel is only available when 'loopback' mode
- * is enabled.
- * Number of minor starts with 16 (_RANGE * _RAS_RAW).
- */
- if (!ipwireless_loopback &&
- minor_offset >=
- IPWIRELESS_PCMCIA_MINOR_RANGE * TTYTYPE_RAS_RAW)
- return NULL;
-
- return ttys[minor_offset];
- }
-}
-
-static int ipw_open(struct tty_struct *linux_tty, struct file *filp)
-{
- int minor = linux_tty->index;
- struct ipw_tty *tty = get_tty(minor);
-
- if (!tty)
- return -ENODEV;
-
- mutex_lock(&tty->ipw_tty_mutex);
-
- if (tty->closing) {
- mutex_unlock(&tty->ipw_tty_mutex);
- return -ENODEV;
- }
- if (tty->open_count == 0)
- tty->tx_bytes_queued = 0;
-
- tty->open_count++;
-
- tty->linux_tty = linux_tty;
- linux_tty->driver_data = tty;
- linux_tty->low_latency = 1;
-
- if (tty->tty_type == TTYTYPE_MODEM)
- ipwireless_ppp_open(tty->network);
-
- mutex_unlock(&tty->ipw_tty_mutex);
-
- return 0;
-}
-
-static void do_ipw_close(struct ipw_tty *tty)
-{
- tty->open_count--;
-
- if (tty->open_count == 0) {
- struct tty_struct *linux_tty = tty->linux_tty;
-
- if (linux_tty != NULL) {
- tty->linux_tty = NULL;
- linux_tty->driver_data = NULL;
-
- if (tty->tty_type == TTYTYPE_MODEM)
- ipwireless_ppp_close(tty->network);
- }
- }
-}
-
-static void ipw_hangup(struct tty_struct *linux_tty)
-{
- struct ipw_tty *tty = linux_tty->driver_data;
-
- if (!tty)
- return;
-
- mutex_lock(&tty->ipw_tty_mutex);
- if (tty->open_count == 0) {
- mutex_unlock(&tty->ipw_tty_mutex);
- return;
- }
-
- do_ipw_close(tty);
-
- mutex_unlock(&tty->ipw_tty_mutex);
-}
-
-static void ipw_close(struct tty_struct *linux_tty, struct file *filp)
-{
- ipw_hangup(linux_tty);
-}
-
-/* Take data received from hardware, and send it out the tty */
-void ipwireless_tty_received(struct ipw_tty *tty, unsigned char *data,
- unsigned int length)
-{
- struct tty_struct *linux_tty;
- int work = 0;
-
- mutex_lock(&tty->ipw_tty_mutex);
- linux_tty = tty->linux_tty;
- if (linux_tty == NULL) {
- mutex_unlock(&tty->ipw_tty_mutex);
- return;
- }
-
- if (!tty->open_count) {
- mutex_unlock(&tty->ipw_tty_mutex);
- return;
- }
- mutex_unlock(&tty->ipw_tty_mutex);
-
- work = tty_insert_flip_string(linux_tty, data, length);
-
- if (work != length)
- printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME
- ": %d chars not inserted to flip buffer!\n",
- length - work);
-
- /*
- * This may sleep if ->low_latency is set
- */
- if (work)
- tty_flip_buffer_push(linux_tty);
-}
-
-static void ipw_write_packet_sent_callback(void *callback_data,
- unsigned int packet_length)
-{
- struct ipw_tty *tty = callback_data;
-
- /*
- * Packet has been sent, so we subtract the number of bytes from our
- * tally of outstanding TX bytes.
- */
- tty->tx_bytes_queued -= packet_length;
-}
-
-static int ipw_write(struct tty_struct *linux_tty,
- const unsigned char *buf, int count)
-{
- struct ipw_tty *tty = linux_tty->driver_data;
- int room, ret;
-
- if (!tty)
- return -ENODEV;
-
- mutex_lock(&tty->ipw_tty_mutex);
- if (!tty->open_count) {
- mutex_unlock(&tty->ipw_tty_mutex);
- return -EINVAL;
- }
-
- room = IPWIRELESS_TX_QUEUE_SIZE - tty->tx_bytes_queued;
- if (room < 0)
- room = 0;
- /* Don't allow caller to write any more than we have room for */
- if (count > room)
- count = room;
-
- if (count == 0) {
- mutex_unlock(&tty->ipw_tty_mutex);
- return 0;
- }
-
- ret = ipwireless_send_packet(tty->hardware, IPW_CHANNEL_RAS,
- (unsigned char *) buf, count,
- ipw_write_packet_sent_callback, tty);
- if (ret == -1) {
- mutex_unlock(&tty->ipw_tty_mutex);
- return 0;
- }
-
- tty->tx_bytes_queued += count;
- mutex_unlock(&tty->ipw_tty_mutex);
-
- return count;
-}
-
-static int ipw_write_room(struct tty_struct *linux_tty)
-{
- struct ipw_tty *tty = linux_tty->driver_data;
- int room;
-
- if (!tty)
- return -ENODEV;
-
- if (!tty->open_count)
- return -EINVAL;
-
- room = IPWIRELESS_TX_QUEUE_SIZE - tty->tx_bytes_queued;
- if (room < 0)
- room = 0;
-
- return room;
-}
-
-static int ipwireless_get_serial_info(struct ipw_tty *tty,
- struct serial_struct __user *retinfo)
-{
- struct serial_struct tmp;
-
- if (!retinfo)
- return (-EFAULT);
-
- memset(&tmp, 0, sizeof(tmp));
- tmp.type = PORT_UNKNOWN;
- tmp.line = tty->index;
- tmp.port = 0;
- tmp.irq = 0;
- tmp.flags = 0;
- tmp.baud_base = 115200;
- tmp.close_delay = 0;
- tmp.closing_wait = 0;
- tmp.custom_divisor = 0;
- tmp.hub6 = 0;
- if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
- return -EFAULT;
-
- return 0;
-}
-
-static int ipw_chars_in_buffer(struct tty_struct *linux_tty)
-{
- struct ipw_tty *tty = linux_tty->driver_data;
-
- if (!tty)
- return -ENODEV;
-
- if (!tty->open_count)
- return -EINVAL;
-
- return tty->tx_bytes_queued;
-}
-
-static int get_control_lines(struct ipw_tty *tty)
-{
- unsigned int my = tty->control_lines;
- unsigned int out = 0;
-
- if (my & IPW_CONTROL_LINE_RTS)
- out |= TIOCM_RTS;
- if (my & IPW_CONTROL_LINE_DTR)
- out |= TIOCM_DTR;
- if (my & IPW_CONTROL_LINE_CTS)
- out |= TIOCM_CTS;
- if (my & IPW_CONTROL_LINE_DSR)
- out |= TIOCM_DSR;
- if (my & IPW_CONTROL_LINE_DCD)
- out |= TIOCM_CD;
-
- return out;
-}
-
-static int set_control_lines(struct ipw_tty *tty, unsigned int set,
- unsigned int clear)
-{
- int ret;
-
- if (set & TIOCM_RTS) {
- ret = ipwireless_set_RTS(tty->hardware, tty->channel_idx, 1);
- if (ret)
- return ret;
- if (tty->secondary_channel_idx != -1) {
- ret = ipwireless_set_RTS(tty->hardware,
- tty->secondary_channel_idx, 1);
- if (ret)
- return ret;
- }
- }
- if (set & TIOCM_DTR) {
- ret = ipwireless_set_DTR(tty->hardware, tty->channel_idx, 1);
- if (ret)
- return ret;
- if (tty->secondary_channel_idx != -1) {
- ret = ipwireless_set_DTR(tty->hardware,
- tty->secondary_channel_idx, 1);
- if (ret)
- return ret;
- }
- }
- if (clear & TIOCM_RTS) {
- ret = ipwireless_set_RTS(tty->hardware, tty->channel_idx, 0);
- if (tty->secondary_channel_idx != -1) {
- ret = ipwireless_set_RTS(tty->hardware,
- tty->secondary_channel_idx, 0);
- if (ret)
- return ret;
- }
- }
- if (clear & TIOCM_DTR) {
- ret = ipwireless_set_DTR(tty->hardware, tty->channel_idx, 0);
- if (tty->secondary_channel_idx != -1) {
- ret = ipwireless_set_DTR(tty->hardware,
- tty->secondary_channel_idx, 0);
- if (ret)
- return ret;
- }
- }
- return 0;
-}
-
-static int ipw_tiocmget(struct tty_struct *linux_tty, struct file *file)
-{
- struct ipw_tty *tty = linux_tty->driver_data;
-
- if (!tty)
- return -ENODEV;
-
- if (!tty->open_count)
- return -EINVAL;
-
- return get_control_lines(tty);
-}
-
-static int
-ipw_tiocmset(struct tty_struct *linux_tty, struct file *file,
- unsigned int set, unsigned int clear)
-{
- struct ipw_tty *tty = linux_tty->driver_data;
-
- if (!tty)
- return -ENODEV;
-
- if (!tty->open_count)
- return -EINVAL;
-
- return set_control_lines(tty, set, clear);
-}
-
-static int ipw_ioctl(struct tty_struct *linux_tty, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- struct ipw_tty *tty = linux_tty->driver_data;
-
- if (!tty)
- return -ENODEV;
-
- if (!tty->open_count)
- return -EINVAL;
-
- switch (cmd) {
- case TIOCGSERIAL:
- return ipwireless_get_serial_info(tty, (void __user *) arg);
-
- case TIOCSSERIAL:
- return 0; /* Keeps the PCMCIA scripts happy. */
- }
-
- if (tty->tty_type == TTYTYPE_MODEM) {
- switch (cmd) {
- case PPPIOCGCHAN:
- {
- int chan = ipwireless_ppp_channel_index(
- tty->network);
-
- if (chan < 0)
- return -ENODEV;
- if (put_user(chan, (int __user *) arg))
- return -EFAULT;
- }
- return 0;
-
- case PPPIOCGUNIT:
- {
- int unit = ipwireless_ppp_unit_number(
- tty->network);
-
- if (unit < 0)
- return -ENODEV;
- if (put_user(unit, (int __user *) arg))
- return -EFAULT;
- }
- return 0;
-
- case TCGETS:
- case TCGETA:
- return n_tty_ioctl(linux_tty, file, cmd, arg);
-
- case TCFLSH:
- return n_tty_ioctl(linux_tty, file, cmd, arg);
-
- case FIONREAD:
- {
- int val = 0;
-
- if (put_user(val, (int __user *) arg))
- return -EFAULT;
- }
- return 0;
- }
- }
-
- return -ENOIOCTLCMD;
-}
-
-static int add_tty(dev_node_t *nodesp, int j,
- struct ipw_hardware *hardware,
- struct ipw_network *network, int channel_idx,
- int secondary_channel_idx, int tty_type)
-{
- ttys[j] = kzalloc(sizeof(struct ipw_tty), GFP_KERNEL);
- if (!ttys[j])
- return -ENOMEM;
- ttys[j]->index = j;
- ttys[j]->hardware = hardware;
- ttys[j]->channel_idx = channel_idx;
- ttys[j]->secondary_channel_idx = secondary_channel_idx;
- ttys[j]->network = network;
- ttys[j]->tty_type = tty_type;
- mutex_init(&ttys[j]->ipw_tty_mutex);
-
- tty_register_device(ipw_tty_driver, j, NULL);
- ipwireless_associate_network_tty(network, channel_idx, ttys[j]);
-
- if (secondary_channel_idx != -1)
- ipwireless_associate_network_tty(network,
- secondary_channel_idx,
- ttys[j]);
- if (nodesp != NULL) {
- sprintf(nodesp->dev_name, "ttyIPWp%d", j);
- nodesp->major = ipw_tty_driver->major;
- nodesp->minor = j + ipw_tty_driver->minor_start;
- }
- if (get_tty(j + ipw_tty_driver->minor_start) == ttys[j])
- report_registering(ttys[j]);
- return 0;
-}
-
-struct ipw_tty *ipwireless_tty_create(struct ipw_hardware *hardware,
- struct ipw_network *network,
- dev_node_t *nodes)
-{
- int i, j;
-
- for (i = 0; i < IPWIRELESS_PCMCIA_MINOR_RANGE; i++) {
- int allfree = 1;
-
- for (j = i; j < IPWIRELESS_PCMCIA_MINORS;
- j += IPWIRELESS_PCMCIA_MINOR_RANGE)
- if (ttys[j] != NULL) {
- allfree = 0;
- break;
- }
-
- if (allfree) {
- j = i;
-
- if (add_tty(&nodes[0], j, hardware, network,
- IPW_CHANNEL_DIALLER, IPW_CHANNEL_RAS,
- TTYTYPE_MODEM))
- return NULL;
-
- j += IPWIRELESS_PCMCIA_MINOR_RANGE;
- if (add_tty(&nodes[1], j, hardware, network,
- IPW_CHANNEL_DIALLER, -1,
- TTYTYPE_MONITOR))
- return NULL;
-
- j += IPWIRELESS_PCMCIA_MINOR_RANGE;
- if (add_tty(NULL, j, hardware, network,
- IPW_CHANNEL_RAS, -1,
- TTYTYPE_RAS_RAW))
- return NULL;
-
- nodes[0].next = &nodes[1];
- nodes[1].next = NULL;
-
- return ttys[i];
- }
- }
- return NULL;
-}
-
-/*
- * Must be called before ipwireless_network_free().
- */
-void ipwireless_tty_free(struct ipw_tty *tty)
-{
- int j;
- struct ipw_network *network = ttys[tty->index]->network;
-
- for (j = tty->index; j < IPWIRELESS_PCMCIA_MINORS;
- j += IPWIRELESS_PCMCIA_MINOR_RANGE) {
- struct ipw_tty *ttyj = ttys[j];
-
- if (ttyj) {
- mutex_lock(&ttyj->ipw_tty_mutex);
- if (get_tty(j + ipw_tty_driver->minor_start) == ttyj)
- report_deregistering(ttyj);
- ttyj->closing = 1;
- if (ttyj->linux_tty != NULL) {
- mutex_unlock(&ttyj->ipw_tty_mutex);
- tty_hangup(ttyj->linux_tty);
- /* Wait till the tty_hangup has completed */
- flush_scheduled_work();
- mutex_lock(&ttyj->ipw_tty_mutex);
- }
- while (ttyj->open_count)
- do_ipw_close(ttyj);
- ipwireless_disassociate_network_ttys(network,
- ttyj->channel_idx);
- tty_unregister_device(ipw_tty_driver, j);
- ttys[j] = NULL;
- mutex_unlock(&ttyj->ipw_tty_mutex);
- kfree(ttyj);
- }
- }
-}
-
-static struct tty_operations tty_ops = {
- .open = ipw_open,
- .close = ipw_close,
- .hangup = ipw_hangup,
- .write = ipw_write,
- .write_room = ipw_write_room,
- .ioctl = ipw_ioctl,
- .chars_in_buffer = ipw_chars_in_buffer,
- .tiocmget = ipw_tiocmget,
- .tiocmset = ipw_tiocmset,
-};
-
-int ipwireless_tty_init(void)
-{
- int result;
-
- ipw_tty_driver = alloc_tty_driver(IPWIRELESS_PCMCIA_MINORS);
- if (!ipw_tty_driver)
- return -ENOMEM;
-
- ipw_tty_driver->owner = THIS_MODULE;
- ipw_tty_driver->driver_name = IPWIRELESS_PCCARD_NAME;
- ipw_tty_driver->name = "ttyIPWp";
- ipw_tty_driver->major = 0;
- ipw_tty_driver->minor_start = IPWIRELESS_PCMCIA_START;
- ipw_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
- ipw_tty_driver->subtype = SERIAL_TYPE_NORMAL;
- ipw_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
- ipw_tty_driver->init_termios = tty_std_termios;
- ipw_tty_driver->init_termios.c_cflag =
- B9600 | CS8 | CREAD | HUPCL | CLOCAL;
- ipw_tty_driver->init_termios.c_ispeed = 9600;
- ipw_tty_driver->init_termios.c_ospeed = 9600;
- tty_set_operations(ipw_tty_driver, &tty_ops);
- result = tty_register_driver(ipw_tty_driver);
- if (result) {
- printk(KERN_ERR IPWIRELESS_PCCARD_NAME
- ": failed to register tty driver\n");
- put_tty_driver(ipw_tty_driver);
- return result;
- }
-
- return 0;
-}
-
-void ipwireless_tty_release(void)
-{
- int ret;
-
- ret = tty_unregister_driver(ipw_tty_driver);
- put_tty_driver(ipw_tty_driver);
- if (ret != 0)
- printk(KERN_ERR IPWIRELESS_PCCARD_NAME
- ": tty_unregister_driver failed with code %d\n", ret);
-}
-
-int ipwireless_tty_is_modem(struct ipw_tty *tty)
-{
- return tty->tty_type == TTYTYPE_MODEM;
-}
-
-void
-ipwireless_tty_notify_control_line_change(struct ipw_tty *tty,
- unsigned int channel_idx,
- unsigned int control_lines,
- unsigned int changed_mask)
-{
- unsigned int old_control_lines = tty->control_lines;
-
- tty->control_lines = (tty->control_lines & ~changed_mask)
- | (control_lines & changed_mask);
-
- /*
- * If DCD is de-asserted, we close the tty so pppd can tell that we
- * have gone offline.
- */
- if ((old_control_lines & IPW_CONTROL_LINE_DCD)
- && !(tty->control_lines & IPW_CONTROL_LINE_DCD)
- && tty->linux_tty) {
- tty_hangup(tty->linux_tty);
- }
-}
-
diff --git a/trunk/drivers/char/pcmcia/ipwireless/tty.h b/trunk/drivers/char/pcmcia/ipwireless/tty.h
deleted file mode 100644
index b0deb9168b6b..000000000000
--- a/trunk/drivers/char/pcmcia/ipwireless/tty.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * IPWireless 3G PCMCIA Network Driver
- *
- * Original code
- * by Stephen Blackheath ,
- * Ben Martel
- *
- * Copyrighted as follows:
- * Copyright (C) 2004 by Symmetric Systems Ltd (NZ)
- *
- * Various driver changes and rewrites, port to new kernels
- * Copyright (C) 2006-2007 Jiri Kosina
- *
- * Misc code cleanups and updates
- * Copyright (C) 2007 David Sterba
- */
-
-#ifndef _IPWIRELESS_CS_TTY_H_
-#define _IPWIRELESS_CS_TTY_H_
-
-#include
-#include
-
-#include
-#include
-#include
-#include
-
-struct ipw_tty;
-struct ipw_network;
-struct ipw_hardware;
-
-int ipwireless_tty_init(void);
-void ipwireless_tty_release(void);
-
-struct ipw_tty *ipwireless_tty_create(struct ipw_hardware *hw,
- struct ipw_network *net,
- dev_node_t *nodes);
-void ipwireless_tty_free(struct ipw_tty *tty);
-void ipwireless_tty_received(struct ipw_tty *tty, unsigned char *data,
- unsigned int length);
-int ipwireless_tty_is_modem(struct ipw_tty *tty);
-void ipwireless_tty_notify_control_line_change(struct ipw_tty *tty,
- unsigned int channel_idx,
- unsigned int control_lines,
- unsigned int changed_mask);
-
-#endif
diff --git a/trunk/drivers/firmware/dmi_scan.c b/trunk/drivers/firmware/dmi_scan.c
index e0bade732376..1412d7bcdbd1 100644
--- a/trunk/drivers/firmware/dmi_scan.c
+++ b/trunk/drivers/firmware/dmi_scan.c
@@ -43,18 +43,12 @@ static char * __init dmi_string(const struct dmi_header *dm, u8 s)
* We have to be cautious here. We have seen BIOSes with DMI pointers
* pointing to completely the wrong place for example
*/
-static int __init dmi_table(u32 base, int len, int num,
- void (*decode)(const struct dmi_header *))
+static void dmi_table(u8 *buf, int len, int num,
+ void (*decode)(const struct dmi_header *))
{
- u8 *buf, *data;
+ u8 *data = buf;
int i = 0;
- buf = dmi_ioremap(base, len);
- if (buf == NULL)
- return -1;
-
- data = buf;
-
/*
* Stop when we see all the items the table claimed to have
* OR we run off the end of the table (also happens)
@@ -75,7 +69,23 @@ static int __init dmi_table(u32 base, int len, int num,
data += 2;
i++;
}
- dmi_iounmap(buf, len);
+}
+
+static u32 dmi_base;
+static u16 dmi_len;
+static u16 dmi_num;
+
+static int __init dmi_walk_early(void (*decode)(const struct dmi_header *))
+{
+ u8 *buf;
+
+ buf = dmi_ioremap(dmi_base, dmi_len);
+ if (buf == NULL)
+ return -1;
+
+ dmi_table(buf, dmi_len, dmi_num, decode);
+
+ dmi_iounmap(buf, dmi_len);
return 0;
}
@@ -291,9 +301,9 @@ static int __init dmi_present(const char __iomem *p)
memcpy_fromio(buf, p, 15);
if ((memcmp(buf, "_DMI_", 5) == 0) && dmi_checksum(buf)) {
- u16 num = (buf[13] << 8) | buf[12];
- u16 len = (buf[7] << 8) | buf[6];
- u32 base = (buf[11] << 24) | (buf[10] << 16) |
+ dmi_num = (buf[13] << 8) | buf[12];
+ dmi_len = (buf[7] << 8) | buf[6];
+ dmi_base = (buf[11] << 24) | (buf[10] << 16) |
(buf[9] << 8) | buf[8];
/*
@@ -305,7 +315,7 @@ static int __init dmi_present(const char __iomem *p)
buf[14] >> 4, buf[14] & 0xF);
else
printk(KERN_INFO "DMI present.\n");
- if (dmi_table(base,len, num, dmi_decode) == 0)
+ if (dmi_walk_early(dmi_decode) == 0)
return 0;
}
return 1;
@@ -489,3 +499,27 @@ int dmi_get_year(int field)
return year;
}
+
+/**
+ * dmi_walk - Walk the DMI table and get called back for every record
+ * @decode: Callback function
+ *
+ * Returns -1 when the DMI table can't be reached, 0 on success.
+ */
+int dmi_walk(void (*decode)(const struct dmi_header *))
+{
+ u8 *buf;
+
+ if (!dmi_available)
+ return -1;
+
+ buf = ioremap(dmi_base, dmi_len);
+ if (buf == NULL)
+ return -1;
+
+ dmi_table(buf, dmi_len, dmi_num, decode);
+
+ iounmap(buf);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(dmi_walk);
diff --git a/trunk/drivers/misc/Kconfig b/trunk/drivers/misc/Kconfig
index 7b5220ca7d7f..78cd33861766 100644
--- a/trunk/drivers/misc/Kconfig
+++ b/trunk/drivers/misc/Kconfig
@@ -285,13 +285,4 @@ config INTEL_MENLOW
If unsure, say N.
-config ENCLOSURE_SERVICES
- tristate "Enclosure Services"
- default n
- help
- Provides support for intelligent enclosures (bays which
- contain storage devices). You also need either a host
- driver (SCSI/ATA) which supports enclosures
- or a SCSI enclosure device (SES) to use these services.
-
endif # MISC_DEVICES
diff --git a/trunk/drivers/misc/Makefile b/trunk/drivers/misc/Makefile
index 7f13549cc87e..1f41654aae4d 100644
--- a/trunk/drivers/misc/Makefile
+++ b/trunk/drivers/misc/Makefile
@@ -20,4 +20,3 @@ obj-$(CONFIG_THINKPAD_ACPI) += thinkpad_acpi.o
obj-$(CONFIG_FUJITSU_LAPTOP) += fujitsu-laptop.o
obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o
obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o
-obj-$(CONFIG_ENCLOSURE_SERVICES) += enclosure.o
diff --git a/trunk/drivers/misc/enclosure.c b/trunk/drivers/misc/enclosure.c
deleted file mode 100644
index 6fcb0e96adf4..000000000000
--- a/trunk/drivers/misc/enclosure.c
+++ /dev/null
@@ -1,484 +0,0 @@
-/*
- * Enclosure Services
- *
- * Copyright (C) 2008 James Bottomley
- *
-**-----------------------------------------------------------------------------
-**
-** This program is free software; you can redistribute it and/or
-** modify it under the terms of the GNU General Public License
-** version 2 as published by the Free Software Foundation.
-**
-** This program is distributed in the hope that it will be useful,
-** but WITHOUT ANY WARRANTY; without even the implied warranty of
-** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-** GNU General Public License for more details.
-**
-** You should have received a copy of the GNU General Public License
-** along with this program; if not, write to the Free Software
-** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-**
-**-----------------------------------------------------------------------------
-*/
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-static LIST_HEAD(container_list);
-static DEFINE_MUTEX(container_list_lock);
-static struct class enclosure_class;
-static struct class enclosure_component_class;
-
-/**
- * enclosure_find - find an enclosure given a device
- * @dev: the device to find for
- *
- * Looks through the list of registered enclosures to see
- * if it can find a match for a device. Returns NULL if no
- * enclosure is found. Obtains a reference to the enclosure class
- * device which must be released with class_device_put().
- */
-struct enclosure_device *enclosure_find(struct device *dev)
-{
- struct enclosure_device *edev = NULL;
-
- mutex_lock(&container_list_lock);
- list_for_each_entry(edev, &container_list, node) {
- if (edev->cdev.dev == dev) {
- class_device_get(&edev->cdev);
- mutex_unlock(&container_list_lock);
- return edev;
- }
- }
- mutex_unlock(&container_list_lock);
-
- return NULL;
-}
-EXPORT_SYMBOL_GPL(enclosure_find);
-
-/**
- * enclosure_for_each_device - calls a function for each enclosure
- * @fn: the function to call
- * @data: the data to pass to each call
- *
- * Loops over all the enclosures calling the function.
- *
- * Note, this function uses a mutex which will be held across calls to
- * @fn, so it must have non atomic context, and @fn may (although it
- * should not) sleep or otherwise cause the mutex to be held for
- * indefinite periods
- */
-int enclosure_for_each_device(int (*fn)(struct enclosure_device *, void *),
- void *data)
-{
- int error = 0;
- struct enclosure_device *edev;
-
- mutex_lock(&container_list_lock);
- list_for_each_entry(edev, &container_list, node) {
- error = fn(edev, data);
- if (error)
- break;
- }
- mutex_unlock(&container_list_lock);
-
- return error;
-}
-EXPORT_SYMBOL_GPL(enclosure_for_each_device);
-
-/**
- * enclosure_register - register device as an enclosure
- *
- * @dev: device containing the enclosure
- * @components: number of components in the enclosure
- *
- * This sets up the device for being an enclosure. Note that @dev does
- * not have to be a dedicated enclosure device. It may be some other type
- * of device that additionally responds to enclosure services
- */
-struct enclosure_device *
-enclosure_register(struct device *dev, const char *name, int components,
- struct enclosure_component_callbacks *cb)
-{
- struct enclosure_device *edev =
- kzalloc(sizeof(struct enclosure_device) +
- sizeof(struct enclosure_component)*components,
- GFP_KERNEL);
- int err, i;
-
- BUG_ON(!cb);
-
- if (!edev)
- return ERR_PTR(-ENOMEM);
-
- edev->components = components;
-
- edev->cdev.class = &enclosure_class;
- edev->cdev.dev = get_device(dev);
- edev->cb = cb;
- snprintf(edev->cdev.class_id, BUS_ID_SIZE, "%s", name);
- err = class_device_register(&edev->cdev);
- if (err)
- goto err;
-
- for (i = 0; i < components; i++)
- edev->component[i].number = -1;
-
- mutex_lock(&container_list_lock);
- list_add_tail(&edev->node, &container_list);
- mutex_unlock(&container_list_lock);
-
- return edev;
-
- err:
- put_device(edev->cdev.dev);
- kfree(edev);
- return ERR_PTR(err);
-}
-EXPORT_SYMBOL_GPL(enclosure_register);
-
-static struct enclosure_component_callbacks enclosure_null_callbacks;
-
-/**
- * enclosure_unregister - remove an enclosure
- *
- * @edev: the registered enclosure to remove;
- */
-void enclosure_unregister(struct enclosure_device *edev)
-{
- int i;
-
- mutex_lock(&container_list_lock);
- list_del(&edev->node);
- mutex_unlock(&container_list_lock);
-
- for (i = 0; i < edev->components; i++)
- if (edev->component[i].number != -1)
- class_device_unregister(&edev->component[i].cdev);
-
- /* prevent any callbacks into service user */
- edev->cb = &enclosure_null_callbacks;
- class_device_unregister(&edev->cdev);
-}
-EXPORT_SYMBOL_GPL(enclosure_unregister);
-
-static void enclosure_release(struct class_device *cdev)
-{
- struct enclosure_device *edev = to_enclosure_device(cdev);
-
- put_device(cdev->dev);
- kfree(edev);
-}
-
-static void enclosure_component_release(struct class_device *cdev)
-{
- if (cdev->dev)
- put_device(cdev->dev);
- class_device_put(cdev->parent);
-}
-
-/**
- * enclosure_component_register - add a particular component to an enclosure
- * @edev: the enclosure to add the component
- * @num: the device number
- * @type: the type of component being added
- * @name: an optional name to appear in sysfs (leave NULL if none)
- *
- * Registers the component. The name is optional for enclosures that
- * give their components a unique name. If not, leave the field NULL
- * and a name will be assigned.
- *
- * Returns a pointer to the enclosure component or an error.
- */
-struct enclosure_component *
-enclosure_component_register(struct enclosure_device *edev,
- unsigned int number,
- enum enclosure_component_type type,
- const char *name)
-{
- struct enclosure_component *ecomp;
- struct class_device *cdev;
- int err;
-
- if (number >= edev->components)
- return ERR_PTR(-EINVAL);
-
- ecomp = &edev->component[number];
-
- if (ecomp->number != -1)
- return ERR_PTR(-EINVAL);
-
- ecomp->type = type;
- ecomp->number = number;
- cdev = &ecomp->cdev;
- cdev->parent = class_device_get(&edev->cdev);
- cdev->class = &enclosure_component_class;
- if (name)
- snprintf(cdev->class_id, BUS_ID_SIZE, "%s", name);
- else
- snprintf(cdev->class_id, BUS_ID_SIZE, "%u", number);
-
- err = class_device_register(cdev);
- if (err)
- ERR_PTR(err);
-
- return ecomp;
-}
-EXPORT_SYMBOL_GPL(enclosure_component_register);
-
-/**
- * enclosure_add_device - add a device as being part of an enclosure
- * @edev: the enclosure device being added to.
- * @num: the number of the component
- * @dev: the device being added
- *
- * Declares a real device to reside in slot (or identifier) @num of an
- * enclosure. This will cause the relevant sysfs links to appear.
- * This function may also be used to change a device associated with
- * an enclosure without having to call enclosure_remove_device() in
- * between.
- *
- * Returns zero on success or an error.
- */
-int enclosure_add_device(struct enclosure_device *edev, int component,
- struct device *dev)
-{
- struct class_device *cdev;
-
- if (!edev || component >= edev->components)
- return -EINVAL;
-
- cdev = &edev->component[component].cdev;
-
- class_device_del(cdev);
- if (cdev->dev)
- put_device(cdev->dev);
- cdev->dev = get_device(dev);
- return class_device_add(cdev);
-}
-EXPORT_SYMBOL_GPL(enclosure_add_device);
-
-/**
- * enclosure_remove_device - remove a device from an enclosure
- * @edev: the enclosure device
- * @num: the number of the component to remove
- *
- * Returns zero on success or an error.
- *
- */
-int enclosure_remove_device(struct enclosure_device *edev, int component)
-{
- struct class_device *cdev;
-
- if (!edev || component >= edev->components)
- return -EINVAL;
-
- cdev = &edev->component[component].cdev;
-
- class_device_del(cdev);
- if (cdev->dev)
- put_device(cdev->dev);
- cdev->dev = NULL;
- return class_device_add(cdev);
-}
-EXPORT_SYMBOL_GPL(enclosure_remove_device);
-
-/*
- * sysfs pieces below
- */
-
-static ssize_t enclosure_show_components(struct class_device *cdev, char *buf)
-{
- struct enclosure_device *edev = to_enclosure_device(cdev);
-
- return snprintf(buf, 40, "%d\n", edev->components);
-}
-
-static struct class_device_attribute enclosure_attrs[] = {
- __ATTR(components, S_IRUGO, enclosure_show_components, NULL),
- __ATTR_NULL
-};
-
-static struct class enclosure_class = {
- .name = "enclosure",
- .owner = THIS_MODULE,
- .release = enclosure_release,
- .class_dev_attrs = enclosure_attrs,
-};
-
-static const char *const enclosure_status [] = {
- [ENCLOSURE_STATUS_UNSUPPORTED] = "unsupported",
- [ENCLOSURE_STATUS_OK] = "OK",
- [ENCLOSURE_STATUS_CRITICAL] = "critical",
- [ENCLOSURE_STATUS_NON_CRITICAL] = "non-critical",
- [ENCLOSURE_STATUS_UNRECOVERABLE] = "unrecoverable",
- [ENCLOSURE_STATUS_NOT_INSTALLED] = "not installed",
- [ENCLOSURE_STATUS_UNKNOWN] = "unknown",
- [ENCLOSURE_STATUS_UNAVAILABLE] = "unavailable",
-};
-
-static const char *const enclosure_type [] = {
- [ENCLOSURE_COMPONENT_DEVICE] = "device",
- [ENCLOSURE_COMPONENT_ARRAY_DEVICE] = "array device",
-};
-
-static ssize_t get_component_fault(struct class_device *cdev, char *buf)
-{
- struct enclosure_device *edev = to_enclosure_device(cdev->parent);
- struct enclosure_component *ecomp = to_enclosure_component(cdev);
-
- if (edev->cb->get_fault)
- edev->cb->get_fault(edev, ecomp);
- return snprintf(buf, 40, "%d\n", ecomp->fault);
-}
-
-static ssize_t set_component_fault(struct class_device *cdev, const char *buf,
- size_t count)
-{
- struct enclosure_device *edev = to_enclosure_device(cdev->parent);
- struct enclosure_component *ecomp = to_enclosure_component(cdev);
- int val = simple_strtoul(buf, NULL, 0);
-
- if (edev->cb->set_fault)
- edev->cb->set_fault(edev, ecomp, val);
- return count;
-}
-
-static ssize_t get_component_status(struct class_device *cdev, char *buf)
-{
- struct enclosure_device *edev = to_enclosure_device(cdev->parent);
- struct enclosure_component *ecomp = to_enclosure_component(cdev);
-
- if (edev->cb->get_status)
- edev->cb->get_status(edev, ecomp);
- return snprintf(buf, 40, "%s\n", enclosure_status[ecomp->status]);
-}
-
-static ssize_t set_component_status(struct class_device *cdev, const char *buf,
- size_t count)
-{
- struct enclosure_device *edev = to_enclosure_device(cdev->parent);
- struct enclosure_component *ecomp = to_enclosure_component(cdev);
- int i;
-
- for (i = 0; enclosure_status[i]; i++) {
- if (strncmp(buf, enclosure_status[i],
- strlen(enclosure_status[i])) == 0 &&
- (buf[strlen(enclosure_status[i])] == '\n' ||
- buf[strlen(enclosure_status[i])] == '\0'))
- break;
- }
-
- if (enclosure_status[i] && edev->cb->set_status) {
- edev->cb->set_status(edev, ecomp, i);
- return count;
- } else
- return -EINVAL;
-}
-
-static ssize_t get_component_active(struct class_device *cdev, char *buf)
-{
- struct enclosure_device *edev = to_enclosure_device(cdev->parent);
- struct enclosure_component *ecomp = to_enclosure_component(cdev);
-
- if (edev->cb->get_active)
- edev->cb->get_active(edev, ecomp);
- return snprintf(buf, 40, "%d\n", ecomp->active);
-}
-
-static ssize_t set_component_active(struct class_device *cdev, const char *buf,
- size_t count)
-{
- struct enclosure_device *edev = to_enclosure_device(cdev->parent);
- struct enclosure_component *ecomp = to_enclosure_component(cdev);
- int val = simple_strtoul(buf, NULL, 0);
-
- if (edev->cb->set_active)
- edev->cb->set_active(edev, ecomp, val);
- return count;
-}
-
-static ssize_t get_component_locate(struct class_device *cdev, char *buf)
-{
- struct enclosure_device *edev = to_enclosure_device(cdev->parent);
- struct enclosure_component *ecomp = to_enclosure_component(cdev);
-
- if (edev->cb->get_locate)
- edev->cb->get_locate(edev, ecomp);
- return snprintf(buf, 40, "%d\n", ecomp->locate);
-}
-
-static ssize_t set_component_locate(struct class_device *cdev, const char *buf,
- size_t count)
-{
- struct enclosure_device *edev = to_enclosure_device(cdev->parent);
- struct enclosure_component *ecomp = to_enclosure_component(cdev);
- int val = simple_strtoul(buf, NULL, 0);
-
- if (edev->cb->set_locate)
- edev->cb->set_locate(edev, ecomp, val);
- return count;
-}
-
-static ssize_t get_component_type(struct class_device *cdev, char *buf)
-{
- struct enclosure_component *ecomp = to_enclosure_component(cdev);
-
- return snprintf(buf, 40, "%s\n", enclosure_type[ecomp->type]);
-}
-
-
-static struct class_device_attribute enclosure_component_attrs[] = {
- __ATTR(fault, S_IRUGO | S_IWUSR, get_component_fault,
- set_component_fault),
- __ATTR(status, S_IRUGO | S_IWUSR, get_component_status,
- set_component_status),
- __ATTR(active, S_IRUGO | S_IWUSR, get_component_active,
- set_component_active),
- __ATTR(locate, S_IRUGO | S_IWUSR, get_component_locate,
- set_component_locate),
- __ATTR(type, S_IRUGO, get_component_type, NULL),
- __ATTR_NULL
-};
-
-static struct class enclosure_component_class = {
- .name = "enclosure_component",
- .owner = THIS_MODULE,
- .class_dev_attrs = enclosure_component_attrs,
- .release = enclosure_component_release,
-};
-
-static int __init enclosure_init(void)
-{
- int err;
-
- err = class_register(&enclosure_class);
- if (err)
- return err;
- err = class_register(&enclosure_component_class);
- if (err)
- goto err_out;
-
- return 0;
- err_out:
- class_unregister(&enclosure_class);
-
- return err;
-}
-
-static void __exit enclosure_exit(void)
-{
- class_unregister(&enclosure_component_class);
- class_unregister(&enclosure_class);
-}
-
-module_init(enclosure_init);
-module_exit(enclosure_exit);
-
-MODULE_AUTHOR("James Bottomley");
-MODULE_DESCRIPTION("Enclosure Services");
-MODULE_LICENSE("GPL v2");
diff --git a/trunk/drivers/scsi/Kconfig b/trunk/drivers/scsi/Kconfig
index a5f0aaaf0dd4..14fc7f39e83e 100644
--- a/trunk/drivers/scsi/Kconfig
+++ b/trunk/drivers/scsi/Kconfig
@@ -179,15 +179,7 @@ config CHR_DEV_SCH
say M here and read and
. The module will be called ch.o.
If unsure, say N.
-
-config SCSI_ENCLOSURE
- tristate "SCSI Enclosure Support"
- depends on SCSI && ENCLOSURE_SERVICES
- help
- Enclosures are devices sitting on or in SCSI backplanes that
- manage devices. If you have a disk cage, the chances are that
- it has an enclosure device. Selecting this option will just allow
- certain enclosure conditions to be reported and is not required.
+
comment "Some SCSI devices (e.g. CD jukebox) support multiple LUNs"
depends on SCSI
@@ -358,6 +350,17 @@ config SGIWD93_SCSI
If you have a Western Digital WD93 SCSI controller on
an SGI MIPS system, say Y. Otherwise, say N.
+config SCSI_DECNCR
+ tristate "DEC NCR53C94 Scsi Driver"
+ depends on MACH_DECSTATION && SCSI && TC
+ help
+ Say Y here to support the NCR53C94 SCSI controller chips on IOASIC
+ based TURBOchannel DECstations and TURBOchannel PMAZ-A cards.
+
+config SCSI_DECSII
+ tristate "DEC SII Scsi Driver"
+ depends on MACH_DECSTATION && SCSI && 32BIT
+
config BLK_DEV_3W_XXXX_RAID
tristate "3ware 5/6/7/8xxx ATA-RAID support"
depends on PCI && SCSI
@@ -1260,6 +1263,17 @@ config SCSI_NCR53C8XX_NO_DISCONNECT
not allow targets to disconnect is not reasonable if there is more
than 1 device on a SCSI bus. The normal answer therefore is N.
+config SCSI_MCA_53C9X
+ tristate "NCR MCA 53C9x SCSI support"
+ depends on MCA_LEGACY && SCSI && BROKEN_ON_SMP
+ help
+ Some MicroChannel machines, notably the NCR 35xx line, use a SCSI
+ controller based on the NCR 53C94. This driver will allow use of
+ the controller on the 3550, and very possibly others.
+
+ To compile this driver as a module, choose M here: the
+ module will be called mca_53c9x.
+
config SCSI_PAS16
tristate "PAS16 SCSI support"
depends on ISA && SCSI
@@ -1586,6 +1600,45 @@ config GVP11_SCSI
To compile this driver as a module, choose M here: the
module will be called gvp11.
+config CYBERSTORM_SCSI
+ tristate "CyberStorm SCSI support"
+ depends on ZORRO && SCSI
+ help
+ If you have an Amiga with an original (MkI) Phase5 Cyberstorm
+ accelerator board and the optional Cyberstorm SCSI controller,
+ answer Y. Otherwise, say N.
+
+config CYBERSTORMII_SCSI
+ tristate "CyberStorm Mk II SCSI support"
+ depends on ZORRO && SCSI
+ help
+ If you have an Amiga with a Phase5 Cyberstorm MkII accelerator board
+ and the optional Cyberstorm SCSI controller, say Y. Otherwise,
+ answer N.
+
+config BLZ2060_SCSI
+ tristate "Blizzard 2060 SCSI support"
+ depends on ZORRO && SCSI
+ help
+ If you have an Amiga with a Phase5 Blizzard 2060 accelerator board
+ and want to use the onboard SCSI controller, say Y. Otherwise,
+ answer N.
+
+config BLZ1230_SCSI
+ tristate "Blizzard 1230IV/1260 SCSI support"
+ depends on ZORRO && SCSI
+ help
+ If you have an Amiga 1200 with a Phase5 Blizzard 1230IV or Blizzard
+ 1260 accelerator, and the optional SCSI module, say Y. Otherwise,
+ say N.
+
+config FASTLANE_SCSI
+ tristate "Fastlane SCSI support"
+ depends on ZORRO && SCSI
+ help
+ If you have the Phase5 Fastlane Z3 SCSI controller, or plan to use
+ one in the near future, say Y to this question. Otherwise, say N.
+
config SCSI_A4000T
tristate "A4000T NCR53c710 SCSI support (EXPERIMENTAL)"
depends on AMIGA && SCSI && EXPERIMENTAL
@@ -1613,6 +1666,15 @@ config SCSI_ZORRO7XX
accelerator card for the Amiga 1200,
- the SCSI controller on the GVP Turbo 040/060 accelerator.
+config OKTAGON_SCSI
+ tristate "BSC Oktagon SCSI support (EXPERIMENTAL)"
+ depends on ZORRO && SCSI && EXPERIMENTAL
+ help
+ If you have the BSC Oktagon SCSI disk controller for the Amiga, say
+ Y to this question. If you're in doubt about whether you have one,
+ see the picture at
+ .
+
config ATARI_SCSI
tristate "Atari native SCSI support"
depends on ATARI && SCSI
@@ -1665,6 +1727,18 @@ config MAC_SCSI
SCSI-HOWTO, available from
.
+config SCSI_MAC_ESP
+ tristate "Macintosh NCR53c9[46] SCSI"
+ depends on MAC && SCSI
+ help
+ This is the NCR 53c9x SCSI controller found on most of the 68040
+ based Macintoshes. If you have one of these say Y and read the
+ SCSI-HOWTO, available from
+ .
+
+ To compile this driver as a module, choose M here: the
+ module will be called mac_esp.
+
config MVME147_SCSI
bool "WD33C93 SCSI driver for MVME147"
depends on MVME147 && SCSI=y
@@ -1705,7 +1779,6 @@ config SUN3_SCSI
config SUN3X_ESP
bool "Sun3x ESP SCSI"
depends on SUN3X && SCSI=y
- select SCSI_SPI_ATTRS
help
The ESP was an on-board SCSI controller used on Sun 3/80
machines. Say Y here to compile in support for it.
diff --git a/trunk/drivers/scsi/Makefile b/trunk/drivers/scsi/Makefile
index 925c26b4fff9..93e1428d03fc 100644
--- a/trunk/drivers/scsi/Makefile
+++ b/trunk/drivers/scsi/Makefile
@@ -44,8 +44,15 @@ obj-$(CONFIG_A2091_SCSI) += a2091.o wd33c93.o
obj-$(CONFIG_GVP11_SCSI) += gvp11.o wd33c93.o
obj-$(CONFIG_MVME147_SCSI) += mvme147.o wd33c93.o
obj-$(CONFIG_SGIWD93_SCSI) += sgiwd93.o wd33c93.o
+obj-$(CONFIG_CYBERSTORM_SCSI) += NCR53C9x.o cyberstorm.o
+obj-$(CONFIG_CYBERSTORMII_SCSI) += NCR53C9x.o cyberstormII.o
+obj-$(CONFIG_BLZ2060_SCSI) += NCR53C9x.o blz2060.o
+obj-$(CONFIG_BLZ1230_SCSI) += NCR53C9x.o blz1230.o
+obj-$(CONFIG_FASTLANE_SCSI) += NCR53C9x.o fastlane.o
+obj-$(CONFIG_OKTAGON_SCSI) += NCR53C9x.o oktagon_esp_mod.o
obj-$(CONFIG_ATARI_SCSI) += atari_scsi.o
obj-$(CONFIG_MAC_SCSI) += mac_scsi.o
+obj-$(CONFIG_SCSI_MAC_ESP) += mac_esp.o NCR53C9x.o
obj-$(CONFIG_SUN3_SCSI) += sun3_scsi.o sun3_scsi_vme.o
obj-$(CONFIG_MVME16x_SCSI) += 53c700.o mvme16x_scsi.o
obj-$(CONFIG_BVME6000_SCSI) += 53c700.o bvme6000_scsi.o
@@ -88,6 +95,7 @@ obj-$(CONFIG_SCSI_SYM53C8XX_2) += sym53c8xx_2/
obj-$(CONFIG_SCSI_ZALON) += zalon7xx.o
obj-$(CONFIG_SCSI_EATA_PIO) += eata_pio.o
obj-$(CONFIG_SCSI_7000FASST) += wd7000.o
+obj-$(CONFIG_SCSI_MCA_53C9X) += NCR53C9x.o mca_53c9x.o
obj-$(CONFIG_SCSI_IBMMCA) += ibmmca.o
obj-$(CONFIG_SCSI_EATA) += eata.o
obj-$(CONFIG_SCSI_DC395x) += dc395x.o
@@ -104,12 +112,13 @@ obj-$(CONFIG_SCSI_QLOGICPTI) += qlogicpti.o
obj-$(CONFIG_BLK_DEV_IDESCSI) += ide-scsi.o
obj-$(CONFIG_SCSI_MESH) += mesh.o
obj-$(CONFIG_SCSI_MAC53C94) += mac53c94.o
+obj-$(CONFIG_SCSI_DECNCR) += NCR53C9x.o dec_esp.o
obj-$(CONFIG_BLK_DEV_3W_XXXX_RAID) += 3w-xxxx.o
obj-$(CONFIG_SCSI_3W_9XXX) += 3w-9xxx.o
obj-$(CONFIG_SCSI_PPA) += ppa.o
obj-$(CONFIG_SCSI_IMM) += imm.o
obj-$(CONFIG_JAZZ_ESP) += esp_scsi.o jazz_esp.o
-obj-$(CONFIG_SUN3X_ESP) += esp_scsi.o sun3x_esp.o
+obj-$(CONFIG_SUN3X_ESP) += NCR53C9x.o sun3x_esp.o
obj-$(CONFIG_SCSI_LASI700) += 53c700.o lasi700.o
obj-$(CONFIG_SCSI_SNI_53C710) += 53c700.o sni_53c710.o
obj-$(CONFIG_SCSI_NSP32) += nsp32.o
@@ -129,7 +138,6 @@ obj-$(CONFIG_BLK_DEV_SD) += sd_mod.o
obj-$(CONFIG_BLK_DEV_SR) += sr_mod.o
obj-$(CONFIG_CHR_DEV_SG) += sg.o
obj-$(CONFIG_CHR_DEV_SCH) += ch.o
-obj-$(CONFIG_SCSI_ENCLOSURE) += ses.o
# This goes last, so that "real" scsi devices probe earlier
obj-$(CONFIG_SCSI_DEBUG) += scsi_debug.o
diff --git a/trunk/drivers/scsi/NCR53C9x.c b/trunk/drivers/scsi/NCR53C9x.c
new file mode 100644
index 000000000000..5b0efc903918
--- /dev/null
+++ b/trunk/drivers/scsi/NCR53C9x.c
@@ -0,0 +1,3654 @@
+/* NCR53C9x.c: Generic SCSI driver code for NCR53C9x chips.
+ *
+ * Originally esp.c : EnhancedScsiProcessor Sun SCSI driver code.
+ *
+ * Copyright (C) 1995, 1998 David S. Miller (davem@caip.rutgers.edu)
+ *
+ * Most DMA dependencies put in driver specific files by
+ * Jesper Skov (jskov@cygnus.co.uk)
+ *
+ * Set up to use esp_read/esp_write (preprocessor macros in NCR53c9x.h) by
+ * Tymm Twillman (tymm@coe.missouri.edu)
+ */
+
+/* TODO:
+ *
+ * 1) Maybe disable parity checking in config register one for SCSI1
+ * targets. (Gilmore says parity error on the SBus can lock up
+ * old sun4c's)
+ * 2) Add support for DMA2 pipelining.
+ * 3) Add tagged queueing.
+ * 4) Maybe change use of "esp" to something more "NCR"'ish.
+ */
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "scsi.h"
+#include
+#include "NCR53C9x.h"
+
+#include
+#include
+#include
+#include
+#include
+
+/* Command phase enumeration. */
+enum {
+ not_issued = 0x00, /* Still in the issue_SC queue. */
+
+ /* Various forms of selecting a target. */
+#define in_slct_mask 0x10
+ in_slct_norm = 0x10, /* ESP is arbitrating, normal selection */
+ in_slct_stop = 0x11, /* ESP will select, then stop with IRQ */
+ in_slct_msg = 0x12, /* select, then send a message */
+ in_slct_tag = 0x13, /* select and send tagged queue msg */
+ in_slct_sneg = 0x14, /* select and acquire sync capabilities */
+
+ /* Any post selection activity. */
+#define in_phases_mask 0x20
+ in_datain = 0x20, /* Data is transferring from the bus */
+ in_dataout = 0x21, /* Data is transferring to the bus */
+ in_data_done = 0x22, /* Last DMA data operation done (maybe) */
+ in_msgin = 0x23, /* Eating message from target */
+ in_msgincont = 0x24, /* Eating more msg bytes from target */
+ in_msgindone = 0x25, /* Decide what to do with what we got */
+ in_msgout = 0x26, /* Sending message to target */
+ in_msgoutdone = 0x27, /* Done sending msg out */
+ in_cmdbegin = 0x28, /* Sending cmd after abnormal selection */
+ in_cmdend = 0x29, /* Done sending slow cmd */
+ in_status = 0x2a, /* Was in status phase, finishing cmd */
+ in_freeing = 0x2b, /* freeing the bus for cmd cmplt or disc */
+ in_the_dark = 0x2c, /* Don't know what bus phase we are in */
+
+ /* Special states, ie. not normal bus transitions... */
+#define in_spec_mask 0x80
+ in_abortone = 0x80, /* Aborting one command currently */
+ in_abortall = 0x81, /* Blowing away all commands we have */
+ in_resetdev = 0x82, /* SCSI target reset in progress */
+ in_resetbus = 0x83, /* SCSI bus reset in progress */
+ in_tgterror = 0x84, /* Target did something stupid */
+};
+
+enum {
+ /* Zero has special meaning, see skipahead[12]. */
+/*0*/ do_never,
+
+/*1*/ do_phase_determine,
+/*2*/ do_reset_bus,
+/*3*/ do_reset_complete,
+/*4*/ do_work_bus,
+/*5*/ do_intr_end
+};
+
+/* The master ring of all esp hosts we are managing in this driver. */
+static struct NCR_ESP *espchain;
+int nesps = 0, esps_in_use = 0, esps_running = 0;
+EXPORT_SYMBOL(nesps);
+EXPORT_SYMBOL(esps_running);
+
+irqreturn_t esp_intr(int irq, void *dev_id);
+
+/* Debugging routines */
+static struct esp_cmdstrings {
+ unchar cmdchar;
+ char *text;
+} esp_cmd_strings[] = {
+ /* Miscellaneous */
+ { ESP_CMD_NULL, "ESP_NOP", },
+ { ESP_CMD_FLUSH, "FIFO_FLUSH", },
+ { ESP_CMD_RC, "RSTESP", },
+ { ESP_CMD_RS, "RSTSCSI", },
+ /* Disconnected State Group */
+ { ESP_CMD_RSEL, "RESLCTSEQ", },
+ { ESP_CMD_SEL, "SLCTNATN", },
+ { ESP_CMD_SELA, "SLCTATN", },
+ { ESP_CMD_SELAS, "SLCTATNSTOP", },
+ { ESP_CMD_ESEL, "ENSLCTRESEL", },
+ { ESP_CMD_DSEL, "DISSELRESEL", },
+ { ESP_CMD_SA3, "SLCTATN3", },
+ { ESP_CMD_RSEL3, "RESLCTSEQ", },
+ /* Target State Group */
+ { ESP_CMD_SMSG, "SNDMSG", },
+ { ESP_CMD_SSTAT, "SNDSTATUS", },
+ { ESP_CMD_SDATA, "SNDDATA", },
+ { ESP_CMD_DSEQ, "DISCSEQ", },
+ { ESP_CMD_TSEQ, "TERMSEQ", },
+ { ESP_CMD_TCCSEQ, "TRGTCMDCOMPSEQ", },
+ { ESP_CMD_DCNCT, "DISC", },
+ { ESP_CMD_RMSG, "RCVMSG", },
+ { ESP_CMD_RCMD, "RCVCMD", },
+ { ESP_CMD_RDATA, "RCVDATA", },
+ { ESP_CMD_RCSEQ, "RCVCMDSEQ", },
+ /* Initiator State Group */
+ { ESP_CMD_TI, "TRANSINFO", },
+ { ESP_CMD_ICCSEQ, "INICMDSEQCOMP", },
+ { ESP_CMD_MOK, "MSGACCEPTED", },
+ { ESP_CMD_TPAD, "TPAD", },
+ { ESP_CMD_SATN, "SATN", },
+ { ESP_CMD_RATN, "RATN", },
+};
+#define NUM_ESP_COMMANDS ((sizeof(esp_cmd_strings)) / (sizeof(struct esp_cmdstrings)))
+
+/* Print textual representation of an ESP command */
+static inline void esp_print_cmd(unchar espcmd)
+{
+ unchar dma_bit = espcmd & ESP_CMD_DMA;
+ int i;
+
+ espcmd &= ~dma_bit;
+ for(i=0; i");
+}
+
+/* Print the interrupt register's value */
+static inline void esp_print_ireg(unchar intreg)
+{
+ printk("INTREG< ");
+ if(intreg & ESP_INTR_S)
+ printk("SLCT_NATN ");
+ if(intreg & ESP_INTR_SATN)
+ printk("SLCT_ATN ");
+ if(intreg & ESP_INTR_RSEL)
+ printk("RSLCT ");
+ if(intreg & ESP_INTR_FDONE)
+ printk("FDONE ");
+ if(intreg & ESP_INTR_BSERV)
+ printk("BSERV ");
+ if(intreg & ESP_INTR_DC)
+ printk("DISCNCT ");
+ if(intreg & ESP_INTR_IC)
+ printk("ILL_CMD ");
+ if(intreg & ESP_INTR_SR)
+ printk("SCSI_BUS_RESET ");
+ printk(">");
+}
+
+/* Print the sequence step registers contents */
+static inline void esp_print_seqreg(unchar stepreg)
+{
+ stepreg &= ESP_STEP_VBITS;
+ printk("STEP<%s>",
+ (stepreg == ESP_STEP_ASEL ? "SLCT_ARB_CMPLT" :
+ (stepreg == ESP_STEP_SID ? "1BYTE_MSG_SENT" :
+ (stepreg == ESP_STEP_NCMD ? "NOT_IN_CMD_PHASE" :
+ (stepreg == ESP_STEP_PPC ? "CMD_BYTES_LOST" :
+ (stepreg == ESP_STEP_FINI4 ? "CMD_SENT_OK" :
+ "UNKNOWN"))))));
+}
+
+static char *phase_string(int phase)
+{
+ switch(phase) {
+ case not_issued:
+ return "UNISSUED";
+ case in_slct_norm:
+ return "SLCTNORM";
+ case in_slct_stop:
+ return "SLCTSTOP";
+ case in_slct_msg:
+ return "SLCTMSG";
+ case in_slct_tag:
+ return "SLCTTAG";
+ case in_slct_sneg:
+ return "SLCTSNEG";
+ case in_datain:
+ return "DATAIN";
+ case in_dataout:
+ return "DATAOUT";
+ case in_data_done:
+ return "DATADONE";
+ case in_msgin:
+ return "MSGIN";
+ case in_msgincont:
+ return "MSGINCONT";
+ case in_msgindone:
+ return "MSGINDONE";
+ case in_msgout:
+ return "MSGOUT";
+ case in_msgoutdone:
+ return "MSGOUTDONE";
+ case in_cmdbegin:
+ return "CMDBEGIN";
+ case in_cmdend:
+ return "CMDEND";
+ case in_status:
+ return "STATUS";
+ case in_freeing:
+ return "FREEING";
+ case in_the_dark:
+ return "CLUELESS";
+ case in_abortone:
+ return "ABORTONE";
+ case in_abortall:
+ return "ABORTALL";
+ case in_resetdev:
+ return "RESETDEV";
+ case in_resetbus:
+ return "RESETBUS";
+ case in_tgterror:
+ return "TGTERROR";
+ default:
+ return "UNKNOWN";
+ };
+}
+
+#ifdef DEBUG_STATE_MACHINE
+static inline void esp_advance_phase(Scsi_Cmnd *s, int newphase)
+{
+ ESPLOG(("<%s>", phase_string(newphase)));
+ s->SCp.sent_command = s->SCp.phase;
+ s->SCp.phase = newphase;
+}
+#else
+#define esp_advance_phase(__s, __newphase) \
+ (__s)->SCp.sent_command = (__s)->SCp.phase; \
+ (__s)->SCp.phase = (__newphase);
+#endif
+
+#ifdef DEBUG_ESP_CMDS
+static inline void esp_cmd(struct NCR_ESP *esp, struct ESP_regs *eregs,
+ unchar cmd)
+{
+ esp->espcmdlog[esp->espcmdent] = cmd;
+ esp->espcmdent = (esp->espcmdent + 1) & 31;
+ esp_write(eregs->esp_cmnd, cmd);
+}
+#else
+#define esp_cmd(__esp, __eregs, __cmd) esp_write((__eregs)->esp_cmnd, (__cmd))
+#endif
+
+/* How we use the various Linux SCSI data structures for operation.
+ *
+ * struct scsi_cmnd:
+ *
+ * We keep track of the syncronous capabilities of a target
+ * in the device member, using sync_min_period and
+ * sync_max_offset. These are the values we directly write
+ * into the ESP registers while running a command. If offset
+ * is zero the ESP will use asynchronous transfers.
+ * If the borken flag is set we assume we shouldn't even bother
+ * trying to negotiate for synchronous transfer as this target
+ * is really stupid. If we notice the target is dropping the
+ * bus, and we have been allowing it to disconnect, we clear
+ * the disconnect flag.
+ */
+
+/* Manipulation of the ESP command queues. Thanks to the aha152x driver
+ * and its author, Juergen E. Fischer, for the methods used here.
+ * Note that these are per-ESP queues, not global queues like
+ * the aha152x driver uses.
+ */
+static inline void append_SC(Scsi_Cmnd **SC, Scsi_Cmnd *new_SC)
+{
+ Scsi_Cmnd *end;
+
+ new_SC->host_scribble = (unsigned char *) NULL;
+ if(!*SC)
+ *SC = new_SC;
+ else {
+ for(end=*SC;end->host_scribble;end=(Scsi_Cmnd *)end->host_scribble)
+ ;
+ end->host_scribble = (unsigned char *) new_SC;
+ }
+}
+
+static inline void prepend_SC(Scsi_Cmnd **SC, Scsi_Cmnd *new_SC)
+{
+ new_SC->host_scribble = (unsigned char *) *SC;
+ *SC = new_SC;
+}
+
+static inline Scsi_Cmnd *remove_first_SC(Scsi_Cmnd **SC)
+{
+ Scsi_Cmnd *ptr;
+
+ ptr = *SC;
+ if(ptr)
+ *SC = (Scsi_Cmnd *) (*SC)->host_scribble;
+ return ptr;
+}
+
+static inline Scsi_Cmnd *remove_SC(Scsi_Cmnd **SC, int target, int lun)
+{
+ Scsi_Cmnd *ptr, *prev;
+
+ for(ptr = *SC, prev = NULL;
+ ptr && ((ptr->device->id != target) || (ptr->device->lun != lun));
+ prev = ptr, ptr = (Scsi_Cmnd *) ptr->host_scribble)
+ ;
+ if(ptr) {
+ if(prev)
+ prev->host_scribble=ptr->host_scribble;
+ else
+ *SC=(Scsi_Cmnd *)ptr->host_scribble;
+ }
+ return ptr;
+}
+
+/* Resetting various pieces of the ESP scsi driver chipset */
+
+/* Reset the ESP chip, _not_ the SCSI bus. */
+static void esp_reset_esp(struct NCR_ESP *esp, struct ESP_regs *eregs)
+{
+ int family_code, version, i;
+ volatile int trash;
+
+ /* Now reset the ESP chip */
+ esp_cmd(esp, eregs, ESP_CMD_RC);
+ esp_cmd(esp, eregs, ESP_CMD_NULL | ESP_CMD_DMA);
+ if(esp->erev == fast)
+ esp_write(eregs->esp_cfg2, ESP_CONFIG2_FENAB);
+ esp_cmd(esp, eregs, ESP_CMD_NULL | ESP_CMD_DMA);
+
+ /* This is the only point at which it is reliable to read
+ * the ID-code for a fast ESP chip variant.
+ */
+ esp->max_period = ((35 * esp->ccycle) / 1000);
+ if(esp->erev == fast) {
+ char *erev2string[] = {
+ "Emulex FAS236",
+ "Emulex FPESP100A",
+ "fast",
+ "QLogic FAS366",
+ "Emulex FAS216",
+ "Symbios Logic 53CF9x-2",
+ "unknown!"
+ };
+
+ version = esp_read(eregs->esp_uid);
+ family_code = (version & 0xf8) >> 3;
+ if(family_code == 0x02) {
+ if ((version & 7) == 2)
+ esp->erev = fas216;
+ else
+ esp->erev = fas236;
+ } else if(family_code == 0x0a)
+ esp->erev = fas366; /* Version is usually '5'. */
+ else if(family_code == 0x00) {
+ if ((version & 7) == 2)
+ esp->erev = fas100a; /* NCR53C9X */
+ else
+ esp->erev = espunknown;
+ } else if(family_code == 0x14) {
+ if ((version & 7) == 2)
+ esp->erev = fsc;
+ else
+ esp->erev = espunknown;
+ } else if(family_code == 0x00) {
+ if ((version & 7) == 2)
+ esp->erev = fas100a; /* NCR53C9X */
+ else
+ esp->erev = espunknown;
+ } else
+ esp->erev = espunknown;
+ ESPLOG(("esp%d: FAST chip is %s (family=%d, version=%d)\n",
+ esp->esp_id, erev2string[esp->erev - fas236],
+ family_code, (version & 7)));
+
+ esp->min_period = ((4 * esp->ccycle) / 1000);
+ } else {
+ esp->min_period = ((5 * esp->ccycle) / 1000);
+ }
+
+ /* Reload the configuration registers */
+ esp_write(eregs->esp_cfact, esp->cfact);
+ esp->prev_stp = 0;
+ esp_write(eregs->esp_stp, 0);
+ esp->prev_soff = 0;
+ esp_write(eregs->esp_soff, 0);
+ esp_write(eregs->esp_timeo, esp->neg_defp);
+ esp->max_period = (esp->max_period + 3)>>2;
+ esp->min_period = (esp->min_period + 3)>>2;
+
+ esp_write(eregs->esp_cfg1, esp->config1);
+ switch(esp->erev) {
+ case esp100:
+ /* nothing to do */
+ break;
+ case esp100a:
+ esp_write(eregs->esp_cfg2, esp->config2);
+ break;
+ case esp236:
+ /* Slow 236 */
+ esp_write(eregs->esp_cfg2, esp->config2);
+ esp->prev_cfg3 = esp->config3[0];
+ esp_write(eregs->esp_cfg3, esp->prev_cfg3);
+ break;
+ case fas366:
+ panic("esp: FAS366 support not present, please notify "
+ "jongk@cs.utwente.nl");
+ break;
+ case fas216:
+ case fas236:
+ case fsc:
+ /* Fast ESP variants */
+ esp_write(eregs->esp_cfg2, esp->config2);
+ for(i=0; i<8; i++)
+ esp->config3[i] |= ESP_CONFIG3_FCLK;
+ esp->prev_cfg3 = esp->config3[0];
+ esp_write(eregs->esp_cfg3, esp->prev_cfg3);
+ if(esp->diff)
+ esp->radelay = 0;
+ else
+ esp->radelay = 16;
+ /* Different timeout constant for these chips */
+ esp->neg_defp =
+ FSC_NEG_DEFP(esp->cfreq,
+ (esp->cfact == ESP_CCF_F0 ?
+ ESP_CCF_F7 + 1 : esp->cfact));
+ esp_write(eregs->esp_timeo, esp->neg_defp);
+ /* Enable Active Negotiation if possible */
+ if((esp->erev == fsc) && !esp->diff)
+ esp_write(eregs->esp_cfg4, ESP_CONFIG4_EAN);
+ break;
+ case fas100a:
+ /* Fast 100a */
+ esp_write(eregs->esp_cfg2, esp->config2);
+ for(i=0; i<8; i++)
+ esp->config3[i] |= ESP_CONFIG3_FCLOCK;
+ esp->prev_cfg3 = esp->config3[0];
+ esp_write(eregs->esp_cfg3, esp->prev_cfg3);
+ esp->radelay = 32;
+ break;
+ default:
+ panic("esp: what could it be... I wonder...");
+ break;
+ };
+
+ /* Eat any bitrot in the chip */
+ trash = esp_read(eregs->esp_intrpt);
+ udelay(100);
+}
+
+/* This places the ESP into a known state at boot time. */
+void esp_bootup_reset(struct NCR_ESP *esp, struct ESP_regs *eregs)
+{
+ volatile unchar trash;
+
+ /* Reset the DMA */
+ if(esp->dma_reset)
+ esp->dma_reset(esp);
+
+ /* Reset the ESP */
+ esp_reset_esp(esp, eregs);
+
+ /* Reset the SCSI bus, but tell ESP not to generate an irq */
+ esp_write(eregs->esp_cfg1, (esp_read(eregs->esp_cfg1) | ESP_CONFIG1_SRRDISAB));
+ esp_cmd(esp, eregs, ESP_CMD_RS);
+ udelay(400);
+ esp_write(eregs->esp_cfg1, esp->config1);
+
+ /* Eat any bitrot in the chip and we are done... */
+ trash = esp_read(eregs->esp_intrpt);
+}
+EXPORT_SYMBOL(esp_bootup_reset);
+
+/* Allocate structure and insert basic data such as SCSI chip frequency
+ * data and a pointer to the device
+ */
+struct NCR_ESP* esp_allocate(struct scsi_host_template *tpnt, void *esp_dev,
+ int hotplug)
+{
+ struct NCR_ESP *esp, *elink;
+ struct Scsi_Host *esp_host;
+
+ if (hotplug)
+ esp_host = scsi_host_alloc(tpnt, sizeof(struct NCR_ESP));
+ else
+ esp_host = scsi_register(tpnt, sizeof(struct NCR_ESP));
+ if(!esp_host)
+ panic("Cannot register ESP SCSI host");
+ esp = (struct NCR_ESP *) esp_host->hostdata;
+ if(!esp)
+ panic("No esp in hostdata");
+ esp->ehost = esp_host;
+ esp->edev = esp_dev;
+ esp->esp_id = nesps++;
+
+ /* Set bitshift value (only used on Amiga with multiple ESPs) */
+ esp->shift = 2;
+
+ /* Put into the chain of esp chips detected */
+ if(espchain) {
+ elink = espchain;
+ while(elink->next) elink = elink->next;
+ elink->next = esp;
+ } else {
+ espchain = esp;
+ }
+ esp->next = NULL;
+
+ return esp;
+}
+
+void esp_deallocate(struct NCR_ESP *esp)
+{
+ struct NCR_ESP *elink;
+
+ if(espchain == esp) {
+ espchain = NULL;
+ } else {
+ for(elink = espchain; elink && (elink->next != esp); elink = elink->next);
+ if(elink)
+ elink->next = esp->next;
+ }
+ nesps--;
+}
+
+/* Complete initialization of ESP structure and device
+ * Caller must have initialized appropriate parts of the ESP structure
+ * between the call to esp_allocate and this function.
+ */
+void esp_initialize(struct NCR_ESP *esp)
+{
+ struct ESP_regs *eregs = esp->eregs;
+ unsigned int fmhz;
+ unchar ccf;
+ int i;
+
+ /* Check out the clock properties of the chip. */
+
+ /* This is getting messy but it has to be done
+ * correctly or else you get weird behavior all
+ * over the place. We are trying to basically
+ * figure out three pieces of information.
+ *
+ * a) Clock Conversion Factor
+ *
+ * This is a representation of the input
+ * crystal clock frequency going into the
+ * ESP on this machine. Any operation whose
+ * timing is longer than 400ns depends on this
+ * value being correct. For example, you'll
+ * get blips for arbitration/selection during
+ * high load or with multiple targets if this
+ * is not set correctly.
+ *
+ * b) Selection Time-Out
+ *
+ * The ESP isn't very bright and will arbitrate
+ * for the bus and try to select a target
+ * forever if you let it. This value tells
+ * the ESP when it has taken too long to
+ * negotiate and that it should interrupt
+ * the CPU so we can see what happened.
+ * The value is computed as follows (from
+ * NCR/Symbios chip docs).
+ *
+ * (Time Out Period) * (Input Clock)
+ * STO = ----------------------------------
+ * (8192) * (Clock Conversion Factor)
+ *
+ * You usually want the time out period to be
+ * around 250ms, I think we'll set it a little
+ * bit higher to account for fully loaded SCSI
+ * bus's and slow devices that don't respond so
+ * quickly to selection attempts. (yeah, I know
+ * this is out of spec. but there is a lot of
+ * buggy pieces of firmware out there so bite me)
+ *
+ * c) Imperical constants for synchronous offset
+ * and transfer period register values
+ *
+ * This entails the smallest and largest sync
+ * period we could ever handle on this ESP.
+ */
+
+ fmhz = esp->cfreq;
+
+ if(fmhz <= (5000000))
+ ccf = 0;
+ else
+ ccf = (((5000000 - 1) + (fmhz))/(5000000));
+ if(!ccf || ccf > 8) {
+ /* If we can't find anything reasonable,
+ * just assume 20MHZ. This is the clock
+ * frequency of the older sun4c's where I've
+ * been unable to find the clock-frequency
+ * PROM property. All other machines provide
+ * useful values it seems.
+ */
+ ccf = ESP_CCF_F4;
+ fmhz = (20000000);
+ }
+ if(ccf==(ESP_CCF_F7+1))
+ esp->cfact = ESP_CCF_F0;
+ else if(ccf == ESP_CCF_NEVER)
+ esp->cfact = ESP_CCF_F2;
+ else
+ esp->cfact = ccf;
+ esp->cfreq = fmhz;
+ esp->ccycle = ESP_MHZ_TO_CYCLE(fmhz);
+ esp->ctick = ESP_TICK(ccf, esp->ccycle);
+ esp->neg_defp = ESP_NEG_DEFP(fmhz, ccf);
+ esp->sync_defp = SYNC_DEFP_SLOW;
+
+ printk("SCSI ID %d Clk %dMHz CCF=%d TOut %d ",
+ esp->scsi_id, (esp->cfreq / 1000000),
+ ccf, (int) esp->neg_defp);
+
+ /* Fill in ehost data */
+ esp->ehost->base = (unsigned long)eregs;
+ esp->ehost->this_id = esp->scsi_id;
+ esp->ehost->irq = esp->irq;
+
+ /* SCSI id mask */
+ esp->scsi_id_mask = (1 << esp->scsi_id);
+
+ /* Probe the revision of this esp */
+ esp->config1 = (ESP_CONFIG1_PENABLE | (esp->scsi_id & 7));
+ esp->config2 = (ESP_CONFIG2_SCSI2ENAB | ESP_CONFIG2_REGPARITY);
+ esp_write(eregs->esp_cfg2, esp->config2);
+ if((esp_read(eregs->esp_cfg2) & ~(ESP_CONFIG2_MAGIC)) !=
+ (ESP_CONFIG2_SCSI2ENAB | ESP_CONFIG2_REGPARITY)) {
+ printk("NCR53C90(esp100)\n");
+ esp->erev = esp100;
+ } else {
+ esp->config2 = 0;
+ esp_write(eregs->esp_cfg2, 0);
+ esp_write(eregs->esp_cfg3, 5);
+ if(esp_read(eregs->esp_cfg3) != 5) {
+ printk("NCR53C90A(esp100a)\n");
+ esp->erev = esp100a;
+ } else {
+ int target;
+
+ for(target=0; target<8; target++)
+ esp->config3[target] = 0;
+ esp->prev_cfg3 = 0;
+ esp_write(eregs->esp_cfg3, 0);
+ if(ccf > ESP_CCF_F5) {
+ printk("NCR53C9XF(espfast)\n");
+ esp->erev = fast;
+ esp->sync_defp = SYNC_DEFP_FAST;
+ } else {
+ printk("NCR53C9x(esp236)\n");
+ esp->erev = esp236;
+ }
+ }
+ }
+
+ /* Initialize the command queues */
+ esp->current_SC = NULL;
+ esp->disconnected_SC = NULL;
+ esp->issue_SC = NULL;
+
+ /* Clear the state machines. */
+ esp->targets_present = 0;
+ esp->resetting_bus = 0;
+ esp->snip = 0;
+
+ init_waitqueue_head(&esp->reset_queue);
+
+ esp->fas_premature_intr_workaround = 0;
+ for(i = 0; i < 32; i++)
+ esp->espcmdlog[i] = 0;
+ esp->espcmdent = 0;
+ for(i = 0; i < 16; i++) {
+ esp->cur_msgout[i] = 0;
+ esp->cur_msgin[i] = 0;
+ }
+ esp->prevmsgout = esp->prevmsgin = 0;
+ esp->msgout_len = esp->msgin_len = 0;
+
+ /* Clear the one behind caches to hold unmatchable values. */
+ esp->prev_soff = esp->prev_stp = esp->prev_cfg3 = 0xff;
+
+ /* Reset the thing before we try anything... */
+ esp_bootup_reset(esp, eregs);
+
+ esps_in_use++;
+}
+
+/* The info function will return whatever useful
+ * information the developer sees fit. If not provided, then
+ * the name field will be used instead.
+ */
+const char *esp_info(struct Scsi_Host *host)
+{
+ struct NCR_ESP *esp;
+
+ esp = (struct NCR_ESP *) host->hostdata;
+ switch(esp->erev) {
+ case esp100:
+ return "ESP100 (NCR53C90)";
+ case esp100a:
+ return "ESP100A (NCR53C90A)";
+ case esp236:
+ return "ESP236 (NCR53C9x)";
+ case fas216:
+ return "Emulex FAS216";
+ case fas236:
+ return "Emulex FAS236";
+ case fas366:
+ return "QLogic FAS366";
+ case fas100a:
+ return "FPESP100A";
+ case fsc:
+ return "Symbios Logic 53CF9x-2";
+ default:
+ panic("Bogon ESP revision");
+ };
+}
+EXPORT_SYMBOL(esp_info);
+
+/* From Wolfgang Stanglmeier's NCR scsi driver. */
+struct info_str
+{
+ char *buffer;
+ int length;
+ int offset;
+ int pos;
+};
+
+static void copy_mem_info(struct info_str *info, char *data, int len)
+{
+ if (info->pos + len > info->length)
+ len = info->length - info->pos;
+
+ if (info->pos + len < info->offset) {
+ info->pos += len;
+ return;
+ }
+ if (info->pos < info->offset) {
+ data += (info->offset - info->pos);
+ len -= (info->offset - info->pos);
+ }
+
+ if (len > 0) {
+ memcpy(info->buffer + info->pos, data, len);
+ info->pos += len;
+ }
+}
+
+static int copy_info(struct info_str *info, char *fmt, ...)
+{
+ va_list args;
+ char buf[81];
+ int len;
+
+ va_start(args, fmt);
+ len = vsprintf(buf, fmt, args);
+ va_end(args);
+
+ copy_mem_info(info, buf, len);
+ return len;
+}
+
+static int esp_host_info(struct NCR_ESP *esp, char *ptr, off_t offset, int len)
+{
+ struct scsi_device *sdev;
+ struct info_str info;
+ int i;
+
+ info.buffer = ptr;
+ info.length = len;
+ info.offset = offset;
+ info.pos = 0;
+
+ copy_info(&info, "ESP Host Adapter:\n");
+ copy_info(&info, "\tESP Model\t\t");
+ switch(esp->erev) {
+ case esp100:
+ copy_info(&info, "ESP100 (NCR53C90)\n");
+ break;
+ case esp100a:
+ copy_info(&info, "ESP100A (NCR53C90A)\n");
+ break;
+ case esp236:
+ copy_info(&info, "ESP236 (NCR53C9x)\n");
+ break;
+ case fas216:
+ copy_info(&info, "Emulex FAS216\n");
+ break;
+ case fas236:
+ copy_info(&info, "Emulex FAS236\n");
+ break;
+ case fas100a:
+ copy_info(&info, "FPESP100A\n");
+ break;
+ case fast:
+ copy_info(&info, "Generic FAST\n");
+ break;
+ case fas366:
+ copy_info(&info, "QLogic FAS366\n");
+ break;
+ case fsc:
+ copy_info(&info, "Symbios Logic 53C9x-2\n");
+ break;
+ case espunknown:
+ default:
+ copy_info(&info, "Unknown!\n");
+ break;
+ };
+ copy_info(&info, "\tLive Targets\t\t[ ");
+ for(i = 0; i < 15; i++) {
+ if(esp->targets_present & (1 << i))
+ copy_info(&info, "%d ", i);
+ }
+ copy_info(&info, "]\n\n");
+
+ /* Now describe the state of each existing target. */
+ copy_info(&info, "Target #\tconfig3\t\tSync Capabilities\tDisconnect\n");
+
+ shost_for_each_device(sdev, esp->ehost) {
+ struct esp_device *esp_dev = sdev->hostdata;
+ uint id = sdev->id;
+
+ if (!(esp->targets_present & (1 << id)))
+ continue;
+
+ copy_info(&info, "%d\t\t", id);
+ copy_info(&info, "%08lx\t", esp->config3[id]);
+ copy_info(&info, "[%02lx,%02lx]\t\t\t",
+ esp_dev->sync_max_offset,
+ esp_dev->sync_min_period);
+ copy_info(&info, "%s\n", esp_dev->disconnect ? "yes" : "no");
+ }
+
+ return info.pos > info.offset? info.pos - info.offset : 0;
+}
+
+/* ESP proc filesystem code. */
+int esp_proc_info(struct Scsi_Host *shost, char *buffer, char **start, off_t offset, int length,
+ int inout)
+{
+ struct NCR_ESP *esp = (struct NCR_ESP *)shost->hostdata;
+
+ if(inout)
+ return -EINVAL; /* not yet */
+ if(start)
+ *start = buffer;
+ return esp_host_info(esp, buffer, offset, length);
+}
+EXPORT_SYMBOL(esp_proc_info);
+
+static void esp_get_dmabufs(struct NCR_ESP *esp, Scsi_Cmnd *sp)
+{
+ if(sp->use_sg == 0) {
+ sp->SCp.this_residual = sp->request_bufflen;
+ sp->SCp.buffer = (struct scatterlist *) sp->request_buffer;
+ sp->SCp.buffers_residual = 0;
+ if (esp->dma_mmu_get_scsi_one)
+ esp->dma_mmu_get_scsi_one(esp, sp);
+ else
+ sp->SCp.ptr =
+ (char *) virt_to_phys(sp->request_buffer);
+ } else {
+ sp->SCp.buffer = (struct scatterlist *) sp->request_buffer;
+ sp->SCp.buffers_residual = sp->use_sg - 1;
+ sp->SCp.this_residual = sp->SCp.buffer->length;
+ if (esp->dma_mmu_get_scsi_sgl)
+ esp->dma_mmu_get_scsi_sgl(esp, sp);
+ else
+ sp->SCp.ptr =
+ (char *) virt_to_phys(sg_virt(sp->SCp.buffer));
+ }
+}
+
+static void esp_release_dmabufs(struct NCR_ESP *esp, Scsi_Cmnd *sp)
+{
+ if(sp->use_sg == 0) {
+ if (esp->dma_mmu_release_scsi_one)
+ esp->dma_mmu_release_scsi_one(esp, sp);
+ } else {
+ if (esp->dma_mmu_release_scsi_sgl)
+ esp->dma_mmu_release_scsi_sgl(esp, sp);
+ }
+}
+
+static void esp_restore_pointers(struct NCR_ESP *esp, Scsi_Cmnd *sp)
+{
+ struct esp_pointers *ep = &esp->data_pointers[scmd_id(sp)];
+
+ sp->SCp.ptr = ep->saved_ptr;
+ sp->SCp.buffer = ep->saved_buffer;
+ sp->SCp.this_residual = ep->saved_this_residual;
+ sp->SCp.buffers_residual = ep->saved_buffers_residual;
+}
+
+static void esp_save_pointers(struct NCR_ESP *esp, Scsi_Cmnd *sp)
+{
+ struct esp_pointers *ep = &esp->data_pointers[scmd_id(sp)];
+
+ ep->saved_ptr = sp->SCp.ptr;
+ ep->saved_buffer = sp->SCp.buffer;
+ ep->saved_this_residual = sp->SCp.this_residual;
+ ep->saved_buffers_residual = sp->SCp.buffers_residual;
+}
+
+/* Some rules:
+ *
+ * 1) Never ever panic while something is live on the bus.
+ * If there is to be any chance of syncing the disks this
+ * rule is to be obeyed.
+ *
+ * 2) Any target that causes a foul condition will no longer
+ * have synchronous transfers done to it, no questions
+ * asked.
+ *
+ * 3) Keep register accesses to a minimum. Think about some
+ * day when we have Xbus machines this is running on and
+ * the ESP chip is on the other end of the machine on a
+ * different board from the cpu where this is running.
+ */
+
+/* Fire off a command. We assume the bus is free and that the only
+ * case where we could see an interrupt is where we have disconnected
+ * commands active and they are trying to reselect us.
+ */
+static inline void esp_check_cmd(struct NCR_ESP *esp, Scsi_Cmnd *sp)
+{
+ switch(sp->cmd_len) {
+ case 6:
+ case 10:
+ case 12:
+ esp->esp_slowcmd = 0;
+ break;
+
+ default:
+ esp->esp_slowcmd = 1;
+ esp->esp_scmdleft = sp->cmd_len;
+ esp->esp_scmdp = &sp->cmnd[0];
+ break;
+ };
+}
+
+static inline void build_sync_nego_msg(struct NCR_ESP *esp, int period, int offset)
+{
+ esp->cur_msgout[0] = EXTENDED_MESSAGE;
+ esp->cur_msgout[1] = 3;
+ esp->cur_msgout[2] = EXTENDED_SDTR;
+ esp->cur_msgout[3] = period;
+ esp->cur_msgout[4] = offset;
+ esp->msgout_len = 5;
+}
+
+static void esp_exec_cmd(struct NCR_ESP *esp)
+{
+ struct ESP_regs *eregs = esp->eregs;
+ struct esp_device *esp_dev;
+ Scsi_Cmnd *SCptr;
+ struct scsi_device *SDptr;
+ volatile unchar *cmdp = esp->esp_command;
+ unsigned char the_esp_command;
+ int lun, target;
+ int i;
+
+ /* Hold off if we have disconnected commands and
+ * an IRQ is showing...
+ */
+ if(esp->disconnected_SC && esp->dma_irq_p(esp))
+ return;
+
+ /* Grab first member of the issue queue. */
+ SCptr = esp->current_SC = remove_first_SC(&esp->issue_SC);
+
+ /* Safe to panic here because current_SC is null. */
+ if(!SCptr)
+ panic("esp: esp_exec_cmd and issue queue is NULL");
+
+ SDptr = SCptr->device;
+ esp_dev = SDptr->hostdata;
+ lun = SCptr->device->lun;
+ target = SCptr->device->id;
+
+ esp->snip = 0;
+ esp->msgout_len = 0;
+
+ /* Send it out whole, or piece by piece? The ESP
+ * only knows how to automatically send out 6, 10,
+ * and 12 byte commands. I used to think that the
+ * Linux SCSI code would never throw anything other
+ * than that to us, but then again there is the
+ * SCSI generic driver which can send us anything.
+ */
+ esp_check_cmd(esp, SCptr);
+
+ /* If arbitration/selection is successful, the ESP will leave
+ * ATN asserted, causing the target to go into message out
+ * phase. The ESP will feed the target the identify and then
+ * the target can only legally go to one of command,
+ * datain/out, status, or message in phase, or stay in message
+ * out phase (should we be trying to send a sync negotiation
+ * message after the identify). It is not allowed to drop
+ * BSY, but some buggy targets do and we check for this
+ * condition in the selection complete code. Most of the time
+ * we'll make the command bytes available to the ESP and it
+ * will not interrupt us until it finishes command phase, we
+ * cannot do this for command sizes the ESP does not
+ * understand and in this case we'll get interrupted right
+ * when the target goes into command phase.
+ *
+ * It is absolutely _illegal_ in the presence of SCSI-2 devices
+ * to use the ESP select w/o ATN command. When SCSI-2 devices are
+ * present on the bus we _must_ always go straight to message out
+ * phase with an identify message for the target. Being that
+ * selection attempts in SCSI-1 w/o ATN was an option, doing SCSI-2
+ * selections should not confuse SCSI-1 we hope.
+ */
+
+ if(esp_dev->sync) {
+ /* this targets sync is known */
+#ifdef CONFIG_SCSI_MAC_ESP
+do_sync_known:
+#endif
+ if(esp_dev->disconnect)
+ *cmdp++ = IDENTIFY(1, lun);
+ else
+ *cmdp++ = IDENTIFY(0, lun);
+
+ if(esp->esp_slowcmd) {
+ the_esp_command = (ESP_CMD_SELAS | ESP_CMD_DMA);
+ esp_advance_phase(SCptr, in_slct_stop);
+ } else {
+ the_esp_command = (ESP_CMD_SELA | ESP_CMD_DMA);
+ esp_advance_phase(SCptr, in_slct_norm);
+ }
+ } else if(!(esp->targets_present & (1<disconnect)) {
+ /* After the bootup SCSI code sends both the
+ * TEST_UNIT_READY and INQUIRY commands we want
+ * to at least attempt allowing the device to
+ * disconnect.
+ */
+ ESPMISC(("esp: Selecting device for first time. target=%d "
+ "lun=%d\n", target, SCptr->device->lun));
+ if(!SDptr->borken && !esp_dev->disconnect)
+ esp_dev->disconnect = 1;
+
+ *cmdp++ = IDENTIFY(0, lun);
+ esp->prevmsgout = NOP;
+ esp_advance_phase(SCptr, in_slct_norm);
+ the_esp_command = (ESP_CMD_SELA | ESP_CMD_DMA);
+
+ /* Take no chances... */
+ esp_dev->sync_max_offset = 0;
+ esp_dev->sync_min_period = 0;
+ } else {
+ int toshiba_cdrom_hwbug_wkaround = 0;
+
+#ifdef CONFIG_SCSI_MAC_ESP
+ /* Never allow synchronous transfers (disconnect OK) on
+ * Macintosh. Well, maybe later when we figured out how to
+ * do DMA on the machines that support it ...
+ */
+ esp_dev->disconnect = 1;
+ esp_dev->sync_max_offset = 0;
+ esp_dev->sync_min_period = 0;
+ esp_dev->sync = 1;
+ esp->snip = 0;
+ goto do_sync_known;
+#endif
+ /* We've talked to this guy before,
+ * but never negotiated. Let's try
+ * sync negotiation.
+ */
+ if(!SDptr->borken) {
+ if((SDptr->type == TYPE_ROM) &&
+ (!strncmp(SDptr->vendor, "TOSHIBA", 7))) {
+ /* Nice try sucker... */
+ ESPMISC(("esp%d: Disabling sync for buggy "
+ "Toshiba CDROM.\n", esp->esp_id));
+ toshiba_cdrom_hwbug_wkaround = 1;
+ build_sync_nego_msg(esp, 0, 0);
+ } else {
+ build_sync_nego_msg(esp, esp->sync_defp, 15);
+ }
+ } else {
+ build_sync_nego_msg(esp, 0, 0);
+ }
+ esp_dev->sync = 1;
+ esp->snip = 1;
+
+ /* A fix for broken SCSI1 targets, when they disconnect
+ * they lock up the bus and confuse ESP. So disallow
+ * disconnects for SCSI1 targets for now until we
+ * find a better fix.
+ *
+ * Addendum: This is funny, I figured out what was going
+ * on. The blotzed SCSI1 target would disconnect,
+ * one of the other SCSI2 targets or both would be
+ * disconnected as well. The SCSI1 target would
+ * stay disconnected long enough that we start
+ * up a command on one of the SCSI2 targets. As
+ * the ESP is arbitrating for the bus the SCSI1
+ * target begins to arbitrate as well to reselect
+ * the ESP. The SCSI1 target refuses to drop it's
+ * ID bit on the data bus even though the ESP is
+ * at ID 7 and is the obvious winner for any
+ * arbitration. The ESP is a poor sport and refuses
+ * to lose arbitration, it will continue indefinitely
+ * trying to arbitrate for the bus and can only be
+ * stopped via a chip reset or SCSI bus reset.
+ * Therefore _no_ disconnects for SCSI1 targets
+ * thank you very much. ;-)
+ */
+ if(((SDptr->scsi_level < 3) && (SDptr->type != TYPE_TAPE)) ||
+ toshiba_cdrom_hwbug_wkaround || SDptr->borken) {
+ ESPMISC((KERN_INFO "esp%d: Disabling DISCONNECT for target %d "
+ "lun %d\n", esp->esp_id, SCptr->device->id, SCptr->device->lun));
+ esp_dev->disconnect = 0;
+ *cmdp++ = IDENTIFY(0, lun);
+ } else {
+ *cmdp++ = IDENTIFY(1, lun);
+ }
+
+ /* ESP fifo is only so big...
+ * Make this look like a slow command.
+ */
+ esp->esp_slowcmd = 1;
+ esp->esp_scmdleft = SCptr->cmd_len;
+ esp->esp_scmdp = &SCptr->cmnd[0];
+
+ the_esp_command = (ESP_CMD_SELAS | ESP_CMD_DMA);
+ esp_advance_phase(SCptr, in_slct_msg);
+ }
+
+ if(!esp->esp_slowcmd)
+ for(i = 0; i < SCptr->cmd_len; i++)
+ *cmdp++ = SCptr->cmnd[i];
+
+ esp_write(eregs->esp_busid, (target & 7));
+ if (esp->prev_soff != esp_dev->sync_max_offset ||
+ esp->prev_stp != esp_dev->sync_min_period ||
+ (esp->erev > esp100a &&
+ esp->prev_cfg3 != esp->config3[target])) {
+ esp->prev_soff = esp_dev->sync_max_offset;
+ esp_write(eregs->esp_soff, esp->prev_soff);
+ esp->prev_stp = esp_dev->sync_min_period;
+ esp_write(eregs->esp_stp, esp->prev_stp);
+ if(esp->erev > esp100a) {
+ esp->prev_cfg3 = esp->config3[target];
+ esp_write(eregs->esp_cfg3, esp->prev_cfg3);
+ }
+ }
+ i = (cmdp - esp->esp_command);
+
+ /* Set up the DMA and ESP counters */
+ if(esp->do_pio_cmds){
+ int j = 0;
+
+ /*
+ * XXX MSch:
+ *
+ * It seems this is required, at least to clean up
+ * after failed commands when using PIO mode ...
+ */
+ esp_cmd(esp, eregs, ESP_CMD_FLUSH);
+
+ for(;jesp_fdata, esp->esp_command[j]);
+ the_esp_command &= ~ESP_CMD_DMA;
+
+ /* Tell ESP to "go". */
+ esp_cmd(esp, eregs, the_esp_command);
+ } else {
+ /* Set up the ESP counters */
+ esp_write(eregs->esp_tclow, i);
+ esp_write(eregs->esp_tcmed, 0);
+ esp->dma_init_write(esp, esp->esp_command_dvma, i);
+
+ /* Tell ESP to "go". */
+ esp_cmd(esp, eregs, the_esp_command);
+ }
+}
+
+/* Queue a SCSI command delivered from the mid-level Linux SCSI code. */
+int esp_queue(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
+{
+ struct NCR_ESP *esp;
+
+ /* Set up func ptr and initial driver cmd-phase. */
+ SCpnt->scsi_done = done;
+ SCpnt->SCp.phase = not_issued;
+
+ esp = (struct NCR_ESP *) SCpnt->device->host->hostdata;
+
+ if(esp->dma_led_on)
+ esp->dma_led_on(esp);
+
+ /* We use the scratch area. */
+ ESPQUEUE(("esp_queue: target=%d lun=%d ", SCpnt->device->id, SCpnt->lun));
+ ESPDISC(("N<%02x,%02x>", SCpnt->device->id, SCpnt->lun));
+
+ esp_get_dmabufs(esp, SCpnt);
+ esp_save_pointers(esp, SCpnt); /* FIXME for tag queueing */
+
+ SCpnt->SCp.Status = CHECK_CONDITION;
+ SCpnt->SCp.Message = 0xff;
+ SCpnt->SCp.sent_command = 0;
+
+ /* Place into our queue. */
+ if(SCpnt->cmnd[0] == REQUEST_SENSE) {
+ ESPQUEUE(("RQSENSE\n"));
+ prepend_SC(&esp->issue_SC, SCpnt);
+ } else {
+ ESPQUEUE(("\n"));
+ append_SC(&esp->issue_SC, SCpnt);
+ }
+
+ /* Run it now if we can. */
+ if(!esp->current_SC && !esp->resetting_bus)
+ esp_exec_cmd(esp);
+
+ return 0;
+}
+
+/* Dump driver state. */
+static void esp_dump_cmd(Scsi_Cmnd *SCptr)
+{
+ ESPLOG(("[tgt<%02x> lun<%02x> "
+ "pphase<%s> cphase<%s>]",
+ SCptr->device->id, SCptr->device->lun,
+ phase_string(SCptr->SCp.sent_command),
+ phase_string(SCptr->SCp.phase)));
+}
+
+static void esp_dump_state(struct NCR_ESP *esp,
+ struct ESP_regs *eregs)
+{
+ Scsi_Cmnd *SCptr = esp->current_SC;
+#ifdef DEBUG_ESP_CMDS
+ int i;
+#endif
+
+ ESPLOG(("esp%d: dumping state\n", esp->esp_id));
+
+ /* Print DMA status */
+ esp->dma_dump_state(esp);
+
+ ESPLOG(("esp%d: SW [sreg<%02x> sstep<%02x> ireg<%02x>]\n",
+ esp->esp_id, esp->sreg, esp->seqreg, esp->ireg));
+ ESPLOG(("esp%d: HW reread [sreg<%02x> sstep<%02x> ireg<%02x>]\n",
+ esp->esp_id, esp_read(eregs->esp_status), esp_read(eregs->esp_sstep),
+ esp_read(eregs->esp_intrpt)));
+#ifdef DEBUG_ESP_CMDS
+ printk("esp%d: last ESP cmds [", esp->esp_id);
+ i = (esp->espcmdent - 1) & 31;
+ printk("<");
+ esp_print_cmd(esp->espcmdlog[i]);
+ printk(">");
+ i = (i - 1) & 31;
+ printk("<");
+ esp_print_cmd(esp->espcmdlog[i]);
+ printk(">");
+ i = (i - 1) & 31;
+ printk("<");
+ esp_print_cmd(esp->espcmdlog[i]);
+ printk(">");
+ i = (i - 1) & 31;
+ printk("<");
+ esp_print_cmd(esp->espcmdlog[i]);
+ printk(">");
+ printk("]\n");
+#endif /* (DEBUG_ESP_CMDS) */
+
+ if(SCptr) {
+ ESPLOG(("esp%d: current command ", esp->esp_id));
+ esp_dump_cmd(SCptr);
+ }
+ ESPLOG(("\n"));
+ SCptr = esp->disconnected_SC;
+ ESPLOG(("esp%d: disconnected ", esp->esp_id));
+ while(SCptr) {
+ esp_dump_cmd(SCptr);
+ SCptr = (Scsi_Cmnd *) SCptr->host_scribble;
+ }
+ ESPLOG(("\n"));
+}
+
+/* Abort a command. The host_lock is acquired by caller. */
+int esp_abort(Scsi_Cmnd *SCptr)
+{
+ struct NCR_ESP *esp = (struct NCR_ESP *) SCptr->device->host->hostdata;
+ struct ESP_regs *eregs = esp->eregs;
+ int don;
+
+ ESPLOG(("esp%d: Aborting command\n", esp->esp_id));
+ esp_dump_state(esp, eregs);
+
+ /* Wheee, if this is the current command on the bus, the
+ * best we can do is assert ATN and wait for msgout phase.
+ * This should even fix a hung SCSI bus when we lose state
+ * in the driver and timeout because the eventual phase change
+ * will cause the ESP to (eventually) give an interrupt.
+ */
+ if(esp->current_SC == SCptr) {
+ esp->cur_msgout[0] = ABORT;
+ esp->msgout_len = 1;
+ esp->msgout_ctr = 0;
+ esp_cmd(esp, eregs, ESP_CMD_SATN);
+ return SUCCESS;
+ }
+
+ /* If it is still in the issue queue then we can safely
+ * call the completion routine and report abort success.
+ */
+ don = esp->dma_ports_p(esp);
+ if(don) {
+ esp->dma_ints_off(esp);
+ synchronize_irq(esp->irq);
+ }
+ if(esp->issue_SC) {
+ Scsi_Cmnd **prev, *this;
+ for(prev = (&esp->issue_SC), this = esp->issue_SC;
+ this;
+ prev = (Scsi_Cmnd **) &(this->host_scribble),
+ this = (Scsi_Cmnd *) this->host_scribble) {
+ if(this == SCptr) {
+ *prev = (Scsi_Cmnd *) this->host_scribble;
+ this->host_scribble = NULL;
+ esp_release_dmabufs(esp, this);
+ this->result = DID_ABORT << 16;
+ this->scsi_done(this);
+ if(don)
+ esp->dma_ints_on(esp);
+ return SUCCESS;
+ }
+ }
+ }
+
+ /* Yuck, the command to abort is disconnected, it is not
+ * worth trying to abort it now if something else is live
+ * on the bus at this time. So, we let the SCSI code wait
+ * a little bit and try again later.
+ */
+ if(esp->current_SC) {
+ if(don)
+ esp->dma_ints_on(esp);
+ return FAILED;
+ }
+
+ /* It's disconnected, we have to reconnect to re-establish
+ * the nexus and tell the device to abort. However, we really
+ * cannot 'reconnect' per se. Don't try to be fancy, just
+ * indicate failure, which causes our caller to reset the whole
+ * bus.
+ */
+
+ if(don)
+ esp->dma_ints_on(esp);
+ return FAILED;
+}
+
+/* We've sent ESP_CMD_RS to the ESP, the interrupt had just
+ * arrived indicating the end of the SCSI bus reset. Our job
+ * is to clean out the command queues and begin re-execution
+ * of SCSI commands once more.
+ */
+static int esp_finish_reset(struct NCR_ESP *esp,
+ struct ESP_regs *eregs)
+{
+ Scsi_Cmnd *sp = esp->current_SC;
+
+ /* Clean up currently executing command, if any. */
+ if (sp != NULL) {
+ esp_release_dmabufs(esp, sp);
+ sp->result = (DID_RESET << 16);
+ sp->scsi_done(sp);
+ esp->current_SC = NULL;
+ }
+
+ /* Clean up disconnected queue, they have been invalidated
+ * by the bus reset.
+ */
+ if (esp->disconnected_SC) {
+ while((sp = remove_first_SC(&esp->disconnected_SC)) != NULL) {
+ esp_release_dmabufs(esp, sp);
+ sp->result = (DID_RESET << 16);
+ sp->scsi_done(sp);
+ }
+ }
+
+ /* SCSI bus reset is complete. */
+ esp->resetting_bus = 0;
+ wake_up(&esp->reset_queue);
+
+ /* Ok, now it is safe to get commands going once more. */
+ if(esp->issue_SC)
+ esp_exec_cmd(esp);
+
+ return do_intr_end;
+}
+
+static int esp_do_resetbus(struct NCR_ESP *esp,
+ struct ESP_regs *eregs)
+{
+ ESPLOG(("esp%d: Resetting scsi bus\n", esp->esp_id));
+ esp->resetting_bus = 1;
+ esp_cmd(esp, eregs, ESP_CMD_RS);
+
+ return do_intr_end;
+}
+
+/* Reset ESP chip, reset hanging bus, then kill active and
+ * disconnected commands for targets without soft reset.
+ *
+ * The host_lock is acquired by caller.
+ */
+int esp_reset(Scsi_Cmnd *SCptr)
+{
+ struct NCR_ESP *esp = (struct NCR_ESP *) SCptr->device->host->hostdata;
+
+ spin_lock_irq(esp->ehost->host_lock);
+ (void) esp_do_resetbus(esp, esp->eregs);
+ spin_unlock_irq(esp->ehost->host_lock);
+
+ wait_event(esp->reset_queue, (esp->resetting_bus == 0));
+
+ return SUCCESS;
+}
+
+/* Internal ESP done function. */
+static void esp_done(struct NCR_ESP *esp, int error)
+{
+ Scsi_Cmnd *done_SC;
+
+ if(esp->current_SC) {
+ done_SC = esp->current_SC;
+ esp->current_SC = NULL;
+ esp_release_dmabufs(esp, done_SC);
+ done_SC->result = error;
+ done_SC->scsi_done(done_SC);
+
+ /* Bus is free, issue any commands in the queue. */
+ if(esp->issue_SC && !esp->current_SC)
+ esp_exec_cmd(esp);
+ } else {
+ /* Panic is safe as current_SC is null so we may still
+ * be able to accept more commands to sync disk buffers.
+ */
+ ESPLOG(("panicing\n"));
+ panic("esp: done() called with NULL esp->current_SC");
+ }
+}
+
+/* Wheee, ESP interrupt engine. */
+
+/* Forward declarations. */
+static int esp_do_phase_determine(struct NCR_ESP *esp,
+ struct ESP_regs *eregs);
+static int esp_do_data_finale(struct NCR_ESP *esp, struct ESP_regs *eregs);
+static int esp_select_complete(struct NCR_ESP *esp, struct ESP_regs *eregs);
+static int esp_do_status(struct NCR_ESP *esp, struct ESP_regs *eregs);
+static int esp_do_msgin(struct NCR_ESP *esp, struct ESP_regs *eregs);
+static int esp_do_msgindone(struct NCR_ESP *esp, struct ESP_regs *eregs);
+static int esp_do_msgout(struct NCR_ESP *esp, struct ESP_regs *eregs);
+static int esp_do_cmdbegin(struct NCR_ESP *esp, struct ESP_regs *eregs);
+
+#define sreg_datainp(__sreg) (((__sreg) & ESP_STAT_PMASK) == ESP_DIP)
+#define sreg_dataoutp(__sreg) (((__sreg) & ESP_STAT_PMASK) == ESP_DOP)
+
+/* We try to avoid some interrupts by jumping ahead and see if the ESP
+ * has gotten far enough yet. Hence the following.
+ */
+static inline int skipahead1(struct NCR_ESP *esp, struct ESP_regs *eregs,
+ Scsi_Cmnd *scp, int prev_phase, int new_phase)
+{
+ if(scp->SCp.sent_command != prev_phase)
+ return 0;
+
+ if(esp->dma_irq_p(esp)) {
+ /* Yes, we are able to save an interrupt. */
+ esp->sreg = (esp_read(eregs->esp_status) & ~(ESP_STAT_INTR));
+ esp->ireg = esp_read(eregs->esp_intrpt);
+ if(!(esp->ireg & ESP_INTR_SR))
+ return 0;
+ else
+ return do_reset_complete;
+ }
+ /* Ho hum, target is taking forever... */
+ scp->SCp.sent_command = new_phase; /* so we don't recurse... */
+ return do_intr_end;
+}
+
+static inline int skipahead2(struct NCR_ESP *esp,
+ struct ESP_regs *eregs,
+ Scsi_Cmnd *scp, int prev_phase1, int prev_phase2,
+ int new_phase)
+{
+ if(scp->SCp.sent_command != prev_phase1 &&
+ scp->SCp.sent_command != prev_phase2)
+ return 0;
+ if(esp->dma_irq_p(esp)) {
+ /* Yes, we are able to save an interrupt. */
+ esp->sreg = (esp_read(eregs->esp_status) & ~(ESP_STAT_INTR));
+ esp->ireg = esp_read(eregs->esp_intrpt);
+ if(!(esp->ireg & ESP_INTR_SR))
+ return 0;
+ else
+ return do_reset_complete;
+ }
+ /* Ho hum, target is taking forever... */
+ scp->SCp.sent_command = new_phase; /* so we don't recurse... */
+ return do_intr_end;
+}
+
+/* Misc. esp helper macros. */
+#define esp_setcount(__eregs, __cnt) \
+ esp_write((__eregs)->esp_tclow, ((__cnt) & 0xff)); \
+ esp_write((__eregs)->esp_tcmed, (((__cnt) >> 8) & 0xff))
+
+#define esp_getcount(__eregs) \
+ ((esp_read((__eregs)->esp_tclow)&0xff) | \
+ ((esp_read((__eregs)->esp_tcmed)&0xff) << 8))
+
+#define fcount(__esp, __eregs) \
+ (esp_read((__eregs)->esp_fflags) & ESP_FF_FBYTES)
+
+#define fnzero(__esp, __eregs) \
+ (esp_read((__eregs)->esp_fflags) & ESP_FF_ONOTZERO)
+
+/* XXX speculative nops unnecessary when continuing amidst a data phase
+ * XXX even on esp100!!! another case of flooding the bus with I/O reg
+ * XXX writes...
+ */
+#define esp_maybe_nop(__esp, __eregs) \
+ if((__esp)->erev == esp100) \
+ esp_cmd((__esp), (__eregs), ESP_CMD_NULL)
+
+#define sreg_to_dataphase(__sreg) \
+ ((((__sreg) & ESP_STAT_PMASK) == ESP_DOP) ? in_dataout : in_datain)
+
+/* The ESP100 when in synchronous data phase, can mistake a long final
+ * REQ pulse from the target as an extra byte, it places whatever is on
+ * the data lines into the fifo. For now, we will assume when this
+ * happens that the target is a bit quirky and we don't want to
+ * be talking synchronously to it anyways. Regardless, we need to
+ * tell the ESP to eat the extraneous byte so that we can proceed
+ * to the next phase.
+ */
+static inline int esp100_sync_hwbug(struct NCR_ESP *esp, struct ESP_regs *eregs,
+ Scsi_Cmnd *sp, int fifocnt)
+{
+ /* Do not touch this piece of code. */
+ if((!(esp->erev == esp100)) ||
+ (!(sreg_datainp((esp->sreg = esp_read(eregs->esp_status))) && !fifocnt) &&
+ !(sreg_dataoutp(esp->sreg) && !fnzero(esp, eregs)))) {
+ if(sp->SCp.phase == in_dataout)
+ esp_cmd(esp, eregs, ESP_CMD_FLUSH);
+ return 0;
+ } else {
+ /* Async mode for this guy. */
+ build_sync_nego_msg(esp, 0, 0);
+
+ /* Ack the bogus byte, but set ATN first. */
+ esp_cmd(esp, eregs, ESP_CMD_SATN);
+ esp_cmd(esp, eregs, ESP_CMD_MOK);
+ return 1;
+ }
+}
+
+/* This closes the window during a selection with a reselect pending, because
+ * we use DMA for the selection process the FIFO should hold the correct
+ * contents if we get reselected during this process. So we just need to
+ * ack the possible illegal cmd interrupt pending on the esp100.
+ */
+static inline int esp100_reconnect_hwbug(struct NCR_ESP *esp,
+ struct ESP_regs *eregs)
+{
+ volatile unchar junk;
+
+ if(esp->erev != esp100)
+ return 0;
+ junk = esp_read(eregs->esp_intrpt);
+
+ if(junk & ESP_INTR_SR)
+ return 1;
+ return 0;
+}
+
+/* This verifies the BUSID bits during a reselection so that we know which
+ * target is talking to us.
+ */
+static inline int reconnect_target(struct NCR_ESP *esp, struct ESP_regs *eregs)
+{
+ int it, me = esp->scsi_id_mask, targ = 0;
+
+ if(2 != fcount(esp, eregs))
+ return -1;
+ it = esp_read(eregs->esp_fdata);
+ if(!(it & me))
+ return -1;
+ it &= ~me;
+ if(it & (it - 1))
+ return -1;
+ while(!(it & 1))
+ targ++, it >>= 1;
+ return targ;
+}
+
+/* This verifies the identify from the target so that we know which lun is
+ * being reconnected.
+ */
+static inline int reconnect_lun(struct NCR_ESP *esp, struct ESP_regs *eregs)
+{
+ int lun;
+
+ if((esp->sreg & ESP_STAT_PMASK) != ESP_MIP)
+ return -1;
+ lun = esp_read(eregs->esp_fdata);
+
+ /* Yes, you read this correctly. We report lun of zero
+ * if we see parity error. ESP reports parity error for
+ * the lun byte, and this is the only way to hope to recover
+ * because the target is connected.
+ */
+ if(esp->sreg & ESP_STAT_PERR)
+ return 0;
+
+ /* Check for illegal bits being set in the lun. */
+ if((lun & 0x40) || !(lun & 0x80))
+ return -1;
+
+ return lun & 7;
+}
+
+/* This puts the driver in a state where it can revitalize a command that
+ * is being continued due to reselection.
+ */
+static inline void esp_connect(struct NCR_ESP *esp, struct ESP_regs *eregs,
+ Scsi_Cmnd *sp)
+{
+ struct scsi_device *dp = sp->device;
+ struct esp_device *esp_dev = dp->hostdata;
+
+ if(esp->prev_soff != esp_dev->sync_max_offset ||
+ esp->prev_stp != esp_dev->sync_min_period ||
+ (esp->erev > esp100a &&
+ esp->prev_cfg3 != esp->config3[scmd_id(sp)])) {
+ esp->prev_soff = esp_dev->sync_max_offset;
+ esp_write(eregs->esp_soff, esp->prev_soff);
+ esp->prev_stp = esp_dev->sync_min_period;
+ esp_write(eregs->esp_stp, esp->prev_stp);
+ if(esp->erev > esp100a) {
+ esp->prev_cfg3 = esp->config3[scmd_id(sp)];
+ esp_write(eregs->esp_cfg3, esp->prev_cfg3);
+ }
+ }
+ esp->current_SC = sp;
+}
+
+/* This will place the current working command back into the issue queue
+ * if we are to receive a reselection amidst a selection attempt.
+ */
+static inline void esp_reconnect(struct NCR_ESP *esp, Scsi_Cmnd *sp)
+{
+ if(!esp->disconnected_SC)
+ ESPLOG(("esp%d: Weird, being reselected but disconnected "
+ "command queue is empty.\n", esp->esp_id));
+ esp->snip = 0;
+ esp->current_SC = NULL;
+ sp->SCp.phase = not_issued;
+ append_SC(&esp->issue_SC, sp);
+}
+
+/* Begin message in phase. */
+static int esp_do_msgin(struct NCR_ESP *esp, struct ESP_regs *eregs)
+{
+ esp_cmd(esp, eregs, ESP_CMD_FLUSH);
+ esp_maybe_nop(esp, eregs);
+ esp_cmd(esp, eregs, ESP_CMD_TI);
+ esp->msgin_len = 1;
+ esp->msgin_ctr = 0;
+ esp_advance_phase(esp->current_SC, in_msgindone);
+ return do_work_bus;
+}
+
+static inline void advance_sg(struct NCR_ESP *esp, Scsi_Cmnd *sp)
+{
+ ++sp->SCp.buffer;
+ --sp->SCp.buffers_residual;
+ sp->SCp.this_residual = sp->SCp.buffer->length;
+ if (esp->dma_advance_sg)
+ esp->dma_advance_sg (sp);
+ else
+ sp->SCp.ptr = (char *) virt_to_phys(sg_virt(sp->SCp.buffer));
+
+}
+
+/* Please note that the way I've coded these routines is that I _always_
+ * check for a disconnect during any and all information transfer
+ * phases. The SCSI standard states that the target _can_ cause a BUS
+ * FREE condition by dropping all MSG/CD/IO/BSY signals. Also note
+ * that during information transfer phases the target controls every
+ * change in phase, the only thing the initiator can do is "ask" for
+ * a message out phase by driving ATN true. The target can, and sometimes
+ * will, completely ignore this request so we cannot assume anything when
+ * we try to force a message out phase to abort/reset a target. Most of
+ * the time the target will eventually be nice and go to message out, so
+ * we may have to hold on to our state about what we want to tell the target
+ * for some period of time.
+ */
+
+/* I think I have things working here correctly. Even partial transfers
+ * within a buffer or sub-buffer should not upset us at all no matter
+ * how bad the target and/or ESP fucks things up.
+ */
+static int esp_do_data(struct NCR_ESP *esp, struct ESP_regs *eregs)
+{
+ Scsi_Cmnd *SCptr = esp->current_SC;
+ int thisphase, hmuch;
+
+ ESPDATA(("esp_do_data: "));
+ esp_maybe_nop(esp, eregs);
+ thisphase = sreg_to_dataphase(esp->sreg);
+ esp_advance_phase(SCptr, thisphase);
+ ESPDATA(("newphase<%s> ", (thisphase == in_datain) ? "DATAIN" : "DATAOUT"));
+ hmuch = esp->dma_can_transfer(esp, SCptr);
+
+ /*
+ * XXX MSch: cater for PIO transfer here; PIO used if hmuch == 0
+ */
+ if (hmuch) { /* DMA */
+ /*
+ * DMA
+ */
+ ESPDATA(("hmuch<%d> ", hmuch));
+ esp->current_transfer_size = hmuch;
+ esp_setcount(eregs, (esp->fas_premature_intr_workaround ?
+ (hmuch + 0x40) : hmuch));
+ esp->dma_setup(esp, (__u32)((unsigned long)SCptr->SCp.ptr),
+ hmuch, (thisphase == in_datain));
+ ESPDATA(("DMA|TI --> do_intr_end\n"));
+ esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI);
+ return do_intr_end;
+ /*
+ * end DMA
+ */
+ } else {
+ /*
+ * PIO
+ */
+ int oldphase, i = 0; /* or where we left off last time ?? esp->current_data ?? */
+ int fifocnt = 0;
+ unsigned char *p = phys_to_virt((unsigned long)SCptr->SCp.ptr);
+
+ oldphase = esp_read(eregs->esp_status) & ESP_STAT_PMASK;
+
+ /*
+ * polled transfer; ugly, can we make this happen in a DRQ
+ * interrupt handler ??
+ * requires keeping track of state information in host or
+ * command struct!
+ * Problem: I've never seen a DRQ happen on Mac, not even
+ * with ESP_CMD_DMA ...
+ */
+
+ /* figure out how much needs to be transferred */
+ hmuch = SCptr->SCp.this_residual;
+ ESPDATA(("hmuch<%d> pio ", hmuch));
+ esp->current_transfer_size = hmuch;
+
+ /* tell the ESP ... */
+ esp_setcount(eregs, hmuch);
+
+ /* loop */
+ while (hmuch) {
+ int j, fifo_stuck = 0, newphase;
+ unsigned long timeout;
+#if 0
+ unsigned long flags;
+#endif
+#if 0
+ if ( i % 10 )
+ ESPDATA(("\r"));
+ else
+ ESPDATA(( /*"\n"*/ "\r"));
+#endif
+#if 0
+ local_irq_save(flags);
+#endif
+ if(thisphase == in_datain) {
+ /* 'go' ... */
+ esp_cmd(esp, eregs, ESP_CMD_TI);
+
+ /* wait for data */
+ timeout = 1000000;
+ while (!((esp->sreg=esp_read(eregs->esp_status)) & ESP_STAT_INTR) && --timeout)
+ udelay(2);
+ if (timeout == 0)
+ printk("DRQ datain timeout! \n");
+
+ newphase = esp->sreg & ESP_STAT_PMASK;
+
+ /* see how much we got ... */
+ fifocnt = (esp_read(eregs->esp_fflags) & ESP_FF_FBYTES);
+
+ if (!fifocnt)
+ fifo_stuck++;
+ else
+ fifo_stuck = 0;
+
+ ESPDATA(("\rgot %d st %x ph %x", fifocnt, esp->sreg, newphase));
+
+ /* read fifo */
+ for(j=0;jesp_fdata);
+
+ ESPDATA(("(%d) ", i));
+
+ /* how many to go ?? */
+ hmuch -= fifocnt;
+
+ /* break if status phase !! */
+ if(newphase == ESP_STATP) {
+ /* clear int. */
+ esp->ireg = esp_read(eregs->esp_intrpt);
+ break;
+ }
+ } else {
+#define MAX_FIFO 8
+ /* how much will fit ? */
+ int this_count = MAX_FIFO - fifocnt;
+ if (this_count > hmuch)
+ this_count = hmuch;
+
+ /* fill fifo */
+ for(j=0;jesp_fdata, p[i++]);
+
+ /* how many left if this goes out ?? */
+ hmuch -= this_count;
+
+ /* 'go' ... */
+ esp_cmd(esp, eregs, ESP_CMD_TI);
+
+ /* wait for 'got it' */
+ timeout = 1000000;
+ while (!((esp->sreg=esp_read(eregs->esp_status)) & ESP_STAT_INTR) && --timeout)
+ udelay(2);
+ if (timeout == 0)
+ printk("DRQ dataout timeout! \n");
+
+ newphase = esp->sreg & ESP_STAT_PMASK;
+
+ /* need to check how much was sent ?? */
+ fifocnt = (esp_read(eregs->esp_fflags) & ESP_FF_FBYTES);
+
+ ESPDATA(("\rsent %d st %x ph %x", this_count - fifocnt, esp->sreg, newphase));
+
+ ESPDATA(("(%d) ", i));
+
+ /* break if status phase !! */
+ if(newphase == ESP_STATP) {
+ /* clear int. */
+ esp->ireg = esp_read(eregs->esp_intrpt);
+ break;
+ }
+
+ }
+
+ /* clear int. */
+ esp->ireg = esp_read(eregs->esp_intrpt);
+
+ ESPDATA(("ir %x ... ", esp->ireg));
+
+ if (hmuch == 0)
+ ESPDATA(("done! \n"));
+
+#if 0
+ local_irq_restore(flags);
+#endif
+
+ /* check new bus phase */
+ if (newphase != oldphase && i < esp->current_transfer_size) {
+ /* something happened; disconnect ?? */
+ ESPDATA(("phase change, dropped out with %d done ... ", i));
+ break;
+ }
+
+ /* check int. status */
+ if (esp->ireg & ESP_INTR_DC) {
+ /* disconnect */
+ ESPDATA(("disconnect; %d transferred ... ", i));
+ break;
+ } else if (esp->ireg & ESP_INTR_FDONE) {
+ /* function done */
+ ESPDATA(("function done; %d transferred ... ", i));
+ break;
+ }
+
+ /* XXX fixme: bail out on stall */
+ if (fifo_stuck > 10) {
+ /* we're stuck */
+ ESPDATA(("fifo stall; %d transferred ... ", i));
+ break;
+ }
+ }
+
+ ESPDATA(("\n"));
+ /* check successful completion ?? */
+
+ if (thisphase == in_dataout)
+ hmuch += fifocnt; /* stuck?? adjust data pointer ...*/
+
+ /* tell do_data_finale how much was transferred */
+ esp->current_transfer_size -= hmuch;
+
+ /* still not completely sure on this one ... */
+ return /*do_intr_end*/ do_work_bus /*do_phase_determine*/ ;
+
+ /*
+ * end PIO
+ */
+ }
+ return do_intr_end;
+}
+
+/* See how successful the data transfer was. */
+static int esp_do_data_finale(struct NCR_ESP *esp,
+ struct ESP_regs *eregs)
+{
+ Scsi_Cmnd *SCptr = esp->current_SC;
+ struct esp_device *esp_dev = SCptr->device->hostdata;
+ int bogus_data = 0, bytes_sent = 0, fifocnt, ecount = 0;
+
+ if(esp->dma_led_off)
+ esp->dma_led_off(esp);
+
+ ESPDATA(("esp_do_data_finale: "));
+
+ if(SCptr->SCp.phase == in_datain) {
+ if(esp->sreg & ESP_STAT_PERR) {
+ /* Yuck, parity error. The ESP asserts ATN
+ * so that we can go to message out phase
+ * immediately and inform the target that
+ * something bad happened.
+ */
+ ESPLOG(("esp%d: data bad parity detected.\n",
+ esp->esp_id));
+ esp->cur_msgout[0] = INITIATOR_ERROR;
+ esp->msgout_len = 1;
+ }
+ if(esp->dma_drain)
+ esp->dma_drain(esp);
+ }
+ if(esp->dma_invalidate)
+ esp->dma_invalidate(esp);
+
+ /* This could happen for the above parity error case. */
+ if(!(esp->ireg == ESP_INTR_BSERV)) {
+ /* Please go to msgout phase, please please please... */
+ ESPLOG(("esp%d: !BSERV after data, probably to msgout\n",
+ esp->esp_id));
+ return esp_do_phase_determine(esp, eregs);
+ }
+
+ /* Check for partial transfers and other horrible events. */
+ fifocnt = (esp_read(eregs->esp_fflags) & ESP_FF_FBYTES);
+ ecount = esp_getcount(eregs);
+ if(esp->fas_premature_intr_workaround)
+ ecount -= 0x40;
+ bytes_sent = esp->current_transfer_size;
+
+ ESPDATA(("trans_sz=%d, ", bytes_sent));
+ if(!(esp->sreg & ESP_STAT_TCNT))
+ bytes_sent -= ecount;
+ if(SCptr->SCp.phase == in_dataout)
+ bytes_sent -= fifocnt;
+
+ ESPDATA(("bytes_sent=%d (ecount=%d, fifocnt=%d), ", bytes_sent,
+ ecount, fifocnt));
+
+ /* If we were in synchronous mode, check for peculiarities. */
+ if(esp_dev->sync_max_offset)
+ bogus_data = esp100_sync_hwbug(esp, eregs, SCptr, fifocnt);
+ else
+ esp_cmd(esp, eregs, ESP_CMD_FLUSH);
+
+ /* Until we are sure of what has happened, we are certainly
+ * in the dark.
+ */
+ esp_advance_phase(SCptr, in_the_dark);
+
+ /* Check for premature interrupt condition. Can happen on FAS2x6
+ * chips. QLogic recommends a workaround by overprogramming the
+ * transfer counters, but this makes doing scatter-gather impossible.
+ * Until there is a way to disable scatter-gather for a single target,
+ * and not only for the entire host adapter as it is now, the workaround
+ * is way to expensive performance wise.
+ * Instead, it turns out that when this happens the target has disconnected
+ * already but it doesn't show in the interrupt register. Compensate for
+ * that here to try and avoid a SCSI bus reset.
+ */
+ if(!esp->fas_premature_intr_workaround && (fifocnt == 1) &&
+ sreg_dataoutp(esp->sreg)) {
+ ESPLOG(("esp%d: Premature interrupt, enabling workaround\n",
+ esp->esp_id));
+#if 0
+ /* Disable scatter-gather operations, they are not possible
+ * when using this workaround.
+ */
+ esp->ehost->sg_tablesize = 0;
+ esp->ehost->use_clustering = ENABLE_CLUSTERING;
+ esp->fas_premature_intr_workaround = 1;
+ bytes_sent = 0;
+ if(SCptr->use_sg) {
+ ESPLOG(("esp%d: Aborting scatter-gather operation\n",
+ esp->esp_id));
+ esp->cur_msgout[0] = ABORT;
+ esp->msgout_len = 1;
+ esp->msgout_ctr = 0;
+ esp_cmd(esp, eregs, ESP_CMD_SATN);
+ esp_setcount(eregs, 0xffff);
+ esp_cmd(esp, eregs, ESP_CMD_NULL);
+ esp_cmd(esp, eregs, ESP_CMD_TPAD | ESP_CMD_DMA);
+ return do_intr_end;
+ }
+#else
+ /* Just set the disconnected bit. That's what appears to
+ * happen anyway. The state machine will pick it up when
+ * we return.
+ */
+ esp->ireg |= ESP_INTR_DC;
+#endif
+ }
+
+ if(bytes_sent < 0) {
+ /* I've seen this happen due to lost state in this
+ * driver. No idea why it happened, but allowing
+ * this value to be negative caused things to
+ * lock up. This allows greater chance of recovery.
+ * In fact every time I've seen this, it has been
+ * a driver bug without question.
+ */
+ ESPLOG(("esp%d: yieee, bytes_sent < 0!\n", esp->esp_id));
+ ESPLOG(("esp%d: csz=%d fifocount=%d ecount=%d\n",
+ esp->esp_id,
+ esp->current_transfer_size, fifocnt, ecount));
+ ESPLOG(("esp%d: use_sg=%d ptr=%p this_residual=%d\n",
+ esp->esp_id,
+ SCptr->use_sg, SCptr->SCp.ptr, SCptr->SCp.this_residual));
+ ESPLOG(("esp%d: Forcing async for target %d\n", esp->esp_id,
+ SCptr->device->id));
+ SCptr->device->borken = 1;
+ esp_dev->sync = 0;
+ bytes_sent = 0;
+ }
+
+ /* Update the state of our transfer. */
+ SCptr->SCp.ptr += bytes_sent;
+ SCptr->SCp.this_residual -= bytes_sent;
+ if(SCptr->SCp.this_residual < 0) {
+ /* shit */
+ ESPLOG(("esp%d: Data transfer overrun.\n", esp->esp_id));
+ SCptr->SCp.this_residual = 0;
+ }
+
+ /* Maybe continue. */
+ if(!bogus_data) {
+ ESPDATA(("!bogus_data, "));
+ /* NO MATTER WHAT, we advance the scatterlist,
+ * if the target should decide to disconnect
+ * in between scatter chunks (which is common)
+ * we could die horribly! I used to have the sg
+ * advance occur only if we are going back into
+ * (or are staying in) a data phase, you can
+ * imagine the hell I went through trying to
+ * figure this out.
+ */
+ if(!SCptr->SCp.this_residual && SCptr->SCp.buffers_residual)
+ advance_sg(esp, SCptr);
+#ifdef DEBUG_ESP_DATA
+ if(sreg_datainp(esp->sreg) || sreg_dataoutp(esp->sreg)) {
+ ESPDATA(("to more data\n"));
+ } else {
+ ESPDATA(("to new phase\n"));
+ }
+#endif
+ return esp_do_phase_determine(esp, eregs);
+ }
+ /* Bogus data, just wait for next interrupt. */
+ ESPLOG(("esp%d: bogus_data during end of data phase\n",
+ esp->esp_id));
+ return do_intr_end;
+}
+
+/* We received a non-good status return at the end of
+ * running a SCSI command. This is used to decide if
+ * we should clear our synchronous transfer state for
+ * such a device when that happens.
+ *
+ * The idea is that when spinning up a disk or rewinding
+ * a tape, we don't want to go into a loop re-negotiating
+ * synchronous capabilities over and over.
+ */
+static int esp_should_clear_sync(Scsi_Cmnd *sp)
+{
+ unchar cmd = sp->cmnd[0];
+
+ /* These cases are for spinning up a disk and
+ * waiting for that spinup to complete.
+ */
+ if(cmd == START_STOP)
+ return 0;
+
+ if(cmd == TEST_UNIT_READY)
+ return 0;
+
+ /* One more special case for SCSI tape drives,
+ * this is what is used to probe the device for
+ * completion of a rewind or tape load operation.
+ */
+ if(sp->device->type == TYPE_TAPE && cmd == MODE_SENSE)
+ return 0;
+
+ return 1;
+}
+
+/* Either a command is completing or a target is dropping off the bus
+ * to continue the command in the background so we can do other work.
+ */
+static int esp_do_freebus(struct NCR_ESP *esp, struct ESP_regs *eregs)
+{
+ Scsi_Cmnd *SCptr = esp->current_SC;
+ int rval;
+
+ rval = skipahead2(esp, eregs, SCptr, in_status, in_msgindone, in_freeing);
+ if(rval)
+ return rval;
+
+ if(esp->ireg != ESP_INTR_DC) {
+ ESPLOG(("esp%d: Target will not disconnect\n", esp->esp_id));
+ return do_reset_bus; /* target will not drop BSY... */
+ }
+ esp->msgout_len = 0;
+ esp->prevmsgout = NOP;
+ if(esp->prevmsgin == COMMAND_COMPLETE) {
+ struct esp_device *esp_dev = SCptr->device->hostdata;
+ /* Normal end of nexus. */
+ if(esp->disconnected_SC)
+ esp_cmd(esp, eregs, ESP_CMD_ESEL);
+
+ if(SCptr->SCp.Status != GOOD &&
+ SCptr->SCp.Status != CONDITION_GOOD &&
+ ((1<targets_present) &&
+ esp_dev->sync && esp_dev->sync_max_offset) {
+ /* SCSI standard says that the synchronous capabilities
+ * should be renegotiated at this point. Most likely
+ * we are about to request sense from this target
+ * in which case we want to avoid using sync
+ * transfers until we are sure of the current target
+ * state.
+ */
+ ESPMISC(("esp: Status <%d> for target %d lun %d\n",
+ SCptr->SCp.Status, SCptr->device->id, SCptr->device->lun));
+
+ /* But don't do this when spinning up a disk at
+ * boot time while we poll for completion as it
+ * fills up the console with messages. Also, tapes
+ * can report not ready many times right after
+ * loading up a tape.
+ */
+ if(esp_should_clear_sync(SCptr) != 0)
+ esp_dev->sync = 0;
+ }
+ ESPDISC(("F<%02x,%02x>", SCptr->device->id, SCptr->device->lun));
+ esp_done(esp, ((SCptr->SCp.Status & 0xff) |
+ ((SCptr->SCp.Message & 0xff)<<8) |
+ (DID_OK << 16)));
+ } else if(esp->prevmsgin == DISCONNECT) {
+ /* Normal disconnect. */
+ esp_cmd(esp, eregs, ESP_CMD_ESEL);
+ ESPDISC(("D<%02x,%02x>", SCptr->device->id, SCptr->device->lun));
+ append_SC(&esp->disconnected_SC, SCptr);
+ esp->current_SC = NULL;
+ if(esp->issue_SC)
+ esp_exec_cmd(esp);
+ } else {
+ /* Driver bug, we do not expect a disconnect here
+ * and should not have advanced the state engine
+ * to in_freeing.
+ */
+ ESPLOG(("esp%d: last msg not disc and not cmd cmplt.\n",
+ esp->esp_id));
+ return do_reset_bus;
+ }
+ return do_intr_end;
+}
+
+/* When a reselect occurs, and we cannot find the command to
+ * reconnect to in our queues, we do this.
+ */
+static int esp_bad_reconnect(struct NCR_ESP *esp)
+{
+ Scsi_Cmnd *sp;
+
+ ESPLOG(("esp%d: Eieeee, reconnecting unknown command!\n",
+ esp->esp_id));
+ ESPLOG(("QUEUE DUMP\n"));
+ sp = esp->issue_SC;
+ ESPLOG(("esp%d: issue_SC[", esp->esp_id));
+ while(sp) {
+ ESPLOG(("<%02x,%02x>", sp->device->id, sp->device->lun));
+ sp = (Scsi_Cmnd *) sp->host_scribble;
+ }
+ ESPLOG(("]\n"));
+ sp = esp->current_SC;
+ ESPLOG(("esp%d: current_SC[", esp->esp_id));
+ while(sp) {
+ ESPLOG(("<%02x,%02x>", sp->device->id, sp->device->lun));
+ sp = (Scsi_Cmnd *) sp->host_scribble;
+ }
+ ESPLOG(("]\n"));
+ sp = esp->disconnected_SC;
+ ESPLOG(("esp%d: disconnected_SC[", esp->esp_id));
+ while(sp) {
+ ESPLOG(("<%02x,%02x>", sp->device->id, sp->device->lun));
+ sp = (Scsi_Cmnd *) sp->host_scribble;
+ }
+ ESPLOG(("]\n"));
+ return do_reset_bus;
+}
+
+/* Do the needy when a target tries to reconnect to us. */
+static int esp_do_reconnect(struct NCR_ESP *esp,
+ struct ESP_regs *eregs)
+{
+ int lun, target;
+ Scsi_Cmnd *SCptr;
+
+ /* Check for all bogus conditions first. */
+ target = reconnect_target(esp, eregs);
+ if(target < 0) {
+ ESPDISC(("bad bus bits\n"));
+ return do_reset_bus;
+ }
+ lun = reconnect_lun(esp, eregs);
+ if(lun < 0) {
+ ESPDISC(("target=%2x, bad identify msg\n", target));
+ return do_reset_bus;
+ }
+
+ /* Things look ok... */
+ ESPDISC(("R<%02x,%02x>", target, lun));
+
+ esp_cmd(esp, eregs, ESP_CMD_FLUSH);
+ if(esp100_reconnect_hwbug(esp, eregs))
+ return do_reset_bus;
+ esp_cmd(esp, eregs, ESP_CMD_NULL);
+
+ SCptr = remove_SC(&esp->disconnected_SC, (unchar) target, (unchar) lun);
+ if(!SCptr)
+ return esp_bad_reconnect(esp);
+
+ esp_connect(esp, eregs, SCptr);
+ esp_cmd(esp, eregs, ESP_CMD_MOK);
+
+ /* Reconnect implies a restore pointers operation. */
+ esp_restore_pointers(esp, SCptr);
+
+ esp->snip = 0;
+ esp_advance_phase(SCptr, in_the_dark);
+ return do_intr_end;
+}
+
+/* End of NEXUS (hopefully), pick up status + message byte then leave if
+ * all goes well.
+ */
+static int esp_do_status(struct NCR_ESP *esp, struct ESP_regs *eregs)
+{
+ Scsi_Cmnd *SCptr = esp->current_SC;
+ int intr, rval;
+
+ rval = skipahead1(esp, eregs, SCptr, in_the_dark, in_status);
+ if(rval)
+ return rval;
+
+ intr = esp->ireg;
+ ESPSTAT(("esp_do_status: "));
+ if(intr != ESP_INTR_DC) {
+ int message_out = 0; /* for parity problems */
+
+ /* Ack the message. */
+ ESPSTAT(("ack msg, "));
+ esp_cmd(esp, eregs, ESP_CMD_MOK);
+
+ if(esp->dma_poll)
+ esp->dma_poll(esp, (unsigned char *) esp->esp_command);
+
+ ESPSTAT(("got something, "));
+ /* ESP chimes in with one of
+ *
+ * 1) function done interrupt:
+ * both status and message in bytes
+ * are available
+ *
+ * 2) bus service interrupt:
+ * only status byte was acquired
+ *
+ * 3) Anything else:
+ * can't happen, but we test for it
+ * anyways
+ *
+ * ALSO: If bad parity was detected on either
+ * the status _or_ the message byte then
+ * the ESP has asserted ATN on the bus
+ * and we must therefore wait for the
+ * next phase change.
+ */
+ if(intr & ESP_INTR_FDONE) {
+ /* We got it all, hallejulia. */
+ ESPSTAT(("got both, "));
+ SCptr->SCp.Status = esp->esp_command[0];
+ SCptr->SCp.Message = esp->esp_command[1];
+ esp->prevmsgin = SCptr->SCp.Message;
+ esp->cur_msgin[0] = SCptr->SCp.Message;
+ if(esp->sreg & ESP_STAT_PERR) {
+ /* There was bad parity for the
+ * message byte, the status byte
+ * was ok.
+ */
+ message_out = MSG_PARITY_ERROR;
+ }
+ } else if(intr == ESP_INTR_BSERV) {
+ /* Only got status byte. */
+ ESPLOG(("esp%d: got status only, ", esp->esp_id));
+ if(!(esp->sreg & ESP_STAT_PERR)) {
+ SCptr->SCp.Status = esp->esp_command[0];
+ SCptr->SCp.Message = 0xff;
+ } else {
+ /* The status byte had bad parity.
+ * we leave the scsi_pointer Status
+ * field alone as we set it to a default
+ * of CHECK_CONDITION in esp_queue.
+ */
+ message_out = INITIATOR_ERROR;
+ }
+ } else {
+ /* This shouldn't happen ever. */
+ ESPSTAT(("got bolixed\n"));
+ esp_advance_phase(SCptr, in_the_dark);
+ return esp_do_phase_determine(esp, eregs);
+ }
+
+ if(!message_out) {
+ ESPSTAT(("status=%2x msg=%2x, ", SCptr->SCp.Status,
+ SCptr->SCp.Message));
+ if(SCptr->SCp.Message == COMMAND_COMPLETE) {
+ ESPSTAT(("and was COMMAND_COMPLETE\n"));
+ esp_advance_phase(SCptr, in_freeing);
+ return esp_do_freebus(esp, eregs);
+ } else {
+ ESPLOG(("esp%d: and _not_ COMMAND_COMPLETE\n",
+ esp->esp_id));
+ esp->msgin_len = esp->msgin_ctr = 1;
+ esp_advance_phase(SCptr, in_msgindone);
+ return esp_do_msgindone(esp, eregs);
+ }
+ } else {
+ /* With luck we'll be able to let the target
+ * know that bad parity happened, it will know
+ * which byte caused the problems and send it
+ * again. For the case where the status byte
+ * receives bad parity, I do not believe most
+ * targets recover very well. We'll see.
+ */
+ ESPLOG(("esp%d: bad parity somewhere mout=%2x\n",
+ esp->esp_id, message_out));
+ esp->cur_msgout[0] = message_out;
+ esp->msgout_len = esp->msgout_ctr = 1;
+ esp_advance_phase(SCptr, in_the_dark);
+ return esp_do_phase_determine(esp, eregs);
+ }
+ } else {
+ /* If we disconnect now, all hell breaks loose. */
+ ESPLOG(("esp%d: whoops, disconnect\n", esp->esp_id));
+ esp_advance_phase(SCptr, in_the_dark);
+ return esp_do_phase_determine(esp, eregs);
+ }
+}
+
+static int esp_enter_status(struct NCR_ESP *esp,
+ struct ESP_regs *eregs)
+{
+ unchar thecmd = ESP_CMD_ICCSEQ;
+
+ esp_cmd(esp, eregs, ESP_CMD_FLUSH);
+
+ if(esp->do_pio_cmds) {
+ esp_advance_phase(esp->current_SC, in_status);
+ esp_cmd(esp, eregs, thecmd);
+ while(!(esp_read(esp->eregs->esp_status) & ESP_STAT_INTR));
+ esp->esp_command[0] = esp_read(eregs->esp_fdata);
+ while(!(esp_read(esp->eregs->esp_status) & ESP_STAT_INTR));
+ esp->esp_command[1] = esp_read(eregs->esp_fdata);
+ } else {
+ esp->esp_command[0] = esp->esp_command[1] = 0xff;
+ esp_write(eregs->esp_tclow, 2);
+ esp_write(eregs->esp_tcmed, 0);
+ esp->dma_init_read(esp, esp->esp_command_dvma, 2);
+ thecmd |= ESP_CMD_DMA;
+ esp_cmd(esp, eregs, thecmd);
+ esp_advance_phase(esp->current_SC, in_status);
+ }
+
+ return esp_do_status(esp, eregs);
+}
+
+static int esp_disconnect_amidst_phases(struct NCR_ESP *esp,
+ struct ESP_regs *eregs)
+{
+ Scsi_Cmnd *sp = esp->current_SC;
+ struct esp_device *esp_dev = sp->device->hostdata;
+
+ /* This means real problems if we see this
+ * here. Unless we were actually trying
+ * to force the device to abort/reset.
+ */
+ ESPLOG(("esp%d: Disconnect amidst phases, ", esp->esp_id));
+ ESPLOG(("pphase<%s> cphase<%s>, ",
+ phase_string(sp->SCp.phase),
+ phase_string(sp->SCp.sent_command)));
+
+ if(esp->disconnected_SC)
+ esp_cmd(esp, eregs, ESP_CMD_ESEL);
+
+ switch(esp->cur_msgout[0]) {
+ default:
+ /* We didn't expect this to happen at all. */
+ ESPLOG(("device is bolixed\n"));
+ esp_advance_phase(sp, in_tgterror);
+ esp_done(esp, (DID_ERROR << 16));
+ break;
+
+ case BUS_DEVICE_RESET:
+ ESPLOG(("device reset successful\n"));
+ esp_dev->sync_max_offset = 0;
+ esp_dev->sync_min_period = 0;
+ esp_dev->sync = 0;
+ esp_advance_phase(sp, in_resetdev);
+ esp_done(esp, (DID_RESET << 16));
+ break;
+
+ case ABORT:
+ ESPLOG(("device abort successful\n"));
+ esp_advance_phase(sp, in_abortone);
+ esp_done(esp, (DID_ABORT << 16));
+ break;
+
+ };
+ return do_intr_end;
+}
+
+static int esp_enter_msgout(struct NCR_ESP *esp,
+ struct ESP_regs *eregs)
+{
+ esp_advance_phase(esp->current_SC, in_msgout);
+ return esp_do_msgout(esp, eregs);
+}
+
+static int esp_enter_msgin(struct NCR_ESP *esp,
+ struct ESP_regs *eregs)
+{
+ esp_advance_phase(esp->current_SC, in_msgin);
+ return esp_do_msgin(esp, eregs);
+}
+
+static int esp_enter_cmd(struct NCR_ESP *esp,
+ struct ESP_regs *eregs)
+{
+ esp_advance_phase(esp->current_SC, in_cmdbegin);
+ return esp_do_cmdbegin(esp, eregs);
+}
+
+static int esp_enter_badphase(struct NCR_ESP *esp,
+ struct ESP_regs *eregs)
+{
+ ESPLOG(("esp%d: Bizarre bus phase %2x.\n", esp->esp_id,
+ esp->sreg & ESP_STAT_PMASK));
+ return do_reset_bus;
+}
+
+typedef int (*espfunc_t)(struct NCR_ESP *,
+ struct ESP_regs *);
+
+static espfunc_t phase_vector[] = {
+ esp_do_data, /* ESP_DOP */
+ esp_do_data, /* ESP_DIP */
+ esp_enter_cmd, /* ESP_CMDP */
+ esp_enter_status, /* ESP_STATP */
+ esp_enter_badphase, /* ESP_STAT_PMSG */
+ esp_enter_badphase, /* ESP_STAT_PMSG | ESP_STAT_PIO */
+ esp_enter_msgout, /* ESP_MOP */
+ esp_enter_msgin, /* ESP_MIP */
+};
+
+/* The target has control of the bus and we have to see where it has
+ * taken us.
+ */
+static int esp_do_phase_determine(struct NCR_ESP *esp,
+ struct ESP_regs *eregs)
+{
+ if ((esp->ireg & ESP_INTR_DC) != 0)
+ return esp_disconnect_amidst_phases(esp, eregs);
+ return phase_vector[esp->sreg & ESP_STAT_PMASK](esp, eregs);
+}
+
+/* First interrupt after exec'ing a cmd comes here. */
+static int esp_select_complete(struct NCR_ESP *esp, struct ESP_regs *eregs)
+{
+ Scsi_Cmnd *SCptr = esp->current_SC;
+ struct esp_device *esp_dev = SCptr->device->hostdata;
+ int cmd_bytes_sent, fcnt;
+
+ fcnt = (esp_read(eregs->esp_fflags) & ESP_FF_FBYTES);
+ cmd_bytes_sent = esp->dma_bytes_sent(esp, fcnt);
+ if(esp->dma_invalidate)
+ esp->dma_invalidate(esp);
+
+ /* Let's check to see if a reselect happened
+ * while we we're trying to select. This must
+ * be checked first.
+ */
+ if(esp->ireg == (ESP_INTR_RSEL | ESP_INTR_FDONE)) {
+ esp_reconnect(esp, SCptr);
+ return esp_do_reconnect(esp, eregs);
+ }
+
+ /* Looks like things worked, we should see a bus service &
+ * a function complete interrupt at this point. Note we
+ * are doing a direct comparison because we don't want to
+ * be fooled into thinking selection was successful if
+ * ESP_INTR_DC is set, see below.
+ */
+ if(esp->ireg == (ESP_INTR_FDONE | ESP_INTR_BSERV)) {
+ /* target speaks... */
+ esp->targets_present |= (1<snip)
+ esp_dev->sync = 1;
+
+ /* See how far, if at all, we got in getting
+ * the information out to the target.
+ */
+ switch(esp->seqreg) {
+ default:
+
+ case ESP_STEP_ASEL:
+ /* Arbitration won, target selected, but
+ * we are in some phase which is not command
+ * phase nor is it message out phase.
+ *
+ * XXX We've confused the target, obviously.
+ * XXX So clear it's state, but we also end
+ * XXX up clearing everyone elses. That isn't
+ * XXX so nice. I'd like to just reset this
+ * XXX target, but if I cannot even get it's
+ * XXX attention and finish selection to talk
+ * XXX to it, there is not much more I can do.
+ * XXX If we have a loaded bus we're going to
+ * XXX spend the next second or so renegotiating
+ * XXX for synchronous transfers.
+ */
+ ESPLOG(("esp%d: STEP_ASEL for tgt %d\n",
+ esp->esp_id, SCptr->device->id));
+
+ case ESP_STEP_SID:
+ /* Arbitration won, target selected, went
+ * to message out phase, sent one message
+ * byte, then we stopped. ATN is asserted
+ * on the SCSI bus and the target is still
+ * there hanging on. This is a legal
+ * sequence step if we gave the ESP a select
+ * and stop command.
+ *
+ * XXX See above, I could set the borken flag
+ * XXX in the device struct and retry the
+ * XXX command. But would that help for
+ * XXX tagged capable targets?
+ */
+
+ case ESP_STEP_NCMD:
+ /* Arbitration won, target selected, maybe
+ * sent the one message byte in message out
+ * phase, but we did not go to command phase
+ * in the end. Actually, we could have sent
+ * only some of the message bytes if we tried
+ * to send out the entire identify and tag
+ * message using ESP_CMD_SA3.
+ */
+ cmd_bytes_sent = 0;
+ break;
+
+ case ESP_STEP_PPC:
+ /* No, not the powerPC pinhead. Arbitration
+ * won, all message bytes sent if we went to
+ * message out phase, went to command phase
+ * but only part of the command was sent.
+ *
+ * XXX I've seen this, but usually in conjunction
+ * XXX with a gross error which appears to have
+ * XXX occurred between the time I told the
+ * XXX ESP to arbitrate and when I got the
+ * XXX interrupt. Could I have misloaded the
+ * XXX command bytes into the fifo? Actually,
+ * XXX I most likely missed a phase, and therefore
+ * XXX went into never never land and didn't even
+ * XXX know it. That was the old driver though.
+ * XXX What is even more peculiar is that the ESP
+ * XXX showed the proper function complete and
+ * XXX bus service bits in the interrupt register.
+ */
+
+ case ESP_STEP_FINI4:
+ case ESP_STEP_FINI5:
+ case ESP_STEP_FINI6:
+ case ESP_STEP_FINI7:
+ /* Account for the identify message */
+ if(SCptr->SCp.phase == in_slct_norm)
+ cmd_bytes_sent -= 1;
+ };
+ esp_cmd(esp, eregs, ESP_CMD_NULL);
+
+ /* Be careful, we could really get fucked during synchronous
+ * data transfers if we try to flush the fifo now.
+ */
+ if(!fcnt && /* Fifo is empty and... */
+ /* either we are not doing synchronous transfers or... */
+ (!esp_dev->sync_max_offset ||
+ /* We are not going into data in phase. */
+ ((esp->sreg & ESP_STAT_PMASK) != ESP_DIP)))
+ esp_cmd(esp, eregs, ESP_CMD_FLUSH); /* flush is safe */
+
+ /* See how far we got if this is not a slow command. */
+ if(!esp->esp_slowcmd) {
+ if(cmd_bytes_sent < 0)
+ cmd_bytes_sent = 0;
+ if(cmd_bytes_sent != SCptr->cmd_len) {
+ /* Crapola, mark it as a slowcmd
+ * so that we have some chance of
+ * keeping the command alive with
+ * good luck.
+ *
+ * XXX Actually, if we didn't send it all
+ * XXX this means either we didn't set things
+ * XXX up properly (driver bug) or the target
+ * XXX or the ESP detected parity on one of
+ * XXX the command bytes. This makes much
+ * XXX more sense, and therefore this code
+ * XXX should be changed to send out a
+ * XXX parity error message or if the status
+ * XXX register shows no parity error then
+ * XXX just expect the target to bring the
+ * XXX bus into message in phase so that it
+ * XXX can send us the parity error message.
+ * XXX SCSI sucks...
+ */
+ esp->esp_slowcmd = 1;
+ esp->esp_scmdp = &(SCptr->cmnd[cmd_bytes_sent]);
+ esp->esp_scmdleft = (SCptr->cmd_len - cmd_bytes_sent);
+ }
+ }
+
+ /* Now figure out where we went. */
+ esp_advance_phase(SCptr, in_the_dark);
+ return esp_do_phase_determine(esp, eregs);
+ }
+
+ /* Did the target even make it? */
+ if(esp->ireg == ESP_INTR_DC) {
+ /* wheee... nobody there or they didn't like
+ * what we told it to do, clean up.
+ */
+
+ /* If anyone is off the bus, but working on
+ * a command in the background for us, tell
+ * the ESP to listen for them.
+ */
+ if(esp->disconnected_SC)
+ esp_cmd(esp, eregs, ESP_CMD_ESEL);
+
+ if(((1<device->id) & esp->targets_present) &&
+ esp->seqreg && esp->cur_msgout[0] == EXTENDED_MESSAGE &&
+ (SCptr->SCp.phase == in_slct_msg ||
+ SCptr->SCp.phase == in_slct_stop)) {
+ /* shit */
+ esp->snip = 0;
+ ESPLOG(("esp%d: Failed synchronous negotiation for target %d "
+ "lun %d\n", esp->esp_id, SCptr->device->id, SCptr->device->lun));
+ esp_dev->sync_max_offset = 0;
+ esp_dev->sync_min_period = 0;
+ esp_dev->sync = 1; /* so we don't negotiate again */
+
+ /* Run the command again, this time though we
+ * won't try to negotiate for synchronous transfers.
+ *
+ * XXX I'd like to do something like send an
+ * XXX INITIATOR_ERROR or ABORT message to the
+ * XXX target to tell it, "Sorry I confused you,
+ * XXX please come back and I will be nicer next
+ * XXX time". But that requires having the target
+ * XXX on the bus, and it has dropped BSY on us.
+ */
+ esp->current_SC = NULL;
+ esp_advance_phase(SCptr, not_issued);
+ prepend_SC(&esp->issue_SC, SCptr);
+ esp_exec_cmd(esp);
+ return do_intr_end;
+ }
+
+ /* Ok, this is normal, this is what we see during boot
+ * or whenever when we are scanning the bus for targets.
+ * But first make sure that is really what is happening.
+ */
+ if(((1<device->id) & esp->targets_present)) {
+ ESPLOG(("esp%d: Warning, live target %d not responding to "
+ "selection.\n", esp->esp_id, SCptr->device->id));
+
+ /* This _CAN_ happen. The SCSI standard states that
+ * the target is to _not_ respond to selection if
+ * _it_ detects bad parity on the bus for any reason.
+ * Therefore, we assume that if we've talked successfully
+ * to this target before, bad parity is the problem.
+ */
+ esp_done(esp, (DID_PARITY << 16));
+ } else {
+ /* Else, there really isn't anyone there. */
+ ESPMISC(("esp: selection failure, maybe nobody there?\n"));
+ ESPMISC(("esp: target %d lun %d\n",
+ SCptr->device->id, SCptr->device->lun));
+ esp_done(esp, (DID_BAD_TARGET << 16));
+ }
+ return do_intr_end;
+ }
+
+
+ ESPLOG(("esp%d: Selection failure.\n", esp->esp_id));
+ printk("esp%d: Currently -- ", esp->esp_id);
+ esp_print_ireg(esp->ireg);
+ printk(" ");
+ esp_print_statreg(esp->sreg);
+ printk(" ");
+ esp_print_seqreg(esp->seqreg);
+ printk("\n");
+ printk("esp%d: New -- ", esp->esp_id);
+ esp->sreg = esp_read(eregs->esp_status);
+ esp->seqreg = esp_read(eregs->esp_sstep);
+ esp->ireg = esp_read(eregs->esp_intrpt);
+ esp_print_ireg(esp->ireg);
+ printk(" ");
+ esp_print_statreg(esp->sreg);
+ printk(" ");
+ esp_print_seqreg(esp->seqreg);
+ printk("\n");
+ ESPLOG(("esp%d: resetting bus\n", esp->esp_id));
+ return do_reset_bus; /* ugh... */
+}
+
+/* Continue reading bytes for msgin phase. */
+static int esp_do_msgincont(struct NCR_ESP *esp, struct ESP_regs *eregs)
+{
+ if(esp->ireg & ESP_INTR_BSERV) {
+ /* in the right phase too? */
+ if((esp->sreg & ESP_STAT_PMASK) == ESP_MIP) {
+ /* phew... */
+ esp_cmd(esp, eregs, ESP_CMD_TI);
+ esp_advance_phase(esp->current_SC, in_msgindone);
+ return do_intr_end;
+ }
+
+ /* We changed phase but ESP shows bus service,
+ * in this case it is most likely that we, the
+ * hacker who has been up for 20hrs straight
+ * staring at the screen, drowned in coffee
+ * smelling like retched cigarette ashes
+ * have miscoded something..... so, try to
+ * recover as best we can.
+ */
+ ESPLOG(("esp%d: message in mis-carriage.\n", esp->esp_id));
+ }
+ esp_advance_phase(esp->current_SC, in_the_dark);
+ return do_phase_determine;
+}
+
+static int check_singlebyte_msg(struct NCR_ESP *esp,
+ struct ESP_regs *eregs)
+{
+ esp->prevmsgin = esp->cur_msgin[0];
+ if(esp->cur_msgin[0] & 0x80) {
+ /* wheee... */
+ ESPLOG(("esp%d: target sends identify amidst phases\n",
+ esp->esp_id));
+ esp_advance_phase(esp->current_SC, in_the_dark);
+ return 0;
+ } else if(((esp->cur_msgin[0] & 0xf0) == 0x20) ||
+ (esp->cur_msgin[0] == EXTENDED_MESSAGE)) {
+ esp->msgin_len = 2;
+ esp_advance_phase(esp->current_SC, in_msgincont);
+ return 0;
+ }
+ esp_advance_phase(esp->current_SC, in_the_dark);
+ switch(esp->cur_msgin[0]) {
+ default:
+ /* We don't want to hear about it. */
+ ESPLOG(("esp%d: msg %02x which we don't know about\n", esp->esp_id,
+ esp->cur_msgin[0]));
+ return MESSAGE_REJECT;
+
+ case NOP:
+ ESPLOG(("esp%d: target %d sends a nop\n", esp->esp_id,
+ esp->current_SC->device->id));
+ return 0;
+
+ case RESTORE_POINTERS:
+ /* In this case we might also have to backup the
+ * "slow command" pointer. It is rare to get such
+ * a save/restore pointer sequence so early in the
+ * bus transition sequences, but cover it.
+ */
+ if(esp->esp_slowcmd) {
+ esp->esp_scmdleft = esp->current_SC->cmd_len;
+ esp->esp_scmdp = &esp->current_SC->cmnd[0];
+ }
+ esp_restore_pointers(esp, esp->current_SC);
+ return 0;
+
+ case SAVE_POINTERS:
+ esp_save_pointers(esp, esp->current_SC);
+ return 0;
+
+ case COMMAND_COMPLETE:
+ case DISCONNECT:
+ /* Freeing the bus, let it go. */
+ esp->current_SC->SCp.phase = in_freeing;
+ return 0;
+
+ case MESSAGE_REJECT:
+ ESPMISC(("msg reject, "));
+ if(esp->prevmsgout == EXTENDED_MESSAGE) {
+ struct esp_device *esp_dev = esp->current_SC->device->hostdata;
+
+ /* Doesn't look like this target can
+ * do synchronous or WIDE transfers.
+ */
+ ESPSDTR(("got reject, was trying nego, clearing sync/WIDE\n"));
+ esp_dev->sync = 1;
+ esp_dev->wide = 1;
+ esp_dev->sync_min_period = 0;
+ esp_dev->sync_max_offset = 0;
+ return 0;
+ } else {
+ ESPMISC(("not sync nego, sending ABORT\n"));
+ return ABORT;
+ }
+ };
+}
+
+/* Target negotiates for synchronous transfers before we do, this
+ * is legal although very strange. What is even funnier is that
+ * the SCSI2 standard specifically recommends against targets doing
+ * this because so many initiators cannot cope with this occurring.
+ */
+static int target_with_ants_in_pants(struct NCR_ESP *esp,
+ Scsi_Cmnd *SCptr,
+ struct esp_device *esp_dev)
+{
+ if(esp_dev->sync || SCptr->device->borken) {
+ /* sorry, no can do */
+ ESPSDTR(("forcing to async, "));
+ build_sync_nego_msg(esp, 0, 0);
+ esp_dev->sync = 1;
+ esp->snip = 1;
+ ESPLOG(("esp%d: hoping for msgout\n", esp->esp_id));
+ esp_advance_phase(SCptr, in_the_dark);
+ return EXTENDED_MESSAGE;
+ }
+
+ /* Ok, we'll check them out... */
+ return 0;
+}
+
+static void sync_report(struct NCR_ESP *esp)
+{
+ int msg3, msg4;
+ char *type;
+
+ msg3 = esp->cur_msgin[3];
+ msg4 = esp->cur_msgin[4];
+ if(msg4) {
+ int hz = 1000000000 / (msg3 * 4);
+ int integer = hz / 1000000;
+ int fraction = (hz - (integer * 1000000)) / 10000;
+ if((msg3 * 4) < 200) {
+ type = "FAST";
+ } else {
+ type = "synchronous";
+ }
+
+ /* Do not transform this back into one big printk
+ * again, it triggers a bug in our sparc64-gcc272
+ * sibling call optimization. -DaveM
+ */
+ ESPLOG((KERN_INFO "esp%d: target %d ",
+ esp->esp_id, esp->current_SC->device->id));
+ ESPLOG(("[period %dns offset %d %d.%02dMHz ",
+ (int) msg3 * 4, (int) msg4,
+ integer, fraction));
+ ESPLOG(("%s SCSI%s]\n", type,
+ (((msg3 * 4) < 200) ? "-II" : "")));
+ } else {
+ ESPLOG((KERN_INFO "esp%d: target %d asynchronous\n",
+ esp->esp_id, esp->current_SC->device->id));
+ }
+}
+
+static int check_multibyte_msg(struct NCR_ESP *esp,
+ struct ESP_regs *eregs)
+{
+ Scsi_Cmnd *SCptr = esp->current_SC;
+ struct esp_device *esp_dev = SCptr->device->hostdata;
+ unchar regval = 0;
+ int message_out = 0;
+
+ ESPSDTR(("chk multibyte msg: "));
+ if(esp->cur_msgin[2] == EXTENDED_SDTR) {
+ int period = esp->cur_msgin[3];
+ int offset = esp->cur_msgin[4];
+
+ ESPSDTR(("is sync nego response, "));
+ if(!esp->snip) {
+ int rval;
+
+ /* Target negotiates first! */
+ ESPSDTR(("target jumps the gun, "));
+ message_out = EXTENDED_MESSAGE; /* we must respond */
+ rval = target_with_ants_in_pants(esp, SCptr, esp_dev);
+ if(rval)
+ return rval;
+ }
+
+ ESPSDTR(("examining sdtr, "));
+
+ /* Offset cannot be larger than ESP fifo size. */
+ if(offset > 15) {
+ ESPSDTR(("offset too big %2x, ", offset));
+ offset = 15;
+ ESPSDTR(("sending back new offset\n"));
+ build_sync_nego_msg(esp, period, offset);
+ return EXTENDED_MESSAGE;
+ }
+
+ if(offset && period > esp->max_period) {
+ /* Yeee, async for this slow device. */
+ ESPSDTR(("period too long %2x, ", period));
+ build_sync_nego_msg(esp, 0, 0);
+ ESPSDTR(("hoping for msgout\n"));
+ esp_advance_phase(esp->current_SC, in_the_dark);
+ return EXTENDED_MESSAGE;
+ } else if (offset && period < esp->min_period) {
+ ESPSDTR(("period too short %2x, ", period));
+ period = esp->min_period;
+ if(esp->erev > esp236)
+ regval = 4;
+ else
+ regval = 5;
+ } else if(offset) {
+ int tmp;
+
+ ESPSDTR(("period is ok, "));
+ tmp = esp->ccycle / 1000;
+ regval = (((period << 2) + tmp - 1) / tmp);
+ if(regval && (esp->erev > esp236)) {
+ if(period >= 50)
+ regval--;
+ }
+ }
+
+ if(offset) {
+ unchar bit;
+
+ esp_dev->sync_min_period = (regval & 0x1f);
+ esp_dev->sync_max_offset = (offset | esp->radelay);
+ if(esp->erev > esp236) {
+ if(esp->erev == fas100a)
+ bit = ESP_CONFIG3_FAST;
+ else
+ bit = ESP_CONFIG3_FSCSI;
+ if(period < 50)
+ esp->config3[SCptr->device->id] |= bit;
+ else
+ esp->config3[SCptr->device->id] &= ~bit;
+ esp->prev_cfg3 = esp->config3[SCptr->device->id];
+ esp_write(eregs->esp_cfg3, esp->prev_cfg3);
+ }
+ esp->prev_soff = esp_dev->sync_min_period;
+ esp_write(eregs->esp_soff, esp->prev_soff);
+ esp->prev_stp = esp_dev->sync_max_offset;
+ esp_write(eregs->esp_stp, esp->prev_stp);
+
+ ESPSDTR(("soff=%2x stp=%2x cfg3=%2x\n",
+ esp_dev->sync_max_offset,
+ esp_dev->sync_min_period,
+ esp->config3[scmd_id(SCptr)]));
+
+ esp->snip = 0;
+ } else if(esp_dev->sync_max_offset) {
+ unchar bit;
+
+ /* back to async mode */
+ ESPSDTR(("unaccaptable sync nego, forcing async\n"));
+ esp_dev->sync_max_offset = 0;
+ esp_dev->sync_min_period = 0;
+ esp->prev_soff = 0;
+ esp_write(eregs->esp_soff, 0);
+ esp->prev_stp = 0;
+ esp_write(eregs->esp_stp, 0);
+ if(esp->erev > esp236) {
+ if(esp->erev == fas100a)
+ bit = ESP_CONFIG3_FAST;
+ else
+ bit = ESP_CONFIG3_FSCSI;
+ esp->config3[SCptr->device->id] &= ~bit;
+ esp->prev_cfg3 = esp->config3[SCptr->device->id];
+ esp_write(eregs->esp_cfg3, esp->prev_cfg3);
+ }
+ }
+
+ sync_report(esp);
+
+ ESPSDTR(("chk multibyte msg: sync is known, "));
+ esp_dev->sync = 1;
+
+ if(message_out) {
+ ESPLOG(("esp%d: sending sdtr back, hoping for msgout\n",
+ esp->esp_id));
+ build_sync_nego_msg(esp, period, offset);
+ esp_advance_phase(SCptr, in_the_dark);
+ return EXTENDED_MESSAGE;
+ }
+
+ ESPSDTR(("returning zero\n"));
+ esp_advance_phase(SCptr, in_the_dark); /* ...or else! */
+ return 0;
+ } else if(esp->cur_msgin[2] == EXTENDED_WDTR) {
+ ESPLOG(("esp%d: AIEEE wide msg received\n", esp->esp_id));
+ message_out = MESSAGE_REJECT;
+ } else if(esp->cur_msgin[2] == EXTENDED_MODIFY_DATA_POINTER) {
+ ESPLOG(("esp%d: rejecting modify data ptr msg\n", esp->esp_id));
+ message_out = MESSAGE_REJECT;
+ }
+ esp_advance_phase(SCptr, in_the_dark);
+ return message_out;
+}
+
+static int esp_do_msgindone(struct NCR_ESP *esp, struct ESP_regs *eregs)
+{
+ Scsi_Cmnd *SCptr = esp->current_SC;
+ int message_out = 0, it = 0, rval;
+
+ rval = skipahead1(esp, eregs, SCptr, in_msgin, in_msgindone);
+ if(rval)
+ return rval;
+ if(SCptr->SCp.sent_command != in_status) {
+ if(!(esp->ireg & ESP_INTR_DC)) {
+ if(esp->msgin_len && (esp->sreg & ESP_STAT_PERR)) {
+ message_out = MSG_PARITY_ERROR;
+ esp_cmd(esp, eregs, ESP_CMD_FLUSH);
+ } else if((it = (esp_read(eregs->esp_fflags) & ESP_FF_FBYTES))!=1) {
+ /* We certainly dropped the ball somewhere. */
+ message_out = INITIATOR_ERROR;
+ esp_cmd(esp, eregs, ESP_CMD_FLUSH);
+ } else if(!esp->msgin_len) {
+ it = esp_read(eregs->esp_fdata);
+ esp_advance_phase(SCptr, in_msgincont);
+ } else {
+ /* it is ok and we want it */
+ it = esp->cur_msgin[esp->msgin_ctr] =
+ esp_read(eregs->esp_fdata);
+ esp->msgin_ctr++;
+ }
+ } else {
+ esp_advance_phase(SCptr, in_the_dark);
+ return do_work_bus;
+ }
+ } else {
+ it = esp->cur_msgin[0];
+ }
+ if(!message_out && esp->msgin_len) {
+ if(esp->msgin_ctr < esp->msgin_len) {
+ esp_advance_phase(SCptr, in_msgincont);
+ } else if(esp->msgin_len == 1) {
+ message_out = check_singlebyte_msg(esp, eregs);
+ } else if(esp->msgin_len == 2) {
+ if(esp->cur_msgin[0] == EXTENDED_MESSAGE) {
+ if((it+2) >= 15) {
+ message_out = MESSAGE_REJECT;
+ } else {
+ esp->msgin_len = (it + 2);
+ esp_advance_phase(SCptr, in_msgincont);
+ }
+ } else {
+ message_out = MESSAGE_REJECT; /* foo on you */
+ }
+ } else {
+ message_out = check_multibyte_msg(esp, eregs);
+ }
+ }
+ if(message_out < 0) {
+ return -message_out;
+ } else if(message_out) {
+ if(((message_out != 1) &&
+ ((message_out < 0x20) || (message_out & 0x80))))
+ esp->msgout_len = 1;
+ esp->cur_msgout[0] = message_out;
+ esp_cmd(esp, eregs, ESP_CMD_SATN);
+ esp_advance_phase(SCptr, in_the_dark);
+ esp->msgin_len = 0;
+ }
+ esp->sreg = esp_read(eregs->esp_status);
+ esp->sreg &= ~(ESP_STAT_INTR);
+ if((esp->sreg & (ESP_STAT_PMSG|ESP_STAT_PCD)) == (ESP_STAT_PMSG|ESP_STAT_PCD))
+ esp_cmd(esp, eregs, ESP_CMD_MOK);
+ if((SCptr->SCp.sent_command == in_msgindone) &&
+ (SCptr->SCp.phase == in_freeing))
+ return esp_do_freebus(esp, eregs);
+ return do_intr_end;
+}
+
+static int esp_do_cmdbegin(struct NCR_ESP *esp, struct ESP_regs *eregs)
+{
+ unsigned char tmp;
+ Scsi_Cmnd *SCptr = esp->current_SC;
+
+ esp_advance_phase(SCptr, in_cmdend);
+ esp_cmd(esp, eregs, ESP_CMD_FLUSH);
+ tmp = *esp->esp_scmdp++;
+ esp->esp_scmdleft--;
+ esp_write(eregs->esp_fdata, tmp);
+ esp_cmd(esp, eregs, ESP_CMD_TI);
+ return do_intr_end;
+}
+
+static int esp_do_cmddone(struct NCR_ESP *esp, struct ESP_regs *eregs)
+{
+ esp_cmd(esp, eregs, ESP_CMD_NULL);
+ if(esp->ireg & ESP_INTR_BSERV) {
+ esp_advance_phase(esp->current_SC, in_the_dark);
+ return esp_do_phase_determine(esp, eregs);
+ }
+ ESPLOG(("esp%d: in do_cmddone() but didn't get BSERV interrupt.\n",
+ esp->esp_id));
+ return do_reset_bus;
+}
+
+static int esp_do_msgout(struct NCR_ESP *esp, struct ESP_regs *eregs)
+{
+ esp_cmd(esp, eregs, ESP_CMD_FLUSH);
+ switch(esp->msgout_len) {
+ case 1:
+ esp_write(eregs->esp_fdata, esp->cur_msgout[0]);
+ esp_cmd(esp, eregs, ESP_CMD_TI);
+ break;
+
+ case 2:
+ if(esp->do_pio_cmds){
+ esp_write(eregs->esp_fdata, esp->cur_msgout[0]);
+ esp_write(eregs->esp_fdata, esp->cur_msgout[1]);
+ esp_cmd(esp, eregs, ESP_CMD_TI);
+ } else {
+ esp->esp_command[0] = esp->cur_msgout[0];
+ esp->esp_command[1] = esp->cur_msgout[1];
+ esp->dma_setup(esp, esp->esp_command_dvma, 2, 0);
+ esp_setcount(eregs, 2);
+ esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI);
+ }
+ break;
+
+ case 4:
+ esp->snip = 1;
+ if(esp->do_pio_cmds){
+ esp_write(eregs->esp_fdata, esp->cur_msgout[0]);
+ esp_write(eregs->esp_fdata, esp->cur_msgout[1]);
+ esp_write(eregs->esp_fdata, esp->cur_msgout[2]);
+ esp_write(eregs->esp_fdata, esp->cur_msgout[3]);
+ esp_cmd(esp, eregs, ESP_CMD_TI);
+ } else {
+ esp->esp_command[0] = esp->cur_msgout[0];
+ esp->esp_command[1] = esp->cur_msgout[1];
+ esp->esp_command[2] = esp->cur_msgout[2];
+ esp->esp_command[3] = esp->cur_msgout[3];
+ esp->dma_setup(esp, esp->esp_command_dvma, 4, 0);
+ esp_setcount(eregs, 4);
+ esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI);
+ }
+ break;
+
+ case 5:
+ esp->snip = 1;
+ if(esp->do_pio_cmds){
+ esp_write(eregs->esp_fdata, esp->cur_msgout[0]);
+ esp_write(eregs->esp_fdata, esp->cur_msgout[1]);
+ esp_write(eregs->esp_fdata, esp->cur_msgout[2]);
+ esp_write(eregs->esp_fdata, esp->cur_msgout[3]);
+ esp_write(eregs->esp_fdata, esp->cur_msgout[4]);
+ esp_cmd(esp, eregs, ESP_CMD_TI);
+ } else {
+ esp->esp_command[0] = esp->cur_msgout[0];
+ esp->esp_command[1] = esp->cur_msgout[1];
+ esp->esp_command[2] = esp->cur_msgout[2];
+ esp->esp_command[3] = esp->cur_msgout[3];
+ esp->esp_command[4] = esp->cur_msgout[4];
+ esp->dma_setup(esp, esp->esp_command_dvma, 5, 0);
+ esp_setcount(eregs, 5);
+ esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI);
+ }
+ break;
+
+ default:
+ /* whoops */
+ ESPMISC(("bogus msgout sending NOP\n"));
+ esp->cur_msgout[0] = NOP;
+ esp_write(eregs->esp_fdata, esp->cur_msgout[0]);
+ esp->msgout_len = 1;
+ esp_cmd(esp, eregs, ESP_CMD_TI);
+ break;
+ }
+ esp_advance_phase(esp->current_SC, in_msgoutdone);
+ return do_intr_end;
+}
+
+static int esp_do_msgoutdone(struct NCR_ESP *esp,
+ struct ESP_regs *eregs)
+{
+ if((esp->msgout_len > 1) && esp->dma_barrier)
+ esp->dma_barrier(esp);
+
+ if(!(esp->ireg & ESP_INTR_DC)) {
+ esp_cmd(esp, eregs, ESP_CMD_NULL);
+ switch(esp->sreg & ESP_STAT_PMASK) {
+ case ESP_MOP:
+ /* whoops, parity error */
+ ESPLOG(("esp%d: still in msgout, parity error assumed\n",
+ esp->esp_id));
+ if(esp->msgout_len > 1)
+ esp_cmd(esp, eregs, ESP_CMD_SATN);
+ esp_advance_phase(esp->current_SC, in_msgout);
+ return do_work_bus;
+
+ case ESP_DIP:
+ break;
+
+ default:
+ if(!fcount(esp, eregs) &&
+ !(((struct esp_device *)esp->current_SC->device->hostdata)->sync_max_offset))
+ esp_cmd(esp, eregs, ESP_CMD_FLUSH);
+ break;
+
+ };
+ }
+
+ /* If we sent out a synchronous negotiation message, update
+ * our state.
+ */
+ if(esp->cur_msgout[2] == EXTENDED_MESSAGE &&
+ esp->cur_msgout[4] == EXTENDED_SDTR) {
+ esp->snip = 1; /* anal retentiveness... */
+ }
+
+ esp->prevmsgout = esp->cur_msgout[0];
+ esp->msgout_len = 0;
+ esp_advance_phase(esp->current_SC, in_the_dark);
+ return esp_do_phase_determine(esp, eregs);
+}
+
+static int esp_bus_unexpected(struct NCR_ESP *esp, struct ESP_regs *eregs)
+{
+ ESPLOG(("esp%d: command in weird state %2x\n",
+ esp->esp_id, esp->current_SC->SCp.phase));
+ return do_reset_bus;
+}
+
+static espfunc_t bus_vector[] = {
+ esp_do_data_finale,
+ esp_do_data_finale,
+ esp_bus_unexpected,
+ esp_do_msgin,
+ esp_do_msgincont,
+ esp_do_msgindone,
+ esp_do_msgout,
+ esp_do_msgoutdone,
+ esp_do_cmdbegin,
+ esp_do_cmddone,
+ esp_do_status,
+ esp_do_freebus,
+ esp_do_phase_determine,
+ esp_bus_unexpected,
+ esp_bus_unexpected,
+ esp_bus_unexpected,
+};
+
+/* This is the second tier in our dual-level SCSI state machine. */
+static int esp_work_bus(struct NCR_ESP *esp, struct ESP_regs *eregs)
+{
+ Scsi_Cmnd *SCptr = esp->current_SC;
+ unsigned int phase;
+
+ ESPBUS(("esp_work_bus: "));
+ if(!SCptr) {
+ ESPBUS(("reconnect\n"));
+ return esp_do_reconnect(esp, eregs);
+ }
+ phase = SCptr->SCp.phase;
+ if ((phase & 0xf0) == in_phases_mask)
+ return bus_vector[(phase & 0x0f)](esp, eregs);
+ else if((phase & 0xf0) == in_slct_mask)
+ return esp_select_complete(esp, eregs);
+ else
+ return esp_bus_unexpected(esp, eregs);
+}
+
+static espfunc_t isvc_vector[] = {
+ NULL,
+ esp_do_phase_determine,
+ esp_do_resetbus,
+ esp_finish_reset,
+ esp_work_bus
+};
+
+/* Main interrupt handler for an esp adapter. */
+void esp_handle(struct NCR_ESP *esp)
+{
+ struct ESP_regs *eregs;
+ Scsi_Cmnd *SCptr;
+ int what_next = do_intr_end;
+ eregs = esp->eregs;
+ SCptr = esp->current_SC;
+
+ if(esp->dma_irq_entry)
+ esp->dma_irq_entry(esp);
+
+ /* Check for errors. */
+ esp->sreg = esp_read(eregs->esp_status);
+ esp->sreg &= (~ESP_STAT_INTR);
+ esp->seqreg = (esp_read(eregs->esp_sstep) & ESP_STEP_VBITS);
+ esp->ireg = esp_read(eregs->esp_intrpt); /* Unlatch intr and stat regs */
+ ESPIRQ(("handle_irq: [sreg<%02x> sstep<%02x> ireg<%02x>]\n",
+ esp->sreg, esp->seqreg, esp->ireg));
+ if(esp->sreg & (ESP_STAT_SPAM)) {
+ /* Gross error, could be due to one of:
+ *
+ * - top of fifo overwritten, could be because
+ * we tried to do a synchronous transfer with
+ * an offset greater than ESP fifo size
+ *
+ * - top of command register overwritten
+ *
+ * - DMA setup to go in one direction, SCSI
+ * bus points in the other, whoops
+ *
+ * - weird phase change during asynchronous
+ * data phase while we are initiator
+ */
+ ESPLOG(("esp%d: Gross error sreg=%2x\n", esp->esp_id, esp->sreg));
+
+ /* If a command is live on the bus we cannot safely
+ * reset the bus, so we'll just let the pieces fall
+ * where they may. Here we are hoping that the
+ * target will be able to cleanly go away soon
+ * so we can safely reset things.
+ */
+ if(!SCptr) {
+ ESPLOG(("esp%d: No current cmd during gross error, "
+ "resetting bus\n", esp->esp_id));
+ what_next = do_reset_bus;
+ goto state_machine;
+ }
+ }
+
+ /* No current cmd is only valid at this point when there are
+ * commands off the bus or we are trying a reset.
+ */
+ if(!SCptr && !esp->disconnected_SC && !(esp->ireg & ESP_INTR_SR)) {
+ /* Panic is safe, since current_SC is null. */
+ ESPLOG(("esp%d: no command in esp_handle()\n", esp->esp_id));
+ panic("esp_handle: current_SC == penguin within interrupt!");
+ }
+
+ if(esp->ireg & (ESP_INTR_IC)) {
+ /* Illegal command fed to ESP. Outside of obvious
+ * software bugs that could cause this, there is
+ * a condition with ESP100 where we can confuse the
+ * ESP into an erroneous illegal command interrupt
+ * because it does not scrape the FIFO properly
+ * for reselection. See esp100_reconnect_hwbug()
+ * to see how we try very hard to avoid this.
+ */
+ ESPLOG(("esp%d: invalid command\n", esp->esp_id));
+
+ esp_dump_state(esp, eregs);
+
+ if(SCptr) {
+ /* Devices with very buggy firmware can drop BSY
+ * during a scatter list interrupt when using sync
+ * mode transfers. We continue the transfer as
+ * expected, the target drops the bus, the ESP
+ * gets confused, and we get a illegal command
+ * interrupt because the bus is in the disconnected
+ * state now and ESP_CMD_TI is only allowed when
+ * a nexus is alive on the bus.
+ */
+ ESPLOG(("esp%d: Forcing async and disabling disconnect for "
+ "target %d\n", esp->esp_id, SCptr->device->id));
+ SCptr->device->borken = 1; /* foo on you */
+ }
+
+ what_next = do_reset_bus;
+ } else if(!(esp->ireg & ~(ESP_INTR_FDONE | ESP_INTR_BSERV | ESP_INTR_DC))) {
+ int phase;
+
+ if(SCptr) {
+ phase = SCptr->SCp.phase;
+ if(phase & in_phases_mask) {
+ what_next = esp_work_bus(esp, eregs);
+ } else if(phase & in_slct_mask) {
+ what_next = esp_select_complete(esp, eregs);
+ } else {
+ ESPLOG(("esp%d: interrupt for no good reason...\n",
+ esp->esp_id));
+ what_next = do_intr_end;
+ }
+ } else {
+ ESPLOG(("esp%d: BSERV or FDONE or DC while SCptr==NULL\n",
+ esp->esp_id));
+ what_next = do_reset_bus;
+ }
+ } else if(esp->ireg & ESP_INTR_SR) {
+ ESPLOG(("esp%d: SCSI bus reset interrupt\n", esp->esp_id));
+ what_next = do_reset_complete;
+ } else if(esp->ireg & (ESP_INTR_S | ESP_INTR_SATN)) {
+ ESPLOG(("esp%d: AIEEE we have been selected by another initiator!\n",
+ esp->esp_id));
+ what_next = do_reset_bus;
+ } else if(esp->ireg & ESP_INTR_RSEL) {
+ if(!SCptr) {
+ /* This is ok. */
+ what_next = esp_do_reconnect(esp, eregs);
+ } else if(SCptr->SCp.phase & in_slct_mask) {
+ /* Only selection code knows how to clean
+ * up properly.
+ */
+ ESPDISC(("Reselected during selection attempt\n"));
+ what_next = esp_select_complete(esp, eregs);
+ } else {
+ ESPLOG(("esp%d: Reselected while bus is busy\n",
+ esp->esp_id));
+ what_next = do_reset_bus;
+ }
+ }
+
+ /* This is tier-one in our dual level SCSI state machine. */
+state_machine:
+ while(what_next != do_intr_end) {
+ if (what_next >= do_phase_determine &&
+ what_next < do_intr_end)
+ what_next = isvc_vector[what_next](esp, eregs);
+ else {
+ /* state is completely lost ;-( */
+ ESPLOG(("esp%d: interrupt engine loses state, resetting bus\n",
+ esp->esp_id));
+ what_next = do_reset_bus;
+ }
+ }
+ if(esp->dma_irq_exit)
+ esp->dma_irq_exit(esp);
+}
+EXPORT_SYMBOL(esp_handle);
+
+#ifndef CONFIG_SMP
+irqreturn_t esp_intr(int irq, void *dev_id)
+{
+ struct NCR_ESP *esp;
+ unsigned long flags;
+ int again;
+ struct Scsi_Host *dev = dev_id;
+
+ /* Handle all ESP interrupts showing at this IRQ level. */
+ spin_lock_irqsave(dev->host_lock, flags);
+repeat:
+ again = 0;
+ for_each_esp(esp) {
+#ifndef __mips__
+ if(((esp)->irq & 0xff) == irq) {
+#endif
+ if(esp->dma_irq_p(esp)) {
+ again = 1;
+
+ esp->dma_ints_off(esp);
+
+ ESPIRQ(("I%d(", esp->esp_id));
+ esp_handle(esp);
+ ESPIRQ((")"));
+
+ esp->dma_ints_on(esp);
+ }
+#ifndef __mips__
+ }
+#endif
+ }
+ if(again)
+ goto repeat;
+ spin_unlock_irqrestore(dev->host_lock, flags);
+ return IRQ_HANDLED;
+}
+#else
+/* For SMP we only service one ESP on the list list at our IRQ level! */
+irqreturn_t esp_intr(int irq, void *dev_id)
+{
+ struct NCR_ESP *esp;
+ unsigned long flags;
+ struct Scsi_Host *dev = dev_id;
+
+ /* Handle all ESP interrupts showing at this IRQ level. */
+ spin_lock_irqsave(dev->host_lock, flags);
+ for_each_esp(esp) {
+ if(((esp)->irq & 0xf) == irq) {
+ if(esp->dma_irq_p(esp)) {
+ esp->dma_ints_off(esp);
+
+ ESPIRQ(("I[%d:%d](",
+ smp_processor_id(), esp->esp_id));
+ esp_handle(esp);
+ ESPIRQ((")"));
+
+ esp->dma_ints_on(esp);
+ goto out;
+ }
+ }
+ }
+out:
+ spin_unlock_irqrestore(dev->host_lock, flags);
+ return IRQ_HANDLED;
+}
+#endif
+
+int esp_slave_alloc(struct scsi_device *SDptr)
+{
+ struct esp_device *esp_dev =
+ kzalloc(sizeof(struct esp_device), GFP_ATOMIC);
+
+ if (!esp_dev)
+ return -ENOMEM;
+ SDptr->hostdata = esp_dev;
+ return 0;
+}
+
+void esp_slave_destroy(struct scsi_device *SDptr)
+{
+ struct NCR_ESP *esp = (struct NCR_ESP *) SDptr->host->hostdata;
+
+ esp->targets_present &= ~(1 << sdev_id(SDptr));
+ kfree(SDptr->hostdata);
+ SDptr->hostdata = NULL;
+}
+
+#ifdef MODULE
+int init_module(void) { return 0; }
+void cleanup_module(void) {}
+void esp_release(void)
+{
+ esps_in_use--;
+ esps_running = esps_in_use;
+}
+EXPORT_SYMBOL(esp_release);
+#endif
+
+EXPORT_SYMBOL(esp_abort);
+EXPORT_SYMBOL(esp_allocate);
+EXPORT_SYMBOL(esp_deallocate);
+EXPORT_SYMBOL(esp_initialize);
+EXPORT_SYMBOL(esp_intr);
+EXPORT_SYMBOL(esp_queue);
+EXPORT_SYMBOL(esp_reset);
+EXPORT_SYMBOL(esp_slave_alloc);
+EXPORT_SYMBOL(esp_slave_destroy);
+EXPORT_SYMBOL(esps_in_use);
+
+MODULE_LICENSE("GPL");
diff --git a/trunk/drivers/scsi/NCR53C9x.h b/trunk/drivers/scsi/NCR53C9x.h
new file mode 100644
index 000000000000..00a0ba040dba
--- /dev/null
+++ b/trunk/drivers/scsi/NCR53C9x.h
@@ -0,0 +1,668 @@
+/* NCR53C9x.c: Defines and structures for the NCR53C9x generic driver.
+ *
+ * Originally esp.h: Defines and structures for the Sparc ESP
+ * (Enhanced SCSI Processor) driver under Linux.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ *
+ * Generalization by Jesper Skov (jskov@cygnus.co.uk)
+ *
+ * More generalization (for i386 stuff) by Tymm Twillman (tymm@computer.org)
+ */
+
+#ifndef NCR53C9X_H
+#define NCR53C9X_H
+
+#include
+
+/* djweis for mac driver */
+#if defined(CONFIG_MAC)
+#define PAD_SIZE 15
+#else
+#define PAD_SIZE 3
+#endif
+
+/* Handle multiple hostadapters on Amiga
+ * generally PAD_SIZE = 3
+ * but there is one exception: Oktagon (PAD_SIZE = 1) */
+#if defined(CONFIG_OKTAGON_SCSI) || defined(CONFIG_OKTAGON_SCSI_MODULE)
+#undef PAD_SIZE
+#if defined(CONFIG_BLZ1230_SCSI) || defined(CONFIG_BLZ1230_SCSI_MODULE) || \
+ defined(CONFIG_BLZ2060_SCSI) || defined(CONFIG_BLZ2060_SCSI_MODULE) || \
+ defined(CONFIG_CYBERSTORM_SCSI) || defined(CONFIG_CYBERSTORM_SCSI_MODULE) || \
+ defined(CONFIG_CYBERSTORMII_SCSI) || defined(CONFIG_CYBERSTORMII_SCSI_MODULE) || \
+ defined(CONFIG_FASTLANE_SCSI) || defined(CONFIG_FASTLANE_SCSI_MODULE)
+#define MULTIPLE_PAD_SIZES
+#else
+#define PAD_SIZE 1
+#endif
+#endif
+
+/* Macros for debugging messages */
+
+#define DEBUG_ESP
+/* #define DEBUG_ESP_DATA */
+/* #define DEBUG_ESP_QUEUE */
+/* #define DEBUG_ESP_DISCONNECT */
+/* #define DEBUG_ESP_STATUS */
+/* #define DEBUG_ESP_PHASES */
+/* #define DEBUG_ESP_WORKBUS */
+/* #define DEBUG_STATE_MACHINE */
+/* #define DEBUG_ESP_CMDS */
+/* #define DEBUG_ESP_IRQS */
+/* #define DEBUG_SDTR */
+/* #define DEBUG_ESP_SG */
+
+/* Use the following to sprinkle debugging messages in a way which
+ * suits you if combinations of the above become too verbose when
+ * trying to track down a specific problem.
+ */
+/* #define DEBUG_ESP_MISC */
+
+#if defined(DEBUG_ESP)
+#define ESPLOG(foo) printk foo
+#else
+#define ESPLOG(foo)
+#endif /* (DEBUG_ESP) */
+
+#if defined(DEBUG_ESP_DATA)
+#define ESPDATA(foo) printk foo
+#else
+#define ESPDATA(foo)
+#endif
+
+#if defined(DEBUG_ESP_QUEUE)
+#define ESPQUEUE(foo) printk foo
+#else
+#define ESPQUEUE(foo)
+#endif
+
+#if defined(DEBUG_ESP_DISCONNECT)
+#define ESPDISC(foo) printk foo
+#else
+#define ESPDISC(foo)
+#endif
+
+#if defined(DEBUG_ESP_STATUS)
+#define ESPSTAT(foo) printk foo
+#else
+#define ESPSTAT(foo)
+#endif
+
+#if defined(DEBUG_ESP_PHASES)
+#define ESPPHASE(foo) printk foo
+#else
+#define ESPPHASE(foo)
+#endif
+
+#if defined(DEBUG_ESP_WORKBUS)
+#define ESPBUS(foo) printk foo
+#else
+#define ESPBUS(foo)
+#endif
+
+#if defined(DEBUG_ESP_IRQS)
+#define ESPIRQ(foo) printk foo
+#else
+#define ESPIRQ(foo)
+#endif
+
+#if defined(DEBUG_SDTR)
+#define ESPSDTR(foo) printk foo
+#else
+#define ESPSDTR(foo)
+#endif
+
+#if defined(DEBUG_ESP_MISC)
+#define ESPMISC(foo) printk foo
+#else
+#define ESPMISC(foo)
+#endif
+
+/*
+ * padding for register structure
+ */
+#ifdef CONFIG_JAZZ_ESP
+#define EREGS_PAD(n)
+#else
+#ifndef MULTIPLE_PAD_SIZES
+#define EREGS_PAD(n) unchar n[PAD_SIZE];
+#endif
+#endif
+
+/* The ESP SCSI controllers have their register sets in three
+ * "classes":
+ *
+ * 1) Registers which are both read and write.
+ * 2) Registers which are read only.
+ * 3) Registers which are write only.
+ *
+ * Yet, they all live within the same IO space.
+ */
+
+#if !defined(__i386__) && !defined(__x86_64__)
+
+#ifndef MULTIPLE_PAD_SIZES
+
+#ifdef CONFIG_CPU_HAS_WB
+#include
+#define esp_write(__reg, __val) do{(__reg) = (__val); wbflush();} while(0)
+#else
+#define esp_write(__reg, __val) ((__reg) = (__val))
+#endif
+#define esp_read(__reg) (__reg)
+
+struct ESP_regs {
+ /* Access Description Offset */
+ volatile unchar esp_tclow; /* rw Low bits of the transfer count 0x00 */
+ EREGS_PAD(tlpad1);
+ volatile unchar esp_tcmed; /* rw Mid bits of the transfer count 0x04 */
+ EREGS_PAD(fdpad);
+ volatile unchar esp_fdata; /* rw FIFO data bits 0x08 */
+ EREGS_PAD(cbpad);
+ volatile unchar esp_cmnd; /* rw SCSI command bits 0x0c */
+ EREGS_PAD(stpad);
+ volatile unchar esp_status; /* ro ESP status register 0x10 */
+#define esp_busid esp_status /* wo Bus ID for select/reselect 0x10 */
+ EREGS_PAD(irqpd);
+ volatile unchar esp_intrpt; /* ro Kind of interrupt 0x14 */
+#define esp_timeo esp_intrpt /* wo Timeout value for select/resel 0x14 */
+ EREGS_PAD(sspad);
+ volatile unchar esp_sstep; /* ro Sequence step register 0x18 */
+#define esp_stp esp_sstep /* wo Transfer period per sync 0x18 */
+ EREGS_PAD(ffpad);
+ volatile unchar esp_fflags; /* ro Bits of current FIFO info 0x1c */
+#define esp_soff esp_fflags /* wo Sync offset 0x1c */
+ EREGS_PAD(cf1pd);
+ volatile unchar esp_cfg1; /* rw First configuration register 0x20 */
+ EREGS_PAD(cfpad);
+ volatile unchar esp_cfact; /* wo Clock conversion factor 0x24 */
+ EREGS_PAD(ctpad);
+ volatile unchar esp_ctest; /* wo Chip test register 0x28 */
+ EREGS_PAD(cf2pd);
+ volatile unchar esp_cfg2; /* rw Second configuration register 0x2c */
+ EREGS_PAD(cf3pd);
+
+ /* The following is only found on the 53C9X series SCSI chips */
+ volatile unchar esp_cfg3; /* rw Third configuration register 0x30 */
+ EREGS_PAD(cf4pd);
+ volatile unchar esp_cfg4; /* rw Fourth configuration register 0x34 */
+ EREGS_PAD(thpd);
+ /* The following is found on all chips except the NCR53C90 (ESP100) */
+ volatile unchar esp_tchi; /* rw High bits of transfer count 0x38 */
+#define esp_uid esp_tchi /* ro Unique ID code 0x38 */
+ EREGS_PAD(fgpad);
+ volatile unchar esp_fgrnd; /* rw Data base for fifo 0x3c */
+};
+
+#else /* MULTIPLE_PAD_SIZES */
+
+#define esp_write(__reg, __val) (*(__reg) = (__val))
+#define esp_read(__reg) (*(__reg))
+
+struct ESP_regs {
+ unsigned char io_addr[64]; /* dummy */
+ /* Access Description Offset */
+#define esp_tclow io_addr /* rw Low bits of the transfer count 0x00 */
+#define esp_tcmed io_addr + (1<<(esp->shift)) /* rw Mid bits of the transfer count 0x04 */
+#define esp_fdata io_addr + (2<<(esp->shift)) /* rw FIFO data bits 0x08 */
+#define esp_cmnd io_addr + (3<<(esp->shift)) /* rw SCSI command bits 0x0c */
+#define esp_status io_addr + (4<<(esp->shift)) /* ro ESP status register 0x10 */
+#define esp_busid esp_status /* wo Bus ID for select/reselect 0x10 */
+#define esp_intrpt io_addr + (5<<(esp->shift)) /* ro Kind of interrupt 0x14 */
+#define esp_timeo esp_intrpt /* wo Timeout value for select/resel 0x14 */
+#define esp_sstep io_addr + (6<<(esp->shift)) /* ro Sequence step register 0x18 */
+#define esp_stp esp_sstep /* wo Transfer period per sync 0x18 */
+#define esp_fflags io_addr + (7<<(esp->shift)) /* ro Bits of current FIFO info 0x1c */
+#define esp_soff esp_fflags /* wo Sync offset 0x1c */
+#define esp_cfg1 io_addr + (8<<(esp->shift)) /* rw First configuration register 0x20 */
+#define esp_cfact io_addr + (9<<(esp->shift)) /* wo Clock conversion factor 0x24 */
+#define esp_ctest io_addr + (10<<(esp->shift)) /* wo Chip test register 0x28 */
+#define esp_cfg2 io_addr + (11<<(esp->shift)) /* rw Second configuration register 0x2c */
+
+ /* The following is only found on the 53C9X series SCSI chips */
+#define esp_cfg3 io_addr + (12<<(esp->shift)) /* rw Third configuration register 0x30 */
+#define esp_cfg4 io_addr + (13<<(esp->shift)) /* rw Fourth configuration register 0x34 */
+
+ /* The following is found on all chips except the NCR53C90 (ESP100) */
+#define esp_tchi io_addr + (14<<(esp->shift)) /* rw High bits of transfer count 0x38 */
+#define esp_uid esp_tchi /* ro Unique ID code 0x38 */
+#define esp_fgrnd io_addr + (15<<(esp->shift)) /* rw Data base for fifo 0x3c */
+};
+
+#endif
+
+#else /* !defined(__i386__) && !defined(__x86_64__) */
+
+#define esp_write(__reg, __val) outb((__val), (__reg))
+#define esp_read(__reg) inb((__reg))
+
+struct ESP_regs {
+ unsigned int io_addr;
+ /* Access Description Offset */
+#define esp_tclow io_addr /* rw Low bits of the transfer count 0x00 */
+#define esp_tcmed io_addr + 1 /* rw Mid bits of the transfer count 0x04 */
+#define esp_fdata io_addr + 2 /* rw FIFO data bits 0x08 */
+#define esp_cmnd io_addr + 3 /* rw SCSI command bits 0x0c */
+#define esp_status io_addr + 4 /* ro ESP status register 0x10 */
+#define esp_busid esp_status /* wo Bus ID for select/reselect 0x10 */
+#define esp_intrpt io_addr + 5 /* ro Kind of interrupt 0x14 */
+#define esp_timeo esp_intrpt /* wo Timeout value for select/resel 0x14 */
+#define esp_sstep io_addr + 6 /* ro Sequence step register 0x18 */
+#define esp_stp esp_sstep /* wo Transfer period per sync 0x18 */
+#define esp_fflags io_addr + 7 /* ro Bits of current FIFO info 0x1c */
+#define esp_soff esp_fflags /* wo Sync offset 0x1c */
+#define esp_cfg1 io_addr + 8 /* rw First configuration register 0x20 */
+#define esp_cfact io_addr + 9 /* wo Clock conversion factor 0x24 */
+#define esp_ctest io_addr + 10 /* wo Chip test register 0x28 */
+#define esp_cfg2 io_addr + 11 /* rw Second configuration register 0x2c */
+
+ /* The following is only found on the 53C9X series SCSI chips */
+#define esp_cfg3 io_addr + 12 /* rw Third configuration register 0x30 */
+#define esp_cfg4 io_addr + 13 /* rw Fourth configuration register 0x34 */
+
+ /* The following is found on all chips except the NCR53C90 (ESP100) */
+#define esp_tchi io_addr + 14 /* rw High bits of transfer count 0x38 */
+#define esp_uid esp_tchi /* ro Unique ID code 0x38 */
+#define esp_fgrnd io_addr + 15 /* rw Data base for fifo 0x3c */
+};
+
+#endif /* !defined(__i386__) && !defined(__x86_64__) */
+
+/* Various revisions of the ESP board. */
+enum esp_rev {
+ esp100 = 0x00, /* NCR53C90 - very broken */
+ esp100a = 0x01, /* NCR53C90A */
+ esp236 = 0x02,
+ fas236 = 0x03,
+ fas100a = 0x04,
+ fast = 0x05,
+ fas366 = 0x06,
+ fas216 = 0x07,
+ fsc = 0x08, /* SYM53C94-2 */
+ espunknown = 0x09
+};
+
+/* We allocate one of these for each scsi device and attach it to
+ * SDptr->hostdata for use in the driver
+ */
+struct esp_device {
+ unsigned char sync_min_period;
+ unsigned char sync_max_offset;
+ unsigned sync:1;
+ unsigned wide:1;
+ unsigned disconnect:1;
+};
+
+/* We get one of these for each ESP probed. */
+struct NCR_ESP {
+ struct NCR_ESP *next; /* Next ESP on probed or NULL */
+ struct ESP_regs *eregs; /* All esp registers */
+ int dma; /* Who I do transfers with. */
+ void *dregs; /* And his registers. */
+ struct Scsi_Host *ehost; /* Backpointer to SCSI Host */
+
+ void *edev; /* Pointer to controller base/SBus */
+ int esp_id; /* Unique per-ESP ID number */
+
+ /* ESP Configuration Registers */
+ unsigned char config1; /* Copy of the 1st config register */
+ unsigned char config2; /* Copy of the 2nd config register */
+ unsigned char config3[16]; /* Copy of the 3rd config register */
+
+ /* The current command we are sending to the ESP chip. This esp_command
+ * ptr needs to be mapped in DVMA area so we can send commands and read
+ * from the ESP fifo without burning precious CPU cycles. Programmed I/O
+ * sucks when we have the DVMA to do it for us. The ESP is stupid and will
+ * only send out 6, 10, and 12 byte SCSI commands, others we need to send
+ * one byte at a time. esp_slowcmd being set says that we are doing one
+ * of the command types ESP doesn't understand, esp_scmdp keeps track of
+ * which byte we are sending, esp_scmdleft says how many bytes to go.
+ */
+ volatile unchar *esp_command; /* Location of command (CPU view) */
+ __u32 esp_command_dvma; /* Location of command (DVMA view) */
+ unsigned char esp_clen; /* Length of this command */
+ unsigned char esp_slowcmd;
+ unsigned char *esp_scmdp;
+ unsigned char esp_scmdleft;
+
+ /* The following are used to determine the cause of an IRQ. Upon every
+ * IRQ entry we synchronize these with the hardware registers.
+ */
+ unchar ireg; /* Copy of ESP interrupt register */
+ unchar sreg; /* Same for ESP status register */
+ unchar seqreg; /* The ESP sequence register */
+
+ /* The following is set when a premature interrupt condition is detected
+ * in some FAS revisions.
+ */
+ unchar fas_premature_intr_workaround;
+
+ /* To save register writes to the ESP, which can be expensive, we
+ * keep track of the previous value that various registers had for
+ * the last target we connected to. If they are the same for the
+ * current target, we skip the register writes as they are not needed.
+ */
+ unchar prev_soff, prev_stp, prev_cfg3;
+
+ /* For each target we keep track of save/restore data
+ * pointer information. This needs to be updated majorly
+ * when we add support for tagged queueing. -DaveM
+ */
+ struct esp_pointers {
+ char *saved_ptr;
+ struct scatterlist *saved_buffer;
+ int saved_this_residual;
+ int saved_buffers_residual;
+ } data_pointers[16] /*XXX [MAX_TAGS_PER_TARGET]*/;
+
+ /* Clock periods, frequencies, synchronization, etc. */
+ unsigned int cfreq; /* Clock frequency in HZ */
+ unsigned int cfact; /* Clock conversion factor */
+ unsigned int ccycle; /* One ESP clock cycle */
+ unsigned int ctick; /* One ESP clock time */
+ unsigned int radelay; /* FAST chip req/ack delay */
+ unsigned int neg_defp; /* Default negotiation period */
+ unsigned int sync_defp; /* Default sync transfer period */
+ unsigned int max_period; /* longest our period can be */
+ unsigned int min_period; /* shortest period we can withstand */
+ /* For slow to medium speed input clock rates we shoot for 5mb/s,
+ * but for high input clock rates we try to do 10mb/s although I
+ * don't think a transfer can even run that fast with an ESP even
+ * with DMA2 scatter gather pipelining.
+ */
+#define SYNC_DEFP_SLOW 0x32 /* 5mb/s */
+#define SYNC_DEFP_FAST 0x19 /* 10mb/s */
+
+ unsigned int snip; /* Sync. negotiation in progress */
+ unsigned int wnip; /* WIDE negotiation in progress */
+ unsigned int targets_present; /* targets spoken to before */
+
+ int current_transfer_size; /* Set at beginning of data dma */
+
+ unchar espcmdlog[32]; /* Log of current esp cmds sent. */
+ unchar espcmdent; /* Current entry in esp cmd log. */
+
+ /* Misc. info about this ESP */
+ enum esp_rev erev; /* ESP revision */
+ int irq; /* IRQ for this ESP */
+ int scsi_id; /* Who am I as initiator? */
+ int scsi_id_mask; /* Bitmask of 'me'. */
+ int diff; /* Differential SCSI bus? */
+ int slot; /* Slot the adapter occupies */
+
+ /* Our command queues, only one cmd lives in the current_SC queue. */
+ Scsi_Cmnd *issue_SC; /* Commands to be issued */
+ Scsi_Cmnd *current_SC; /* Who is currently working the bus */
+ Scsi_Cmnd *disconnected_SC; /* Commands disconnected from the bus */
+
+ /* Message goo */
+ unchar cur_msgout[16];
+ unchar cur_msgin[16];
+ unchar prevmsgout, prevmsgin;
+ unchar msgout_len, msgin_len;
+ unchar msgout_ctr, msgin_ctr;
+
+ /* States that we cannot keep in the per cmd structure because they
+ * cannot be assosciated with any specific command.
+ */
+ unchar resetting_bus;
+ wait_queue_head_t reset_queue;
+
+ unchar do_pio_cmds; /* Do command transfer with pio */
+
+ /* How much bits do we have to shift the registers */
+ unsigned char shift;
+
+ /* Functions handling DMA
+ */
+ /* Required functions */
+ int (*dma_bytes_sent)(struct NCR_ESP *, int);
+ int (*dma_can_transfer)(struct NCR_ESP *, Scsi_Cmnd *);
+ void (*dma_dump_state)(struct NCR_ESP *);
+ void (*dma_init_read)(struct NCR_ESP *, __u32, int);
+ void (*dma_init_write)(struct NCR_ESP *, __u32, int);
+ void (*dma_ints_off)(struct NCR_ESP *);
+ void (*dma_ints_on)(struct NCR_ESP *);
+ int (*dma_irq_p)(struct NCR_ESP *);
+ int (*dma_ports_p)(struct NCR_ESP *);
+ void (*dma_setup)(struct NCR_ESP *, __u32, int, int);
+
+ /* Optional functions (i.e. may be initialized to 0) */
+ void (*dma_barrier)(struct NCR_ESP *);
+ void (*dma_drain)(struct NCR_ESP *);
+ void (*dma_invalidate)(struct NCR_ESP *);
+ void (*dma_irq_entry)(struct NCR_ESP *);
+ void (*dma_irq_exit)(struct NCR_ESP *);
+ void (*dma_led_off)(struct NCR_ESP *);
+ void (*dma_led_on)(struct NCR_ESP *);
+ void (*dma_poll)(struct NCR_ESP *, unsigned char *);
+ void (*dma_reset)(struct NCR_ESP *);
+
+ /* Optional virtual DMA functions */
+ void (*dma_mmu_get_scsi_one)(struct NCR_ESP *, Scsi_Cmnd *);
+ void (*dma_mmu_get_scsi_sgl)(struct NCR_ESP *, Scsi_Cmnd *);
+ void (*dma_mmu_release_scsi_one)(struct NCR_ESP *, Scsi_Cmnd *);
+ void (*dma_mmu_release_scsi_sgl)(struct NCR_ESP *, Scsi_Cmnd *);
+ void (*dma_advance_sg)(Scsi_Cmnd *);
+};
+
+/* Bitfield meanings for the above registers. */
+
+/* ESP config reg 1, read-write, found on all ESP chips */
+#define ESP_CONFIG1_ID 0x07 /* My BUS ID bits */
+#define ESP_CONFIG1_CHTEST 0x08 /* Enable ESP chip tests */
+#define ESP_CONFIG1_PENABLE 0x10 /* Enable parity checks */
+#define ESP_CONFIG1_PARTEST 0x20 /* Parity test mode enabled? */
+#define ESP_CONFIG1_SRRDISAB 0x40 /* Disable SCSI reset reports */
+#define ESP_CONFIG1_SLCABLE 0x80 /* Enable slow cable mode */
+
+/* ESP config reg 2, read-write, found only on esp100a+esp200+esp236+fsc chips */
+#define ESP_CONFIG2_DMAPARITY 0x01 /* enable DMA Parity (200,236,fsc) */
+#define ESP_CONFIG2_REGPARITY 0x02 /* enable reg Parity (200,236,fsc) */
+#define ESP_CONFIG2_BADPARITY 0x04 /* Bad parity target abort */
+#define ESP_CONFIG2_SCSI2ENAB 0x08 /* Enable SCSI-2 features (tmode only) */
+#define ESP_CONFIG2_HI 0x10 /* High Impedance DREQ ??? */
+#define ESP_CONFIG2_HMEFENAB 0x10 /* HME features enable */
+#define ESP_CONFIG2_BCM 0x20 /* Enable byte-ctrl (236,fsc) */
+#define ESP_CONFIG2_FENAB 0x40 /* Enable features (fas100,esp216,fsc) */
+#define ESP_CONFIG2_SPL 0x40 /* Enable status-phase latch (esp236) */
+#define ESP_CONFIG2_RFB 0x80 /* Reserve FIFO byte (fsc) */
+#define ESP_CONFIG2_MAGIC 0xe0 /* Invalid bits... */
+
+/* ESP config register 3 read-write, found only esp236+fas236+fas100a+fsc chips */
+#define ESP_CONFIG3_FCLOCK 0x01 /* FAST SCSI clock rate (esp100a/fas366) */
+#define ESP_CONFIG3_TEM 0x01 /* Enable thresh-8 mode (esp/fas236/fsc) */
+#define ESP_CONFIG3_FAST 0x02 /* Enable FAST SCSI (esp100a) */
+#define ESP_CONFIG3_ADMA 0x02 /* Enable alternate-dma (esp/fas236/fsc) */
+#define ESP_CONFIG3_TENB 0x04 /* group2 SCSI2 support (esp100a) */
+#define ESP_CONFIG3_SRB 0x04 /* Save residual byte (esp/fas236/fsc) */
+#define ESP_CONFIG3_TMS 0x08 /* Three-byte msg's ok (esp100a) */
+#define ESP_CONFIG3_FCLK 0x08 /* Fast SCSI clock rate (esp/fas236/fsc) */
+#define ESP_CONFIG3_IDMSG 0x10 /* ID message checking (esp100a) */
+#define ESP_CONFIG3_FSCSI 0x10 /* Enable FAST SCSI (esp/fas236/fsc) */
+#define ESP_CONFIG3_GTM 0x20 /* group2 SCSI2 support (esp/fas236/fsc) */
+#define ESP_CONFIG3_TBMS 0x40 /* Three-byte msg's ok (esp/fas236/fsc) */
+#define ESP_CONFIG3_IMS 0x80 /* ID msg chk'ng (esp/fas236/fsc) */
+
+/* ESP config register 4 read-write, found only on fsc chips */
+#define ESP_CONFIG4_BBTE 0x01 /* Back-to-Back transfer enable */
+#define ESP_CONFIG4_TEST 0x02 /* Transfer counter test mode */
+#define ESP_CONFIG4_EAN 0x04 /* Enable Active Negotiation */
+
+/* ESP command register read-write */
+/* Group 1 commands: These may be sent at any point in time to the ESP
+ * chip. None of them can generate interrupts 'cept
+ * the "SCSI bus reset" command if you have not disabled
+ * SCSI reset interrupts in the config1 ESP register.
+ */
+#define ESP_CMD_NULL 0x00 /* Null command, ie. a nop */
+#define ESP_CMD_FLUSH 0x01 /* FIFO Flush */
+#define ESP_CMD_RC 0x02 /* Chip reset */
+#define ESP_CMD_RS 0x03 /* SCSI bus reset */
+
+/* Group 2 commands: ESP must be an initiator and connected to a target
+ * for these commands to work.
+ */
+#define ESP_CMD_TI 0x10 /* Transfer Information */
+#define ESP_CMD_ICCSEQ 0x11 /* Initiator cmd complete sequence */
+#define ESP_CMD_MOK 0x12 /* Message okie-dokie */
+#define ESP_CMD_TPAD 0x18 /* Transfer Pad */
+#define ESP_CMD_SATN 0x1a /* Set ATN */
+#define ESP_CMD_RATN 0x1b /* De-assert ATN */
+
+/* Group 3 commands: ESP must be in the MSGOUT or MSGIN state and be connected
+ * to a target as the initiator for these commands to work.
+ */
+#define ESP_CMD_SMSG 0x20 /* Send message */
+#define ESP_CMD_SSTAT 0x21 /* Send status */
+#define ESP_CMD_SDATA 0x22 /* Send data */
+#define ESP_CMD_DSEQ 0x23 /* Discontinue Sequence */
+#define ESP_CMD_TSEQ 0x24 /* Terminate Sequence */
+#define ESP_CMD_TCCSEQ 0x25 /* Target cmd cmplt sequence */
+#define ESP_CMD_DCNCT 0x27 /* Disconnect */
+#define ESP_CMD_RMSG 0x28 /* Receive Message */
+#define ESP_CMD_RCMD 0x29 /* Receive Command */
+#define ESP_CMD_RDATA 0x2a /* Receive Data */
+#define ESP_CMD_RCSEQ 0x2b /* Receive cmd sequence */
+
+/* Group 4 commands: The ESP must be in the disconnected state and must
+ * not be connected to any targets as initiator for
+ * these commands to work.
+ */
+#define ESP_CMD_RSEL 0x40 /* Reselect */
+#define ESP_CMD_SEL 0x41 /* Select w/o ATN */
+#define ESP_CMD_SELA 0x42 /* Select w/ATN */
+#define ESP_CMD_SELAS 0x43 /* Select w/ATN & STOP */
+#define ESP_CMD_ESEL 0x44 /* Enable selection */
+#define ESP_CMD_DSEL 0x45 /* Disable selections */
+#define ESP_CMD_SA3 0x46 /* Select w/ATN3 */
+#define ESP_CMD_RSEL3 0x47 /* Reselect3 */
+
+/* This bit enables the ESP's DMA */
+#define ESP_CMD_DMA 0x80 /* Do DMA? */
+
+/* ESP status register read-only */
+#define ESP_STAT_PIO 0x01 /* IO phase bit */
+#define ESP_STAT_PCD 0x02 /* CD phase bit */
+#define ESP_STAT_PMSG 0x04 /* MSG phase bit */
+#define ESP_STAT_PMASK 0x07 /* Mask of phase bits */
+#define ESP_STAT_TDONE 0x08 /* Transfer Completed */
+#define ESP_STAT_TCNT 0x10 /* Transfer Counter Is Zero */
+#define ESP_STAT_PERR 0x20 /* Parity error */
+#define ESP_STAT_SPAM 0x40 /* Real bad error */
+/* This indicates the 'interrupt pending' condition, it is a reserved
+ * bit on old revs of the ESP (ESP100, ESP100A, FAS100A).
+ */
+#define ESP_STAT_INTR 0x80 /* Interrupt */
+
+/* The status register can be masked with ESP_STAT_PMASK and compared
+ * with the following values to determine the current phase the ESP
+ * (at least thinks it) is in. For our purposes we also add our own
+ * software 'done' bit for our phase management engine.
+ */
+#define ESP_DOP (0) /* Data Out */
+#define ESP_DIP (ESP_STAT_PIO) /* Data In */
+#define ESP_CMDP (ESP_STAT_PCD) /* Command */
+#define ESP_STATP (ESP_STAT_PCD|ESP_STAT_PIO) /* Status */
+#define ESP_MOP (ESP_STAT_PMSG|ESP_STAT_PCD) /* Message Out */
+#define ESP_MIP (ESP_STAT_PMSG|ESP_STAT_PCD|ESP_STAT_PIO) /* Message In */
+
+/* ESP interrupt register read-only */
+#define ESP_INTR_S 0x01 /* Select w/o ATN */
+#define ESP_INTR_SATN 0x02 /* Select w/ATN */
+#define ESP_INTR_RSEL 0x04 /* Reselected */
+#define ESP_INTR_FDONE 0x08 /* Function done */
+#define ESP_INTR_BSERV 0x10 /* Bus service */
+#define ESP_INTR_DC 0x20 /* Disconnect */
+#define ESP_INTR_IC 0x40 /* Illegal command given */
+#define ESP_INTR_SR 0x80 /* SCSI bus reset detected */
+
+/* Interrupt status macros */
+#define ESP_SRESET_IRQ(esp) ((esp)->intreg & (ESP_INTR_SR))
+#define ESP_ILLCMD_IRQ(esp) ((esp)->intreg & (ESP_INTR_IC))
+#define ESP_SELECT_WITH_ATN_IRQ(esp) ((esp)->intreg & (ESP_INTR_SATN))
+#define ESP_SELECT_WITHOUT_ATN_IRQ(esp) ((esp)->intreg & (ESP_INTR_S))
+#define ESP_SELECTION_IRQ(esp) ((ESP_SELECT_WITH_ATN_IRQ(esp)) || \
+ (ESP_SELECT_WITHOUT_ATN_IRQ(esp)))
+#define ESP_RESELECTION_IRQ(esp) ((esp)->intreg & (ESP_INTR_RSEL))
+
+/* ESP sequence step register read-only */
+#define ESP_STEP_VBITS 0x07 /* Valid bits */
+#define ESP_STEP_ASEL 0x00 /* Selection&Arbitrate cmplt */
+#define ESP_STEP_SID 0x01 /* One msg byte sent */
+#define ESP_STEP_NCMD 0x02 /* Was not in command phase */
+#define ESP_STEP_PPC 0x03 /* Early phase chg caused cmnd
+ * bytes to be lost
+ */
+#define ESP_STEP_FINI4 0x04 /* Command was sent ok */
+
+/* Ho hum, some ESP's set the step register to this as well... */
+#define ESP_STEP_FINI5 0x05
+#define ESP_STEP_FINI6 0x06
+#define ESP_STEP_FINI7 0x07
+#define ESP_STEP_SOM 0x08 /* Synchronous Offset Max */
+
+/* ESP chip-test register read-write */
+#define ESP_TEST_TARG 0x01 /* Target test mode */
+#define ESP_TEST_INI 0x02 /* Initiator test mode */
+#define ESP_TEST_TS 0x04 /* Tristate test mode */
+
+/* ESP unique ID register read-only, found on fas236+fas100a+fsc only */
+#define ESP_UID_F100A 0x00 /* FAS100A */
+#define ESP_UID_F236 0x02 /* FAS236 */
+#define ESP_UID_FSC 0xa2 /* NCR53CF9x-2 */
+#define ESP_UID_REV 0x07 /* ESP revision */
+#define ESP_UID_FAM 0xf8 /* ESP family */
+
+/* ESP fifo flags register read-only */
+/* Note that the following implies a 16 byte FIFO on the ESP. */
+#define ESP_FF_FBYTES 0x1f /* Num bytes in FIFO */
+#define ESP_FF_ONOTZERO 0x20 /* offset ctr not zero (esp100,fsc) */
+#define ESP_FF_SSTEP 0xe0 /* Sequence step */
+
+/* ESP clock conversion factor register write-only */
+#define ESP_CCF_F0 0x00 /* 35.01MHz - 40MHz */
+#define ESP_CCF_NEVER 0x01 /* Set it to this and die */
+#define ESP_CCF_F2 0x02 /* 10MHz */
+#define ESP_CCF_F3 0x03 /* 10.01MHz - 15MHz */
+#define ESP_CCF_F4 0x04 /* 15.01MHz - 20MHz */
+#define ESP_CCF_F5 0x05 /* 20.01MHz - 25MHz */
+#define ESP_CCF_F6 0x06 /* 25.01MHz - 30MHz */
+#define ESP_CCF_F7 0x07 /* 30.01MHz - 35MHz */
+
+#define ESP_BUS_TIMEOUT 275 /* In milli-seconds */
+#define ESP_TIMEO_CONST 8192
+#define FSC_TIMEO_CONST 7668
+#define ESP_NEG_DEFP(mhz, cfact) \
+ ((ESP_BUS_TIMEOUT * ((mhz) / 1000)) / (8192 * (cfact)))
+#define FSC_NEG_DEFP(mhz, cfact) \
+ ((ESP_BUS_TIMEOUT * ((mhz) / 1000)) / (7668 * (cfact)))
+#define ESP_MHZ_TO_CYCLE(mhertz) ((1000000000) / ((mhertz) / 1000))
+#define ESP_TICK(ccf, cycle) ((7682 * (ccf) * (cycle) / 1000))
+
+
+/* UGLY, UGLY, UGLY! */
+extern int nesps, esps_in_use, esps_running;
+
+/* For our interrupt engine. */
+#define for_each_esp(esp) \
+ for((esp) = espchain; (esp); (esp) = (esp)->next)
+
+
+/* External functions */
+extern void esp_bootup_reset(struct NCR_ESP *esp, struct ESP_regs *eregs);
+extern struct NCR_ESP *esp_allocate(struct scsi_host_template *, void *, int);
+extern void esp_deallocate(struct NCR_ESP *);
+extern void esp_release(void);
+extern void esp_initialize(struct NCR_ESP *);
+extern irqreturn_t esp_intr(int, void *);
+extern const char *esp_info(struct Scsi_Host *);
+extern int esp_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+extern int esp_abort(Scsi_Cmnd *);
+extern int esp_reset(Scsi_Cmnd *);
+extern int esp_proc_info(struct Scsi_Host *shost, char *buffer, char **start, off_t offset, int length,
+ int inout);
+extern int esp_slave_alloc(struct scsi_device *);
+extern void esp_slave_destroy(struct scsi_device *);
+#endif /* !(NCR53C9X_H) */
diff --git a/trunk/drivers/scsi/aacraid/aachba.c b/trunk/drivers/scsi/aacraid/aachba.c
index bfd0e64964ac..d7235f42cf5f 100644
--- a/trunk/drivers/scsi/aacraid/aachba.c
+++ b/trunk/drivers/scsi/aacraid/aachba.c
@@ -859,31 +859,44 @@ static int setinqserial(struct aac_dev *dev, void *data, int cid)
le32_to_cpu(dev->adapter_info.serial[0]), cid);
}
-static inline void set_sense(struct sense_data *sense_data, u8 sense_key,
- u8 sense_code, u8 a_sense_code, u8 bit_pointer, u16 field_pointer)
+static void set_sense(u8 *sense_buf, u8 sense_key, u8 sense_code,
+ u8 a_sense_code, u8 incorrect_length,
+ u8 bit_pointer, u16 field_pointer,
+ u32 residue)
{
- u8 *sense_buf = (u8 *)sense_data;
- /* Sense data valid, err code 70h */
- sense_buf[0] = 0x70; /* No info field */
+ sense_buf[0] = 0xF0; /* Sense data valid, err code 70h (current error) */
sense_buf[1] = 0; /* Segment number, always zero */
- sense_buf[2] = sense_key; /* Sense key */
+ if (incorrect_length) {
+ sense_buf[2] = sense_key | 0x20;/* Set ILI bit | sense key */
+ sense_buf[3] = BYTE3(residue);
+ sense_buf[4] = BYTE2(residue);
+ sense_buf[5] = BYTE1(residue);
+ sense_buf[6] = BYTE0(residue);
+ } else
+ sense_buf[2] = sense_key; /* Sense key */
+
+ if (sense_key == ILLEGAL_REQUEST)
+ sense_buf[7] = 10; /* Additional sense length */
+ else
+ sense_buf[7] = 6; /* Additional sense length */
sense_buf[12] = sense_code; /* Additional sense code */
sense_buf[13] = a_sense_code; /* Additional sense code qualifier */
-
if (sense_key == ILLEGAL_REQUEST) {
- sense_buf[7] = 10; /* Additional sense length */
+ sense_buf[15] = 0;
- sense_buf[15] = bit_pointer;
+ if (sense_code == SENCODE_INVALID_PARAM_FIELD)
+ sense_buf[15] = 0x80;/* Std sense key specific field */
/* Illegal parameter is in the parameter block */
+
if (sense_code == SENCODE_INVALID_CDB_FIELD)
- sense_buf[15] |= 0xc0;/* Std sense key specific field */
+ sense_buf[15] = 0xc0;/* Std sense key specific field */
/* Illegal parameter is in the CDB block */
+ sense_buf[15] |= bit_pointer;
sense_buf[16] = field_pointer >> 8; /* MSB */
sense_buf[17] = field_pointer; /* LSB */
- } else
- sense_buf[7] = 6; /* Additional sense length */
+ }
}
static int aac_bounds_32(struct aac_dev * dev, struct scsi_cmnd * cmd, u64 lba)
@@ -893,9 +906,11 @@ static int aac_bounds_32(struct aac_dev * dev, struct scsi_cmnd * cmd, u64 lba)
dprintk((KERN_DEBUG "aacraid: Illegal lba\n"));
cmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
SAM_STAT_CHECK_CONDITION;
- set_sense(&dev->fsa_dev[cid].sense_data,
- HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE,
- ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0);
+ set_sense((u8 *) &dev->fsa_dev[cid].sense_data,
+ HARDWARE_ERROR,
+ SENCODE_INTERNAL_TARGET_FAILURE,
+ ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0,
+ 0, 0);
memcpy(cmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
SCSI_SENSE_BUFFERSIZE));
@@ -1505,9 +1520,11 @@ static void io_callback(void *context, struct fib * fibptr)
le32_to_cpu(readreply->status));
#endif
scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION;
- set_sense(&dev->fsa_dev[cid].sense_data,
- HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE,
- ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0);
+ set_sense((u8 *) &dev->fsa_dev[cid].sense_data,
+ HARDWARE_ERROR,
+ SENCODE_INTERNAL_TARGET_FAILURE,
+ ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0,
+ 0, 0);
memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
SCSI_SENSE_BUFFERSIZE));
@@ -1716,9 +1733,11 @@ static void synchronize_callback(void *context, struct fib *fibptr)
le32_to_cpu(synchronizereply->status));
cmd->result = DID_OK << 16 |
COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION;
- set_sense(&dev->fsa_dev[cid].sense_data,
- HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE,
- ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0);
+ set_sense((u8 *)&dev->fsa_dev[cid].sense_data,
+ HARDWARE_ERROR,
+ SENCODE_INTERNAL_TARGET_FAILURE,
+ ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0,
+ 0, 0);
memcpy(cmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
SCSI_SENSE_BUFFERSIZE));
@@ -1926,9 +1945,10 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
{
dprintk((KERN_WARNING "Only INQUIRY & TUR command supported for controller, rcvd = 0x%x.\n", scsicmd->cmnd[0]));
scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION;
- set_sense(&dev->fsa_dev[cid].sense_data,
- ILLEGAL_REQUEST, SENCODE_INVALID_COMMAND,
- ASENCODE_INVALID_COMMAND, 0, 0);
+ set_sense((u8 *) &dev->fsa_dev[cid].sense_data,
+ ILLEGAL_REQUEST,
+ SENCODE_INVALID_COMMAND,
+ ASENCODE_INVALID_COMMAND, 0, 0, 0, 0);
memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
SCSI_SENSE_BUFFERSIZE));
@@ -1975,9 +1995,10 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
scsicmd->result = DID_OK << 16 |
COMMAND_COMPLETE << 8 |
SAM_STAT_CHECK_CONDITION;
- set_sense(&dev->fsa_dev[cid].sense_data,
- ILLEGAL_REQUEST, SENCODE_INVALID_CDB_FIELD,
- ASENCODE_NO_SENSE, 7, 2);
+ set_sense((u8 *) &dev->fsa_dev[cid].sense_data,
+ ILLEGAL_REQUEST,
+ SENCODE_INVALID_CDB_FIELD,
+ ASENCODE_NO_SENSE, 0, 7, 2, 0);
memcpy(scsicmd->sense_buffer,
&dev->fsa_dev[cid].sense_data,
min_t(size_t,
@@ -2233,9 +2254,9 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
*/
dprintk((KERN_WARNING "Unhandled SCSI Command: 0x%x.\n", scsicmd->cmnd[0]));
scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION;
- set_sense(&dev->fsa_dev[cid].sense_data,
- ILLEGAL_REQUEST, SENCODE_INVALID_COMMAND,
- ASENCODE_INVALID_COMMAND, 0, 0);
+ set_sense((u8 *) &dev->fsa_dev[cid].sense_data,
+ ILLEGAL_REQUEST, SENCODE_INVALID_COMMAND,
+ ASENCODE_INVALID_COMMAND, 0, 0, 0, 0);
memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
min_t(size_t,
sizeof(dev->fsa_dev[cid].sense_data),
diff --git a/trunk/drivers/scsi/aacraid/commctrl.c b/trunk/drivers/scsi/aacraid/commctrl.c
index abef05146d75..f8afa358b6b6 100644
--- a/trunk/drivers/scsi/aacraid/commctrl.c
+++ b/trunk/drivers/scsi/aacraid/commctrl.c
@@ -243,7 +243,6 @@ static int next_getadapter_fib(struct aac_dev * dev, void __user *arg)
* Search the list of AdapterFibContext addresses on the adapter
* to be sure this is a valid address
*/
- spin_lock_irqsave(&dev->fib_lock, flags);
entry = dev->fib_list.next;
fibctx = NULL;
@@ -252,25 +251,24 @@ static int next_getadapter_fib(struct aac_dev * dev, void __user *arg)
/*
* Extract the AdapterFibContext from the Input parameters.
*/
- if (fibctx->unique == f.fibctx) { /* We found a winner */
+ if (fibctx->unique == f.fibctx) { /* We found a winner */
break;
}
entry = entry->next;
fibctx = NULL;
}
if (!fibctx) {
- spin_unlock_irqrestore(&dev->fib_lock, flags);
dprintk ((KERN_INFO "Fib Context not found\n"));
return -EINVAL;
}
if((fibctx->type != FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT) ||
(fibctx->size != sizeof(struct aac_fib_context))) {
- spin_unlock_irqrestore(&dev->fib_lock, flags);
dprintk ((KERN_INFO "Fib Context corrupt?\n"));
return -EINVAL;
}
status = 0;
+ spin_lock_irqsave(&dev->fib_lock, flags);
/*
* If there are no fibs to send back, then either wait or return
* -EAGAIN
@@ -416,8 +414,8 @@ static int close_getadapter_fib(struct aac_dev * dev, void __user *arg)
* @arg: ioctl arguments
*
* This routine returns the driver version.
- * Under Linux, there have been no version incompatibilities, so this is
- * simple!
+ * Under Linux, there have been no version incompatibilities, so this is
+ * simple!
*/
static int check_revision(struct aac_dev *dev, void __user *arg)
@@ -465,7 +463,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
u32 data_dir;
void __user *sg_user[32];
void *sg_list[32];
- u32 sg_indx = 0;
+ u32 sg_indx = 0;
u32 byte_count = 0;
u32 actual_fibsize64, actual_fibsize = 0;
int i;
@@ -519,11 +517,11 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
// Fix up srb for endian and force some values
srbcmd->function = cpu_to_le32(SRBF_ExecuteScsi); // Force this
- srbcmd->channel = cpu_to_le32(user_srbcmd->channel);
+ srbcmd->channel = cpu_to_le32(user_srbcmd->channel);
srbcmd->id = cpu_to_le32(user_srbcmd->id);
- srbcmd->lun = cpu_to_le32(user_srbcmd->lun);
- srbcmd->timeout = cpu_to_le32(user_srbcmd->timeout);
- srbcmd->flags = cpu_to_le32(flags);
+ srbcmd->lun = cpu_to_le32(user_srbcmd->lun);
+ srbcmd->timeout = cpu_to_le32(user_srbcmd->timeout);
+ srbcmd->flags = cpu_to_le32(flags);
srbcmd->retry_limit = 0; // Obsolete parameter
srbcmd->cdb_size = cpu_to_le32(user_srbcmd->cdb_size);
memcpy(srbcmd->cdb, user_srbcmd->cdb, sizeof(srbcmd->cdb));
@@ -788,9 +786,9 @@ static int aac_get_pci_info(struct aac_dev* dev, void __user *arg)
pci_info.bus = dev->pdev->bus->number;
pci_info.slot = PCI_SLOT(dev->pdev->devfn);
- if (copy_to_user(arg, &pci_info, sizeof(struct aac_pci_info))) {
- dprintk((KERN_DEBUG "aacraid: Could not copy pci info\n"));
- return -EFAULT;
+ if (copy_to_user(arg, &pci_info, sizeof(struct aac_pci_info))) {
+ dprintk((KERN_DEBUG "aacraid: Could not copy pci info\n"));
+ return -EFAULT;
}
return 0;
}
diff --git a/trunk/drivers/scsi/aacraid/linit.c b/trunk/drivers/scsi/aacraid/linit.c
index e80d2a0c46af..fb0886140dd7 100644
--- a/trunk/drivers/scsi/aacraid/linit.c
+++ b/trunk/drivers/scsi/aacraid/linit.c
@@ -1130,29 +1130,31 @@ static int __devinit aac_probe_one(struct pci_dev *pdev,
if (error < 0)
goto out_deinit;
+ if (!(aac->adapter_info.options & AAC_OPT_NEW_COMM)) {
+ error = pci_set_dma_max_seg_size(pdev, 65536);
+ if (error)
+ goto out_deinit;
+ }
+
/*
* Lets override negotiations and drop the maximum SG limit to 34
*/
if ((aac_drivers[index].quirks & AAC_QUIRK_34SG) &&
- (shost->sg_tablesize > 34)) {
- shost->sg_tablesize = 34;
- shost->max_sectors = (shost->sg_tablesize * 8) + 112;
+ (aac->scsi_host_ptr->sg_tablesize > 34)) {
+ aac->scsi_host_ptr->sg_tablesize = 34;
+ aac->scsi_host_ptr->max_sectors
+ = (aac->scsi_host_ptr->sg_tablesize * 8) + 112;
}
if ((aac_drivers[index].quirks & AAC_QUIRK_17SG) &&
- (shost->sg_tablesize > 17)) {
- shost->sg_tablesize = 17;
- shost->max_sectors = (shost->sg_tablesize * 8) + 112;
+ (aac->scsi_host_ptr->sg_tablesize > 17)) {
+ aac->scsi_host_ptr->sg_tablesize = 17;
+ aac->scsi_host_ptr->max_sectors
+ = (aac->scsi_host_ptr->sg_tablesize * 8) + 112;
}
- error = pci_set_dma_max_seg_size(pdev,
- (aac->adapter_info.options & AAC_OPT_NEW_COMM) ?
- (shost->max_sectors << 9) : 65536);
- if (error)
- goto out_deinit;
-
/*
- * Firmware printf works only with older firmware.
+ * Firware printf works only with older firmware.
*/
if (aac_drivers[index].quirks & AAC_QUIRK_34SG)
aac->printf_enabled = 1;
diff --git a/trunk/drivers/scsi/advansys.c b/trunk/drivers/scsi/advansys.c
index ccef891d642f..374ed025dc5a 100644
--- a/trunk/drivers/scsi/advansys.c
+++ b/trunk/drivers/scsi/advansys.c
@@ -12261,7 +12261,7 @@ static ushort __devinit AdvReadEEPWord(AdvPortAddr iop_base, int eep_word_addr)
/*
* Write the EEPROM from 'cfg_buf'.
*/
-static void __devinit
+void __devinit
AdvSet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
{
ushort *wbuf;
@@ -12328,7 +12328,7 @@ AdvSet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
/*
* Write the EEPROM from 'cfg_buf'.
*/
-static void __devinit
+void __devinit
AdvSet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf)
{
ushort *wbuf;
@@ -12395,7 +12395,7 @@ AdvSet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf)
/*
* Write the EEPROM from 'cfg_buf'.
*/
-static void __devinit
+void __devinit
AdvSet38C1600EEPConfig(AdvPortAddr iop_base, ADVEEP_38C1600_CONFIG *cfg_buf)
{
ushort *wbuf;
diff --git a/trunk/drivers/scsi/arcmsr/arcmsr.h b/trunk/drivers/scsi/arcmsr/arcmsr.h
index 57786502e3ec..a67e29f83ae5 100644
--- a/trunk/drivers/scsi/arcmsr/arcmsr.h
+++ b/trunk/drivers/scsi/arcmsr/arcmsr.h
@@ -48,7 +48,7 @@ struct class_device_attribute;
/*The limit of outstanding scsi command that firmware can handle*/
#define ARCMSR_MAX_OUTSTANDING_CMD 256
#define ARCMSR_MAX_FREECCB_NUM 320
-#define ARCMSR_DRIVER_VERSION "Driver Version 1.20.00.15 2007/12/24"
+#define ARCMSR_DRIVER_VERSION "Driver Version 1.20.00.15 2007/08/30"
#define ARCMSR_SCSI_INITIATOR_ID 255
#define ARCMSR_MAX_XFER_SECTORS 512
#define ARCMSR_MAX_XFER_SECTORS_B 4096
@@ -248,7 +248,6 @@ struct FIRMWARE_INFO
#define ARCMSR_MESSAGE_START_BGRB 0x00060008
#define ARCMSR_MESSAGE_START_DRIVER_MODE 0x000E0008
#define ARCMSR_MESSAGE_SET_POST_WINDOW 0x000F0008
-#define ARCMSR_MESSAGE_ACTIVE_EOI_MODE 0x00100008
/* ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK */
#define ARCMSR_MESSAGE_FIRMWARE_OK 0x80000000
/* ioctl transfer */
@@ -257,7 +256,6 @@ struct FIRMWARE_INFO
#define ARCMSR_DRV2IOP_DATA_READ_OK 0x00000002
#define ARCMSR_DRV2IOP_CDB_POSTED 0x00000004
#define ARCMSR_DRV2IOP_MESSAGE_CMD_POSTED 0x00000008
-#define ARCMSR_DRV2IOP_END_OF_INTERRUPT 0x00000010
/* data tunnel buffer between user space program and its firmware */
/* user space data to iop 128bytes */
diff --git a/trunk/drivers/scsi/arcmsr/arcmsr_hba.c b/trunk/drivers/scsi/arcmsr/arcmsr_hba.c
index 4f9ff32cfed0..f4a202e8df26 100644
--- a/trunk/drivers/scsi/arcmsr/arcmsr_hba.c
+++ b/trunk/drivers/scsi/arcmsr/arcmsr_hba.c
@@ -315,6 +315,9 @@ static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb)
(0x20 - ((unsigned long)dma_coherent_handle & 0x1F));
}
+ reg = (struct MessageUnit_B *)(dma_coherent +
+ ARCMSR_MAX_FREECCB_NUM * sizeof(struct CommandControlBlock));
+
dma_addr = dma_coherent_handle;
ccb_tmp = (struct CommandControlBlock *)dma_coherent;
for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
@@ -368,8 +371,8 @@ static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb)
out:
dma_free_coherent(&acb->pdev->dev,
- (ARCMSR_MAX_FREECCB_NUM * sizeof(struct CommandControlBlock) + 0x20 +
- sizeof(struct MessageUnit_B)), acb->dma_coherent, acb->dma_coherent_handle);
+ ARCMSR_MAX_FREECCB_NUM * sizeof(struct CommandControlBlock) + 0x20,
+ acb->dma_coherent, acb->dma_coherent_handle);
return -ENOMEM;
}
@@ -506,7 +509,6 @@ static uint8_t arcmsr_hbb_wait_msgint_ready(struct AdapterControlBlock *acb)
& ARCMSR_IOP2DRV_MESSAGE_CMD_DONE) {
writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN
, reg->iop2drv_doorbell_reg);
- writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell_reg);
return 0x00;
}
msleep(10);
@@ -746,7 +748,6 @@ static void arcmsr_drain_donequeue(struct AdapterControlBlock *acb, uint32_t fla
, ccb->startdone
, atomic_read(&acb->ccboutstandingcount));
}
- else
arcmsr_report_ccb_state(acb, ccb, flag_ccb);
}
@@ -885,7 +886,7 @@ static void arcmsr_enable_outbound_ints(struct AdapterControlBlock *acb, \
}
}
-static int arcmsr_build_ccb(struct AdapterControlBlock *acb,
+static void arcmsr_build_ccb(struct AdapterControlBlock *acb,
struct CommandControlBlock *ccb, struct scsi_cmnd *pcmd)
{
struct ARCMSR_CDB *arcmsr_cdb = (struct ARCMSR_CDB *)&ccb->arcmsr_cdb;
@@ -905,8 +906,6 @@ static int arcmsr_build_ccb(struct AdapterControlBlock *acb,
memcpy(arcmsr_cdb->Cdb, pcmd->cmnd, pcmd->cmd_len);
nseg = scsi_dma_map(pcmd);
- if (nseg > ARCMSR_MAX_SG_ENTRIES)
- return FAILED;
BUG_ON(nseg < 0);
if (nseg) {
@@ -947,7 +946,6 @@ static int arcmsr_build_ccb(struct AdapterControlBlock *acb,
arcmsr_cdb->Flags |= ARCMSR_CDB_FLAG_WRITE;
ccb->ccb_flags |= CCB_FLAG_WRITE;
}
- return SUCCESS;
}
static void arcmsr_post_ccb(struct AdapterControlBlock *acb, struct CommandControlBlock *ccb)
@@ -1038,22 +1036,18 @@ static void arcmsr_free_ccb_pool(struct AdapterControlBlock *acb)
switch (acb->adapter_type) {
case ACB_ADAPTER_TYPE_A: {
iounmap(acb->pmuA);
- dma_free_coherent(&acb->pdev->dev,
- ARCMSR_MAX_FREECCB_NUM * sizeof (struct CommandControlBlock) + 0x20,
- acb->dma_coherent,
- acb->dma_coherent_handle);
break;
}
case ACB_ADAPTER_TYPE_B: {
struct MessageUnit_B *reg = acb->pmuB;
iounmap(reg->drv2iop_doorbell_reg - ARCMSR_DRV2IOP_DOORBELL);
iounmap(reg->ioctl_wbuffer_reg - ARCMSR_IOCTL_WBUFFER);
- dma_free_coherent(&acb->pdev->dev,
- (ARCMSR_MAX_FREECCB_NUM * sizeof(struct CommandControlBlock) + 0x20 +
- sizeof(struct MessageUnit_B)), acb->dma_coherent, acb->dma_coherent_handle);
}
}
-
+ dma_free_coherent(&acb->pdev->dev,
+ ARCMSR_MAX_FREECCB_NUM * sizeof (struct CommandControlBlock) + 0x20,
+ acb->dma_coherent,
+ acb->dma_coherent_handle);
}
void arcmsr_iop_message_read(struct AdapterControlBlock *acb)
@@ -1279,9 +1273,7 @@ static int arcmsr_handle_hbb_isr(struct AdapterControlBlock *acb)
return 1;
writel(~outbound_doorbell, reg->iop2drv_doorbell_reg);
- /*in case the last action of doorbell interrupt clearance is cached, this action can push HW to write down the clear bit*/
- readl(reg->iop2drv_doorbell_reg);
- writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell_reg);
+
if (outbound_doorbell & ARCMSR_IOP2DRV_DATA_WRITE_OK) {
arcmsr_iop2drv_data_wrote_handle(acb);
}
@@ -1388,13 +1380,12 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, \
case ARCMSR_MESSAGE_READ_RQBUFFER: {
unsigned long *ver_addr;
+ dma_addr_t buf_handle;
uint8_t *pQbuffer, *ptmpQbuffer;
int32_t allxfer_len = 0;
- void *tmp;
- tmp = kmalloc(1032, GFP_KERNEL|GFP_DMA);
- ver_addr = (unsigned long *)tmp;
- if (!tmp) {
+ ver_addr = pci_alloc_consistent(acb->pdev, 1032, &buf_handle);
+ if (!ver_addr) {
retvalue = ARCMSR_MESSAGE_FAIL;
goto message_out;
}
@@ -1430,19 +1421,18 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, \
memcpy(pcmdmessagefld->messagedatabuffer, (uint8_t *)ver_addr, allxfer_len);
pcmdmessagefld->cmdmessage.Length = allxfer_len;
pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK;
- kfree(tmp);
+ pci_free_consistent(acb->pdev, 1032, ver_addr, buf_handle);
}
break;
case ARCMSR_MESSAGE_WRITE_WQBUFFER: {
unsigned long *ver_addr;
+ dma_addr_t buf_handle;
int32_t my_empty_len, user_len, wqbuf_firstindex, wqbuf_lastindex;
uint8_t *pQbuffer, *ptmpuserbuffer;
- void *tmp;
- tmp = kmalloc(1032, GFP_KERNEL|GFP_DMA);
- ver_addr = (unsigned long *)tmp;
- if (!tmp) {
+ ver_addr = pci_alloc_consistent(acb->pdev, 1032, &buf_handle);
+ if (!ver_addr) {
retvalue = ARCMSR_MESSAGE_FAIL;
goto message_out;
}
@@ -1492,7 +1482,7 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, \
retvalue = ARCMSR_MESSAGE_FAIL;
}
}
- kfree(tmp);
+ pci_free_consistent(acb->pdev, 1032, ver_addr, buf_handle);
}
break;
@@ -1692,11 +1682,8 @@ static int arcmsr_queue_command(struct scsi_cmnd *cmd,
ccb = arcmsr_get_freeccb(acb);
if (!ccb)
return SCSI_MLQUEUE_HOST_BUSY;
- if ( arcmsr_build_ccb( acb, ccb, cmd ) == FAILED ) {
- cmd->result = (DID_ERROR << 16) | (RESERVATION_CONFLICT << 1);
- cmd->scsi_done(cmd);
- return 0;
- }
+
+ arcmsr_build_ccb(acb, ccb, cmd);
arcmsr_post_ccb(acb, ccb);
return 0;
}
@@ -1857,7 +1844,7 @@ static void arcmsr_polling_hba_ccbdone(struct AdapterControlBlock *acb,
}
}
-static void arcmsr_polling_hbb_ccbdone(struct AdapterControlBlock *acb,
+static void arcmsr_polling_hbb_ccbdone(struct AdapterControlBlock *acb, \
struct CommandControlBlock *poll_ccb)
{
struct MessageUnit_B *reg = acb->pmuB;
@@ -1891,7 +1878,7 @@ static void arcmsr_polling_hbb_ccbdone(struct AdapterControlBlock *acb,
(acb->vir2phy_offset + (flag_ccb << 5));/*frame must be 32 bytes aligned*/
poll_ccb_done = (ccb == poll_ccb) ? 1:0;
if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) {
- if ((ccb->startdone == ARCMSR_CCB_ABORTED) || (ccb == poll_ccb)) {
+ if (ccb->startdone == ARCMSR_CCB_ABORTED) {
printk(KERN_NOTICE "arcmsr%d: \
scsi id = %d lun = %d ccb = '0x%p' poll command abort successfully \n"
,acb->host->host_no
@@ -1914,7 +1901,7 @@ static void arcmsr_polling_hbb_ccbdone(struct AdapterControlBlock *acb,
} /*drain reply FIFO*/
}
-static void arcmsr_polling_ccbdone(struct AdapterControlBlock *acb,
+static void arcmsr_polling_ccbdone(struct AdapterControlBlock *acb, \
struct CommandControlBlock *poll_ccb)
{
switch (acb->adapter_type) {
@@ -2039,7 +2026,6 @@ static void arcmsr_wait_firmware_ready(struct AdapterControlBlock *acb)
do {
firmware_state = readl(reg->iop2drv_doorbell_reg);
} while ((firmware_state & ARCMSR_MESSAGE_FIRMWARE_OK) == 0);
- writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell_reg);
}
break;
}
@@ -2104,39 +2090,19 @@ static void arcmsr_clear_doorbell_queue_buffer(struct AdapterControlBlock *acb)
}
}
-static void arcmsr_enable_eoi_mode(struct AdapterControlBlock *acb)
-{
- switch (acb->adapter_type) {
- case ACB_ADAPTER_TYPE_A:
- return;
- case ACB_ADAPTER_TYPE_B:
- {
- struct MessageUnit_B *reg = acb->pmuB;
- writel(ARCMSR_MESSAGE_ACTIVE_EOI_MODE, reg->drv2iop_doorbell_reg);
- if(arcmsr_hbb_wait_msgint_ready(acb)) {
- printk(KERN_NOTICE "ARCMSR IOP enables EOI_MODE TIMEOUT");
- return;
- }
- }
- break;
- }
- return;
-}
-
static void arcmsr_iop_init(struct AdapterControlBlock *acb)
{
uint32_t intmask_org;
- /* disable all outbound interrupt */
- intmask_org = arcmsr_disable_outbound_ints(acb);
arcmsr_wait_firmware_ready(acb);
arcmsr_iop_confirm(acb);
+ /* disable all outbound interrupt */
+ intmask_org = arcmsr_disable_outbound_ints(acb);
arcmsr_get_firmware_spec(acb);
/*start background rebuild*/
arcmsr_start_adapter_bgrb(acb);
/* empty doorbell Qbuffer if door bell ringed */
arcmsr_clear_doorbell_queue_buffer(acb);
- arcmsr_enable_eoi_mode(acb);
/* enable outbound Post Queue,outbound doorbell Interrupt */
arcmsr_enable_outbound_ints(acb, intmask_org);
acb->acb_flags |= ACB_F_IOP_INITED;
@@ -2309,7 +2275,6 @@ static pci_ers_result_t arcmsr_pci_slot_reset(struct pci_dev *pdev)
arcmsr_start_adapter_bgrb(acb);
/* empty doorbell Qbuffer if door bell ringed */
arcmsr_clear_doorbell_queue_buffer(acb);
- arcmsr_enable_eoi_mode(acb);
/* enable outbound Post Queue,outbound doorbell Interrupt */
arcmsr_enable_outbound_ints(acb, intmask_org);
acb->acb_flags |= ACB_F_IOP_INITED;
diff --git a/trunk/drivers/scsi/arm/acornscsi.c b/trunk/drivers/scsi/arm/acornscsi.c
index 3bedf2466bd1..eceacf6d49ea 100644
--- a/trunk/drivers/scsi/arm/acornscsi.c
+++ b/trunk/drivers/scsi/arm/acornscsi.c
@@ -1790,7 +1790,7 @@ int acornscsi_starttransfer(AS_Host *host)
return 0;
}
- residual = scsi_bufflen(host->SCpnt) - host->scsi.SCp.scsi_xferred;
+ residual = host->SCpnt->request_bufflen - host->scsi.SCp.scsi_xferred;
sbic_arm_write(host->scsi.io_port, SBIC_SYNCHTRANSFER, host->device[host->SCpnt->device->id].sync_xfer);
sbic_arm_writenext(host->scsi.io_port, residual >> 16);
@@ -2270,7 +2270,7 @@ intr_ret_t acornscsi_sbicintr(AS_Host *host, int in_irq)
case 0x4b: /* -> PHASE_STATUSIN */
case 0x8b: /* -> PHASE_STATUSIN */
/* DATA IN -> STATUS */
- host->scsi.SCp.scsi_xferred = scsi_bufflen(host->SCpnt) -
+ host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen -
acornscsi_sbic_xfcount(host);
acornscsi_dma_stop(host);
acornscsi_readstatusbyte(host);
@@ -2281,7 +2281,7 @@ intr_ret_t acornscsi_sbicintr(AS_Host *host, int in_irq)
case 0x4e: /* -> PHASE_MSGOUT */
case 0x8e: /* -> PHASE_MSGOUT */
/* DATA IN -> MESSAGE OUT */
- host->scsi.SCp.scsi_xferred = scsi_bufflen(host->SCpnt) -
+ host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen -
acornscsi_sbic_xfcount(host);
acornscsi_dma_stop(host);
acornscsi_sendmessage(host);
@@ -2291,7 +2291,7 @@ intr_ret_t acornscsi_sbicintr(AS_Host *host, int in_irq)
case 0x4f: /* message in */
case 0x8f: /* message in */
/* DATA IN -> MESSAGE IN */
- host->scsi.SCp.scsi_xferred = scsi_bufflen(host->SCpnt) -
+ host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen -
acornscsi_sbic_xfcount(host);
acornscsi_dma_stop(host);
acornscsi_message(host); /* -> PHASE_MSGIN, PHASE_DISCONNECT */
@@ -2319,7 +2319,7 @@ intr_ret_t acornscsi_sbicintr(AS_Host *host, int in_irq)
case 0x4b: /* -> PHASE_STATUSIN */
case 0x8b: /* -> PHASE_STATUSIN */
/* DATA OUT -> STATUS */
- host->scsi.SCp.scsi_xferred = scsi_bufflen(host->SCpnt) -
+ host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen -
acornscsi_sbic_xfcount(host);
acornscsi_dma_stop(host);
acornscsi_dma_adjust(host);
@@ -2331,7 +2331,7 @@ intr_ret_t acornscsi_sbicintr(AS_Host *host, int in_irq)
case 0x4e: /* -> PHASE_MSGOUT */
case 0x8e: /* -> PHASE_MSGOUT */
/* DATA OUT -> MESSAGE OUT */
- host->scsi.SCp.scsi_xferred = scsi_bufflen(host->SCpnt) -
+ host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen -
acornscsi_sbic_xfcount(host);
acornscsi_dma_stop(host);
acornscsi_dma_adjust(host);
@@ -2342,7 +2342,7 @@ intr_ret_t acornscsi_sbicintr(AS_Host *host, int in_irq)
case 0x4f: /* message in */
case 0x8f: /* message in */
/* DATA OUT -> MESSAGE IN */
- host->scsi.SCp.scsi_xferred = scsi_bufflen(host->SCpnt) -
+ host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen -
acornscsi_sbic_xfcount(host);
acornscsi_dma_stop(host);
acornscsi_dma_adjust(host);
diff --git a/trunk/drivers/scsi/arm/scsi.h b/trunk/drivers/scsi/arm/scsi.h
index 138a521ba1a8..bb6550e31926 100644
--- a/trunk/drivers/scsi/arm/scsi.h
+++ b/trunk/drivers/scsi/arm/scsi.h
@@ -18,32 +18,17 @@
* The scatter-gather list handling. This contains all
* the yucky stuff that needs to be fixed properly.
*/
-
-/*
- * copy_SCp_to_sg() Assumes contiguous allocation at @sg of at-most @max
- * entries of uninitialized memory. SCp is from scsi-ml and has a valid
- * (possibly chained) sg-list
- */
static inline int copy_SCp_to_sg(struct scatterlist *sg, struct scsi_pointer *SCp, int max)
{
int bufs = SCp->buffers_residual;
- /* FIXME: It should be easy for drivers to loop on copy_SCp_to_sg().
- * and to remove this BUG_ON. Use min() in-its-place
- */
BUG_ON(bufs + 1 > max);
sg_set_buf(sg, SCp->ptr, SCp->this_residual);
- if (bufs) {
- struct scatterlist *src_sg;
- unsigned i;
-
- for_each_sg(sg_next(SCp->buffer), src_sg, bufs, i)
- *(++sg) = *src_sg;
- sg_mark_end(sg);
- }
-
+ if (bufs)
+ memcpy(sg + 1, SCp->buffer + 1,
+ sizeof(struct scatterlist) * bufs);
return bufs + 1;
}
@@ -51,7 +36,7 @@ static inline int next_SCp(struct scsi_pointer *SCp)
{
int ret = SCp->buffers_residual;
if (ret) {
- SCp->buffer = sg_next(SCp->buffer);
+ SCp->buffer++;
SCp->buffers_residual--;
SCp->ptr = sg_virt(SCp->buffer);
SCp->this_residual = SCp->buffer->length;
@@ -83,46 +68,46 @@ static inline void init_SCp(struct scsi_cmnd *SCpnt)
{
memset(&SCpnt->SCp, 0, sizeof(struct scsi_pointer));
- if (scsi_bufflen(SCpnt)) {
+ if (SCpnt->use_sg) {
unsigned long len = 0;
+ int buf;
- SCpnt->SCp.buffer = scsi_sglist(SCpnt);
- SCpnt->SCp.buffers_residual = scsi_sg_count(SCpnt) - 1;
+ SCpnt->SCp.buffer = (struct scatterlist *) SCpnt->request_buffer;
+ SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1;
SCpnt->SCp.ptr = sg_virt(SCpnt->SCp.buffer);
SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length;
- SCpnt->SCp.phase = scsi_bufflen(SCpnt);
+ SCpnt->SCp.phase = SCpnt->request_bufflen;
#ifdef BELT_AND_BRACES
- { /*
- * Calculate correct buffer length. Some commands
- * come in with the wrong scsi_bufflen.
- */
- struct scatterlist *sg;
- unsigned i, sg_count = scsi_sg_count(SCpnt);
-
- scsi_for_each_sg(SCpnt, sg, sg_count, i)
- len += sg->length;
-
- if (scsi_bufflen(SCpnt) != len) {
- printk(KERN_WARNING
- "scsi%d.%c: bad request buffer "
- "length %d, should be %ld\n",
- SCpnt->device->host->host_no,
- '0' + SCpnt->device->id,
- scsi_bufflen(SCpnt), len);
- /*
- * FIXME: Totaly naive fixup. We should abort
- * with error
- */
- SCpnt->SCp.phase =
- min_t(unsigned long, len,
- scsi_bufflen(SCpnt));
- }
- }
+ /*
+ * 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", SCpnt->device->host->host_no,
+ '0' + SCpnt->device->id, SCpnt->request_bufflen, len);
+ SCpnt->request_bufflen = len;
#endif
} else {
+ SCpnt->SCp.ptr = (unsigned char *)SCpnt->request_buffer;
+ SCpnt->SCp.this_residual = SCpnt->request_bufflen;
+ SCpnt->SCp.phase = 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 //def BELT_AND_BRACES
+ printk(KERN_WARNING "scsi%d.%c: zero length buffer passed for "
+ "command ", SCpnt->host->host_no, '0' + SCpnt->target);
+ __scsi_print_command(SCpnt->cmnd);
+#endif
SCpnt->SCp.ptr = NULL;
- SCpnt->SCp.this_residual = 0;
- SCpnt->SCp.phase = 0;
}
}
diff --git a/trunk/drivers/scsi/blz1230.c b/trunk/drivers/scsi/blz1230.c
new file mode 100644
index 000000000000..23f7c24ab809
--- /dev/null
+++ b/trunk/drivers/scsi/blz1230.c
@@ -0,0 +1,353 @@
+/* blz1230.c: Driver for Blizzard 1230 SCSI IV Controller.
+ *
+ * Copyright (C) 1996 Jesper Skov (jskov@cygnus.co.uk)
+ *
+ * This driver is based on the CyberStorm driver, hence the occasional
+ * reference to CyberStorm.
+ */
+
+/* TODO:
+ *
+ * 1) Figure out how to make a cleaner merge with the sparc driver with regard
+ * to the caches and the Sparc MMU mapping.
+ * 2) Make as few routines required outside the generic driver. A lot of the
+ * routines in this file used to be inline!
+ */
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "scsi.h"
+#include
+#include "NCR53C9x.h"
+
+#include
+#include
+#include
+#include
+
+#include
+
+#define MKIV 1
+
+/* The controller registers can be found in the Z2 config area at these
+ * offsets:
+ */
+#define BLZ1230_ESP_ADDR 0x8000
+#define BLZ1230_DMA_ADDR 0x10000
+#define BLZ1230II_ESP_ADDR 0x10000
+#define BLZ1230II_DMA_ADDR 0x10021
+
+
+/* The Blizzard 1230 DMA interface
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * Only two things can be programmed in the Blizzard DMA:
+ * 1) The data direction is controlled by the status of bit 31 (1 = write)
+ * 2) The source/dest address (word aligned, shifted one right) in bits 30-0
+ *
+ * Program DMA by first latching the highest byte of the address/direction
+ * (i.e. bits 31-24 of the long word constructed as described in steps 1+2
+ * above). Then write each byte of the address/direction (starting with the
+ * top byte, working down) to the DMA address register.
+ *
+ * Figure out interrupt status by reading the ESP status byte.
+ */
+struct blz1230_dma_registers {
+ volatile unsigned char dma_addr; /* DMA address [0x0000] */
+ unsigned char dmapad2[0x7fff];
+ volatile unsigned char dma_latch; /* DMA latch [0x8000] */
+};
+
+struct blz1230II_dma_registers {
+ volatile unsigned char dma_addr; /* DMA address [0x0000] */
+ unsigned char dmapad2[0xf];
+ volatile unsigned char dma_latch; /* DMA latch [0x0010] */
+};
+
+#define BLZ1230_DMA_WRITE 0x80000000
+
+static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count);
+static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp);
+static void dma_dump_state(struct NCR_ESP *esp);
+static void dma_init_read(struct NCR_ESP *esp, __u32 addr, int length);
+static void dma_init_write(struct NCR_ESP *esp, __u32 addr, int length);
+static void dma_ints_off(struct NCR_ESP *esp);
+static void dma_ints_on(struct NCR_ESP *esp);
+static int dma_irq_p(struct NCR_ESP *esp);
+static int dma_ports_p(struct NCR_ESP *esp);
+static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write);
+
+static volatile unsigned char cmd_buffer[16];
+ /* This is where all commands are put
+ * before they are transferred to the ESP chip
+ * via PIO.
+ */
+
+/***************************************************************** Detection */
+int __init blz1230_esp_detect(struct scsi_host_template *tpnt)
+{
+ struct NCR_ESP *esp;
+ struct zorro_dev *z = NULL;
+ unsigned long address;
+ struct ESP_regs *eregs;
+ unsigned long board;
+
+#if MKIV
+#define REAL_BLZ1230_ID ZORRO_PROD_PHASE5_BLIZZARD_1230_IV_1260
+#define REAL_BLZ1230_ESP_ADDR BLZ1230_ESP_ADDR
+#define REAL_BLZ1230_DMA_ADDR BLZ1230_DMA_ADDR
+#else
+#define REAL_BLZ1230_ID ZORRO_PROD_PHASE5_BLIZZARD_1230_II_FASTLANE_Z3_CYBERSCSI_CYBERSTORM060
+#define REAL_BLZ1230_ESP_ADDR BLZ1230II_ESP_ADDR
+#define REAL_BLZ1230_DMA_ADDR BLZ1230II_DMA_ADDR
+#endif
+
+ if ((z = zorro_find_device(REAL_BLZ1230_ID, z))) {
+ board = z->resource.start;
+ if (request_mem_region(board+REAL_BLZ1230_ESP_ADDR,
+ sizeof(struct ESP_regs), "NCR53C9x")) {
+ /* Do some magic to figure out if the blizzard is
+ * equipped with a SCSI controller
+ */
+ address = ZTWO_VADDR(board);
+ eregs = (struct ESP_regs *)(address + REAL_BLZ1230_ESP_ADDR);
+ esp = esp_allocate(tpnt, (void *)board + REAL_BLZ1230_ESP_ADDR,
+ 0);
+
+ esp_write(eregs->esp_cfg1, (ESP_CONFIG1_PENABLE | 7));
+ udelay(5);
+ if(esp_read(eregs->esp_cfg1) != (ESP_CONFIG1_PENABLE | 7))
+ goto err_out;
+
+ /* Do command transfer with programmed I/O */
+ esp->do_pio_cmds = 1;
+
+ /* Required functions */
+ esp->dma_bytes_sent = &dma_bytes_sent;
+ esp->dma_can_transfer = &dma_can_transfer;
+ esp->dma_dump_state = &dma_dump_state;
+ esp->dma_init_read = &dma_init_read;
+ esp->dma_init_write = &dma_init_write;
+ esp->dma_ints_off = &dma_ints_off;
+ esp->dma_ints_on = &dma_ints_on;
+ esp->dma_irq_p = &dma_irq_p;
+ esp->dma_ports_p = &dma_ports_p;
+ esp->dma_setup = &dma_setup;
+
+ /* Optional functions */
+ esp->dma_barrier = 0;
+ esp->dma_drain = 0;
+ esp->dma_invalidate = 0;
+ esp->dma_irq_entry = 0;
+ esp->dma_irq_exit = 0;
+ esp->dma_led_on = 0;
+ esp->dma_led_off = 0;
+ esp->dma_poll = 0;
+ esp->dma_reset = 0;
+
+ /* SCSI chip speed */
+ esp->cfreq = 40000000;
+
+ /* The DMA registers on the Blizzard are mapped
+ * relative to the device (i.e. in the same Zorro
+ * I/O block).
+ */
+ esp->dregs = (void *)(address + REAL_BLZ1230_DMA_ADDR);
+
+ /* ESP register base */
+ esp->eregs = eregs;
+
+ /* Set the command buffer */
+ esp->esp_command = cmd_buffer;
+ esp->esp_command_dvma = virt_to_bus((void *)cmd_buffer);
+
+ esp->irq = IRQ_AMIGA_PORTS;
+ esp->slot = board+REAL_BLZ1230_ESP_ADDR;
+ if (request_irq(IRQ_AMIGA_PORTS, esp_intr, IRQF_SHARED,
+ "Blizzard 1230 SCSI IV", esp->ehost))
+ goto err_out;
+
+ /* Figure out our scsi ID on the bus */
+ esp->scsi_id = 7;
+
+ /* We don't have a differential SCSI-bus. */
+ esp->diff = 0;
+
+ esp_initialize(esp);
+
+ printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps, esps_in_use);
+ esps_running = esps_in_use;
+ return esps_in_use;
+ }
+ }
+ return 0;
+
+ err_out:
+ scsi_unregister(esp->ehost);
+ esp_deallocate(esp);
+ release_mem_region(board+REAL_BLZ1230_ESP_ADDR,
+ sizeof(struct ESP_regs));
+ return 0;
+}
+
+/************************************************************* DMA Functions */
+static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count)
+{
+ /* Since the Blizzard DMA is fully dedicated to the ESP chip,
+ * the number of bytes sent (to the ESP chip) equals the number
+ * of bytes in the FIFO - there is no buffering in the DMA controller.
+ * XXXX Do I read this right? It is from host to ESP, right?
+ */
+ return fifo_count;
+}
+
+static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp)
+{
+ /* I don't think there's any limit on the Blizzard DMA. So we use what
+ * the ESP chip can handle (24 bit).
+ */
+ unsigned long sz = sp->SCp.this_residual;
+ if(sz > 0x1000000)
+ sz = 0x1000000;
+ return sz;
+}
+
+static void dma_dump_state(struct NCR_ESP *esp)
+{
+ ESPLOG(("intreq:<%04x>, intena:<%04x>\n",
+ amiga_custom.intreqr, amiga_custom.intenar));
+}
+
+void dma_init_read(struct NCR_ESP *esp, __u32 addr, int length)
+{
+#if MKIV
+ struct blz1230_dma_registers *dregs =
+ (struct blz1230_dma_registers *) (esp->dregs);
+#else
+ struct blz1230II_dma_registers *dregs =
+ (struct blz1230II_dma_registers *) (esp->dregs);
+#endif
+
+ cache_clear(addr, length);
+
+ addr >>= 1;
+ addr &= ~(BLZ1230_DMA_WRITE);
+
+ /* First set latch */
+ dregs->dma_latch = (addr >> 24) & 0xff;
+
+ /* Then pump the address to the DMA address register */
+#if MKIV
+ dregs->dma_addr = (addr >> 24) & 0xff;
+#endif
+ dregs->dma_addr = (addr >> 16) & 0xff;
+ dregs->dma_addr = (addr >> 8) & 0xff;
+ dregs->dma_addr = (addr ) & 0xff;
+}
+
+void dma_init_write(struct NCR_ESP *esp, __u32 addr, int length)
+{
+#if MKIV
+ struct blz1230_dma_registers *dregs =
+ (struct blz1230_dma_registers *) (esp->dregs);
+#else
+ struct blz1230II_dma_registers *dregs =
+ (struct blz1230II_dma_registers *) (esp->dregs);
+#endif
+
+ cache_push(addr, length);
+
+ addr >>= 1;
+ addr |= BLZ1230_DMA_WRITE;
+
+ /* First set latch */
+ dregs->dma_latch = (addr >> 24) & 0xff;
+
+ /* Then pump the address to the DMA address register */
+#if MKIV
+ dregs->dma_addr = (addr >> 24) & 0xff;
+#endif
+ dregs->dma_addr = (addr >> 16) & 0xff;
+ dregs->dma_addr = (addr >> 8) & 0xff;
+ dregs->dma_addr = (addr ) & 0xff;
+}
+
+static void dma_ints_off(struct NCR_ESP *esp)
+{
+ disable_irq(esp->irq);
+}
+
+static void dma_ints_on(struct NCR_ESP *esp)
+{
+ enable_irq(esp->irq);
+}
+
+static int dma_irq_p(struct NCR_ESP *esp)
+{
+ return (esp_read(esp->eregs->esp_status) & ESP_STAT_INTR);
+}
+
+static int dma_ports_p(struct NCR_ESP *esp)
+{
+ return ((amiga_custom.intenar) & IF_PORTS);
+}
+
+static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write)
+{
+ /* On the Sparc, DMA_ST_WRITE means "move data from device to memory"
+ * so when (write) is true, it actually means READ!
+ */
+ if(write){
+ dma_init_read(esp, addr, count);
+ } else {
+ dma_init_write(esp, addr, count);
+ }
+}
+
+#define HOSTS_C
+
+int blz1230_esp_release(struct Scsi_Host *instance)
+{
+#ifdef MODULE
+ unsigned long address = (unsigned long)((struct NCR_ESP *)instance->hostdata)->edev;
+ esp_deallocate((struct NCR_ESP *)instance->hostdata);
+ esp_release();
+ release_mem_region(address, sizeof(struct ESP_regs));
+ free_irq(IRQ_AMIGA_PORTS, esp_intr);
+#endif
+ return 1;
+}
+
+
+static struct scsi_host_template driver_template = {
+ .proc_name = "esp-blz1230",
+ .proc_info = esp_proc_info,
+ .name = "Blizzard1230 SCSI IV",
+ .detect = blz1230_esp_detect,
+ .slave_alloc = esp_slave_alloc,
+ .slave_destroy = esp_slave_destroy,
+ .release = blz1230_esp_release,
+ .queuecommand = esp_queue,
+ .eh_abort_handler = esp_abort,
+ .eh_bus_reset_handler = esp_reset,
+ .can_queue = 7,
+ .this_id = 7,
+ .sg_tablesize = SG_ALL,
+ .cmd_per_lun = 1,
+ .use_clustering = ENABLE_CLUSTERING
+};
+
+
+#include "scsi_module.c"
+
+MODULE_LICENSE("GPL");
diff --git a/trunk/drivers/scsi/blz2060.c b/trunk/drivers/scsi/blz2060.c
new file mode 100644
index 000000000000..b6203ec00961
--- /dev/null
+++ b/trunk/drivers/scsi/blz2060.c
@@ -0,0 +1,306 @@
+/* blz2060.c: Driver for Blizzard 2060 SCSI Controller.
+ *
+ * Copyright (C) 1996 Jesper Skov (jskov@cygnus.co.uk)
+ *
+ * This driver is based on the CyberStorm driver, hence the occasional
+ * reference to CyberStorm.
+ */
+
+/* TODO:
+ *
+ * 1) Figure out how to make a cleaner merge with the sparc driver with regard
+ * to the caches and the Sparc MMU mapping.
+ * 2) Make as few routines required outside the generic driver. A lot of the
+ * routines in this file used to be inline!
+ */
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "scsi.h"
+#include
+#include "NCR53C9x.h"
+
+#include
+#include
+#include
+#include
+
+#include
+
+/* The controller registers can be found in the Z2 config area at these
+ * offsets:
+ */
+#define BLZ2060_ESP_ADDR 0x1ff00
+#define BLZ2060_DMA_ADDR 0x1ffe0
+
+
+/* The Blizzard 2060 DMA interface
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * Only two things can be programmed in the Blizzard DMA:
+ * 1) The data direction is controlled by the status of bit 31 (1 = write)
+ * 2) The source/dest address (word aligned, shifted one right) in bits 30-0
+ *
+ * Figure out interrupt status by reading the ESP status byte.
+ */
+struct blz2060_dma_registers {
+ volatile unsigned char dma_led_ctrl; /* DMA led control [0x000] */
+ unsigned char dmapad1[0x0f];
+ volatile unsigned char dma_addr0; /* DMA address (MSB) [0x010] */
+ unsigned char dmapad2[0x03];
+ volatile unsigned char dma_addr1; /* DMA address [0x014] */
+ unsigned char dmapad3[0x03];
+ volatile unsigned char dma_addr2; /* DMA address [0x018] */
+ unsigned char dmapad4[0x03];
+ volatile unsigned char dma_addr3; /* DMA address (LSB) [0x01c] */
+};
+
+#define BLZ2060_DMA_WRITE 0x80000000
+
+/* DMA control bits */
+#define BLZ2060_DMA_LED 0x02 /* HD led control 1 = off */
+
+static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count);
+static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp);
+static void dma_dump_state(struct NCR_ESP *esp);
+static void dma_init_read(struct NCR_ESP *esp, __u32 addr, int length);
+static void dma_init_write(struct NCR_ESP *esp, __u32 addr, int length);
+static void dma_ints_off(struct NCR_ESP *esp);
+static void dma_ints_on(struct NCR_ESP *esp);
+static int dma_irq_p(struct NCR_ESP *esp);
+static void dma_led_off(struct NCR_ESP *esp);
+static void dma_led_on(struct NCR_ESP *esp);
+static int dma_ports_p(struct NCR_ESP *esp);
+static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write);
+
+static volatile unsigned char cmd_buffer[16];
+ /* This is where all commands are put
+ * before they are transferred to the ESP chip
+ * via PIO.
+ */
+
+/***************************************************************** Detection */
+int __init blz2060_esp_detect(struct scsi_host_template *tpnt)
+{
+ struct NCR_ESP *esp;
+ struct zorro_dev *z = NULL;
+ unsigned long address;
+
+ if ((z = zorro_find_device(ZORRO_PROD_PHASE5_BLIZZARD_2060, z))) {
+ unsigned long board = z->resource.start;
+ if (request_mem_region(board+BLZ2060_ESP_ADDR,
+ sizeof(struct ESP_regs), "NCR53C9x")) {
+ esp = esp_allocate(tpnt, (void *)board + BLZ2060_ESP_ADDR, 0);
+
+ /* Do command transfer with programmed I/O */
+ esp->do_pio_cmds = 1;
+
+ /* Required functions */
+ esp->dma_bytes_sent = &dma_bytes_sent;
+ esp->dma_can_transfer = &dma_can_transfer;
+ esp->dma_dump_state = &dma_dump_state;
+ esp->dma_init_read = &dma_init_read;
+ esp->dma_init_write = &dma_init_write;
+ esp->dma_ints_off = &dma_ints_off;
+ esp->dma_ints_on = &dma_ints_on;
+ esp->dma_irq_p = &dma_irq_p;
+ esp->dma_ports_p = &dma_ports_p;
+ esp->dma_setup = &dma_setup;
+
+ /* Optional functions */
+ esp->dma_barrier = 0;
+ esp->dma_drain = 0;
+ esp->dma_invalidate = 0;
+ esp->dma_irq_entry = 0;
+ esp->dma_irq_exit = 0;
+ esp->dma_led_on = &dma_led_on;
+ esp->dma_led_off = &dma_led_off;
+ esp->dma_poll = 0;
+ esp->dma_reset = 0;
+
+ /* SCSI chip speed */
+ esp->cfreq = 40000000;
+
+ /* The DMA registers on the Blizzard are mapped
+ * relative to the device (i.e. in the same Zorro
+ * I/O block).
+ */
+ address = (unsigned long)ZTWO_VADDR(board);
+ esp->dregs = (void *)(address + BLZ2060_DMA_ADDR);
+
+ /* ESP register base */
+ esp->eregs = (struct ESP_regs *)(address + BLZ2060_ESP_ADDR);
+
+ /* Set the command buffer */
+ esp->esp_command = cmd_buffer;
+ esp->esp_command_dvma = virt_to_bus((void *)cmd_buffer);
+
+ esp->irq = IRQ_AMIGA_PORTS;
+ request_irq(IRQ_AMIGA_PORTS, esp_intr, IRQF_SHARED,
+ "Blizzard 2060 SCSI", esp->ehost);
+
+ /* Figure out our scsi ID on the bus */
+ esp->scsi_id = 7;
+
+ /* We don't have a differential SCSI-bus. */
+ esp->diff = 0;
+
+ esp_initialize(esp);
+
+ printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps, esps_in_use);
+ esps_running = esps_in_use;
+ return esps_in_use;
+ }
+ }
+ return 0;
+}
+
+/************************************************************* DMA Functions */
+static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count)
+{
+ /* Since the Blizzard DMA is fully dedicated to the ESP chip,
+ * the number of bytes sent (to the ESP chip) equals the number
+ * of bytes in the FIFO - there is no buffering in the DMA controller.
+ * XXXX Do I read this right? It is from host to ESP, right?
+ */
+ return fifo_count;
+}
+
+static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp)
+{
+ /* I don't think there's any limit on the Blizzard DMA. So we use what
+ * the ESP chip can handle (24 bit).
+ */
+ unsigned long sz = sp->SCp.this_residual;
+ if(sz > 0x1000000)
+ sz = 0x1000000;
+ return sz;
+}
+
+static void dma_dump_state(struct NCR_ESP *esp)
+{
+ ESPLOG(("intreq:<%04x>, intena:<%04x>\n",
+ amiga_custom.intreqr, amiga_custom.intenar));
+}
+
+static void dma_init_read(struct NCR_ESP *esp, __u32 addr, int length)
+{
+ struct blz2060_dma_registers *dregs =
+ (struct blz2060_dma_registers *) (esp->dregs);
+
+ cache_clear(addr, length);
+
+ addr >>= 1;
+ addr &= ~(BLZ2060_DMA_WRITE);
+ dregs->dma_addr3 = (addr ) & 0xff;
+ dregs->dma_addr2 = (addr >> 8) & 0xff;
+ dregs->dma_addr1 = (addr >> 16) & 0xff;
+ dregs->dma_addr0 = (addr >> 24) & 0xff;
+}
+
+static void dma_init_write(struct NCR_ESP *esp, __u32 addr, int length)
+{
+ struct blz2060_dma_registers *dregs =
+ (struct blz2060_dma_registers *) (esp->dregs);
+
+ cache_push(addr, length);
+
+ addr >>= 1;
+ addr |= BLZ2060_DMA_WRITE;
+ dregs->dma_addr3 = (addr ) & 0xff;
+ dregs->dma_addr2 = (addr >> 8) & 0xff;
+ dregs->dma_addr1 = (addr >> 16) & 0xff;
+ dregs->dma_addr0 = (addr >> 24) & 0xff;
+}
+
+static void dma_ints_off(struct NCR_ESP *esp)
+{
+ disable_irq(esp->irq);
+}
+
+static void dma_ints_on(struct NCR_ESP *esp)
+{
+ enable_irq(esp->irq);
+}
+
+static int dma_irq_p(struct NCR_ESP *esp)
+{
+ return (esp_read(esp->eregs->esp_status) & ESP_STAT_INTR);
+}
+
+static void dma_led_off(struct NCR_ESP *esp)
+{
+ ((struct blz2060_dma_registers *) (esp->dregs))->dma_led_ctrl =
+ BLZ2060_DMA_LED;
+}
+
+static void dma_led_on(struct NCR_ESP *esp)
+{
+ ((struct blz2060_dma_registers *) (esp->dregs))->dma_led_ctrl = 0;
+}
+
+static int dma_ports_p(struct NCR_ESP *esp)
+{
+ return ((amiga_custom.intenar) & IF_PORTS);
+}
+
+static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write)
+{
+ /* On the Sparc, DMA_ST_WRITE means "move data from device to memory"
+ * so when (write) is true, it actually means READ!
+ */
+ if(write){
+ dma_init_read(esp, addr, count);
+ } else {
+ dma_init_write(esp, addr, count);
+ }
+}
+
+#define HOSTS_C
+
+int blz2060_esp_release(struct Scsi_Host *instance)
+{
+#ifdef MODULE
+ unsigned long address = (unsigned long)((struct NCR_ESP *)instance->hostdata)->edev;
+
+ esp_deallocate((struct NCR_ESP *)instance->hostdata);
+ esp_release();
+ release_mem_region(address, sizeof(struct ESP_regs));
+ free_irq(IRQ_AMIGA_PORTS, esp_intr);
+#endif
+ return 1;
+}
+
+
+static struct scsi_host_template driver_template = {
+ .proc_name = "esp-blz2060",
+ .proc_info = esp_proc_info,
+ .name = "Blizzard2060 SCSI",
+ .detect = blz2060_esp_detect,
+ .slave_alloc = esp_slave_alloc,
+ .slave_destroy = esp_slave_destroy,
+ .release = blz2060_esp_release,
+ .queuecommand = esp_queue,
+ .eh_abort_handler = esp_abort,
+ .eh_bus_reset_handler = esp_reset,
+ .can_queue = 7,
+ .this_id = 7,
+ .sg_tablesize = SG_ALL,
+ .cmd_per_lun = 1,
+ .use_clustering = ENABLE_CLUSTERING
+};
+
+
+#include "scsi_module.c"
+
+MODULE_LICENSE("GPL");
diff --git a/trunk/drivers/scsi/cyberstorm.c b/trunk/drivers/scsi/cyberstorm.c
new file mode 100644
index 000000000000..c6b98a42e89d
--- /dev/null
+++ b/trunk/drivers/scsi/cyberstorm.c
@@ -0,0 +1,377 @@
+/* cyberstorm.c: Driver for CyberStorm SCSI Controller.
+ *
+ * Copyright (C) 1996 Jesper Skov (jskov@cygnus.co.uk)
+ *
+ * The CyberStorm SCSI driver is based on David S. Miller's ESP driver
+ * for the Sparc computers.
+ *
+ * This work was made possible by Phase5 who willingly (and most generously)
+ * supported me with hardware and all the information I needed.
+ */
+
+/* TODO:
+ *
+ * 1) Figure out how to make a cleaner merge with the sparc driver with regard
+ * to the caches and the Sparc MMU mapping.
+ * 2) Make as few routines required outside the generic driver. A lot of the
+ * routines in this file used to be inline!
+ */
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "scsi.h"
+#include
+#include "NCR53C9x.h"
+
+#include
+#include
+#include
+#include
+
+#include
+
+/* The controller registers can be found in the Z2 config area at these
+ * offsets:
+ */
+#define CYBER_ESP_ADDR 0xf400
+#define CYBER_DMA_ADDR 0xf800
+
+
+/* The CyberStorm DMA interface */
+struct cyber_dma_registers {
+ volatile unsigned char dma_addr0; /* DMA address (MSB) [0x000] */
+ unsigned char dmapad1[1];
+ volatile unsigned char dma_addr1; /* DMA address [0x002] */
+ unsigned char dmapad2[1];
+ volatile unsigned char dma_addr2; /* DMA address [0x004] */
+ unsigned char dmapad3[1];
+ volatile unsigned char dma_addr3; /* DMA address (LSB) [0x006] */
+ unsigned char dmapad4[0x3fb];
+ volatile unsigned char cond_reg; /* DMA cond (ro) [0x402] */
+#define ctrl_reg cond_reg /* DMA control (wo) [0x402] */
+};
+
+/* DMA control bits */
+#define CYBER_DMA_LED 0x80 /* HD led control 1 = on */
+#define CYBER_DMA_WRITE 0x40 /* DMA direction. 1 = write */
+#define CYBER_DMA_Z3 0x20 /* 16 (Z2) or 32 (CHIP/Z3) bit DMA transfer */
+
+/* DMA status bits */
+#define CYBER_DMA_HNDL_INTR 0x80 /* DMA IRQ pending? */
+
+/* The bits below appears to be Phase5 Debug bits only; they were not
+ * described by Phase5 so using them may seem a bit stupid...
+ */
+#define CYBER_HOST_ID 0x02 /* If set, host ID should be 7, otherwise
+ * it should be 6.
+ */
+#define CYBER_SLOW_CABLE 0x08 /* If *not* set, assume SLOW_CABLE */
+
+static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count);
+static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp);
+static void dma_dump_state(struct NCR_ESP *esp);
+static void dma_init_read(struct NCR_ESP *esp, __u32 addr, int length);
+static void dma_init_write(struct NCR_ESP *esp, __u32 addr, int length);
+static void dma_ints_off(struct NCR_ESP *esp);
+static void dma_ints_on(struct NCR_ESP *esp);
+static int dma_irq_p(struct NCR_ESP *esp);
+static void dma_led_off(struct NCR_ESP *esp);
+static void dma_led_on(struct NCR_ESP *esp);
+static int dma_ports_p(struct NCR_ESP *esp);
+static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write);
+
+static unsigned char ctrl_data = 0; /* Keep backup of the stuff written
+ * to ctrl_reg. Always write a copy
+ * to this register when writing to
+ * the hardware register!
+ */
+
+static volatile unsigned char cmd_buffer[16];
+ /* This is where all commands are put
+ * before they are transferred to the ESP chip
+ * via PIO.
+ */
+
+/***************************************************************** Detection */
+int __init cyber_esp_detect(struct scsi_host_template *tpnt)
+{
+ struct NCR_ESP *esp;
+ struct zorro_dev *z = NULL;
+ unsigned long address;
+
+ while ((z = zorro_find_device(ZORRO_WILDCARD, z))) {
+ unsigned long board = z->resource.start;
+ if ((z->id == ZORRO_PROD_PHASE5_BLIZZARD_1220_CYBERSTORM ||
+ z->id == ZORRO_PROD_PHASE5_BLIZZARD_1230_II_FASTLANE_Z3_CYBERSCSI_CYBERSTORM060) &&
+ request_mem_region(board+CYBER_ESP_ADDR,
+ sizeof(struct ESP_regs), "NCR53C9x")) {
+ /* Figure out if this is a CyberStorm or really a
+ * Fastlane/Blizzard Mk II by looking at the board size.
+ * CyberStorm maps 64kB
+ * (ZORRO_PROD_PHASE5_BLIZZARD_1220_CYBERSTORM does anyway)
+ */
+ if(z->resource.end-board != 0xffff) {
+ release_mem_region(board+CYBER_ESP_ADDR,
+ sizeof(struct ESP_regs));
+ return 0;
+ }
+ esp = esp_allocate(tpnt, (void *)board + CYBER_ESP_ADDR, 0);
+
+ /* Do command transfer with programmed I/O */
+ esp->do_pio_cmds = 1;
+
+ /* Required functions */
+ esp->dma_bytes_sent = &dma_bytes_sent;
+ esp->dma_can_transfer = &dma_can_transfer;
+ esp->dma_dump_state = &dma_dump_state;
+ esp->dma_init_read = &dma_init_read;
+ esp->dma_init_write = &dma_init_write;
+ esp->dma_ints_off = &dma_ints_off;
+ esp->dma_ints_on = &dma_ints_on;
+ esp->dma_irq_p = &dma_irq_p;
+ esp->dma_ports_p = &dma_ports_p;
+ esp->dma_setup = &dma_setup;
+
+ /* Optional functions */
+ esp->dma_barrier = 0;
+ esp->dma_drain = 0;
+ esp->dma_invalidate = 0;
+ esp->dma_irq_entry = 0;
+ esp->dma_irq_exit = 0;
+ esp->dma_led_on = &dma_led_on;
+ esp->dma_led_off = &dma_led_off;
+ esp->dma_poll = 0;
+ esp->dma_reset = 0;
+
+ /* SCSI chip speed */
+ esp->cfreq = 40000000;
+
+ /* The DMA registers on the CyberStorm are mapped
+ * relative to the device (i.e. in the same Zorro
+ * I/O block).
+ */
+ address = (unsigned long)ZTWO_VADDR(board);
+ esp->dregs = (void *)(address + CYBER_DMA_ADDR);
+
+ /* ESP register base */
+ esp->eregs = (struct ESP_regs *)(address + CYBER_ESP_ADDR);
+
+ /* Set the command buffer */
+ esp->esp_command = cmd_buffer;
+ esp->esp_command_dvma = virt_to_bus((void *)cmd_buffer);
+
+ esp->irq = IRQ_AMIGA_PORTS;
+ request_irq(IRQ_AMIGA_PORTS, esp_intr, IRQF_SHARED,
+ "CyberStorm SCSI", esp->ehost);
+ /* Figure out our scsi ID on the bus */
+ /* The DMA cond flag contains a hardcoded jumper bit
+ * which can be used to select host number 6 or 7.
+ * However, even though it may change, we use a hardcoded
+ * value of 7.
+ */
+ esp->scsi_id = 7;
+
+ /* We don't have a differential SCSI-bus. */
+ esp->diff = 0;
+
+ esp_initialize(esp);
+
+ printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps, esps_in_use);
+ esps_running = esps_in_use;
+ return esps_in_use;
+ }
+ }
+ return 0;
+}
+
+/************************************************************* DMA Functions */
+static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count)
+{
+ /* Since the CyberStorm DMA is fully dedicated to the ESP chip,
+ * the number of bytes sent (to the ESP chip) equals the number
+ * of bytes in the FIFO - there is no buffering in the DMA controller.
+ * XXXX Do I read this right? It is from host to ESP, right?
+ */
+ return fifo_count;
+}
+
+static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp)
+{
+ /* I don't think there's any limit on the CyberDMA. So we use what
+ * the ESP chip can handle (24 bit).
+ */
+ unsigned long sz = sp->SCp.this_residual;
+ if(sz > 0x1000000)
+ sz = 0x1000000;
+ return sz;
+}
+
+static void dma_dump_state(struct NCR_ESP *esp)
+{
+ ESPLOG(("esp%d: dma -- cond_reg<%02x>\n",
+ esp->esp_id, ((struct cyber_dma_registers *)
+ (esp->dregs))->cond_reg));
+ ESPLOG(("intreq:<%04x>, intena:<%04x>\n",
+ amiga_custom.intreqr, amiga_custom.intenar));
+}
+
+static void dma_init_read(struct NCR_ESP *esp, __u32 addr, int length)
+{
+ struct cyber_dma_registers *dregs =
+ (struct cyber_dma_registers *) esp->dregs;
+
+ cache_clear(addr, length);
+
+ addr &= ~(1);
+ dregs->dma_addr0 = (addr >> 24) & 0xff;
+ dregs->dma_addr1 = (addr >> 16) & 0xff;
+ dregs->dma_addr2 = (addr >> 8) & 0xff;
+ dregs->dma_addr3 = (addr ) & 0xff;
+ ctrl_data &= ~(CYBER_DMA_WRITE);
+
+ /* Check if physical address is outside Z2 space and of
+ * block length/block aligned in memory. If this is the
+ * case, enable 32 bit transfer. In all other cases, fall back
+ * to 16 bit transfer.
+ * Obviously 32 bit transfer should be enabled if the DMA address
+ * and length are 32 bit aligned. However, this leads to some
+ * strange behavior. Even 64 bit aligned addr/length fails.
+ * Until I've found a reason for this, 32 bit transfer is only
+ * used for full-block transfers (1kB).
+ * -jskov
+ */
+#if 0
+ if((addr & 0x3fc) || length & 0x3ff || ((addr > 0x200000) &&
+ (addr < 0xff0000)))
+ ctrl_data &= ~(CYBER_DMA_Z3); /* Z2, do 16 bit DMA */
+ else
+ ctrl_data |= CYBER_DMA_Z3; /* CHIP/Z3, do 32 bit DMA */
+#else
+ ctrl_data &= ~(CYBER_DMA_Z3); /* Z2, do 16 bit DMA */
+#endif
+ dregs->ctrl_reg = ctrl_data;
+}
+
+static void dma_init_write(struct NCR_ESP *esp, __u32 addr, int length)
+{
+ struct cyber_dma_registers *dregs =
+ (struct cyber_dma_registers *) esp->dregs;
+
+ cache_push(addr, length);
+
+ addr |= 1;
+ dregs->dma_addr0 = (addr >> 24) & 0xff;
+ dregs->dma_addr1 = (addr >> 16) & 0xff;
+ dregs->dma_addr2 = (addr >> 8) & 0xff;
+ dregs->dma_addr3 = (addr ) & 0xff;
+ ctrl_data |= CYBER_DMA_WRITE;
+
+ /* See comment above */
+#if 0
+ if((addr & 0x3fc) || length & 0x3ff || ((addr > 0x200000) &&
+ (addr < 0xff0000)))
+ ctrl_data &= ~(CYBER_DMA_Z3); /* Z2, do 16 bit DMA */
+ else
+ ctrl_data |= CYBER_DMA_Z3; /* CHIP/Z3, do 32 bit DMA */
+#else
+ ctrl_data &= ~(CYBER_DMA_Z3); /* Z2, do 16 bit DMA */
+#endif
+ dregs->ctrl_reg = ctrl_data;
+}
+
+static void dma_ints_off(struct NCR_ESP *esp)
+{
+ disable_irq(esp->irq);
+}
+
+static void dma_ints_on(struct NCR_ESP *esp)
+{
+ enable_irq(esp->irq);
+}
+
+static int dma_irq_p(struct NCR_ESP *esp)
+{
+ /* It's important to check the DMA IRQ bit in the correct way! */
+ return ((esp_read(esp->eregs->esp_status) & ESP_STAT_INTR) &&
+ ((((struct cyber_dma_registers *)(esp->dregs))->cond_reg) &
+ CYBER_DMA_HNDL_INTR));
+}
+
+static void dma_led_off(struct NCR_ESP *esp)
+{
+ ctrl_data &= ~CYBER_DMA_LED;
+ ((struct cyber_dma_registers *)(esp->dregs))->ctrl_reg = ctrl_data;
+}
+
+static void dma_led_on(struct NCR_ESP *esp)
+{
+ ctrl_data |= CYBER_DMA_LED;
+ ((struct cyber_dma_registers *)(esp->dregs))->ctrl_reg = ctrl_data;
+}
+
+static int dma_ports_p(struct NCR_ESP *esp)
+{
+ return ((amiga_custom.intenar) & IF_PORTS);
+}
+
+static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write)
+{
+ /* On the Sparc, DMA_ST_WRITE means "move data from device to memory"
+ * so when (write) is true, it actually means READ!
+ */
+ if(write){
+ dma_init_read(esp, addr, count);
+ } else {
+ dma_init_write(esp, addr, count);
+ }
+}
+
+#define HOSTS_C
+
+int cyber_esp_release(struct Scsi_Host *instance)
+{
+#ifdef MODULE
+ unsigned long address = (unsigned long)((struct NCR_ESP *)instance->hostdata)->edev;
+
+ esp_deallocate((struct NCR_ESP *)instance->hostdata);
+ esp_release();
+ release_mem_region(address, sizeof(struct ESP_regs));
+ free_irq(IRQ_AMIGA_PORTS, esp_intr);
+#endif
+ return 1;
+}
+
+
+static struct scsi_host_template driver_template = {
+ .proc_name = "esp-cyberstorm",
+ .proc_info = esp_proc_info,
+ .name = "CyberStorm SCSI",
+ .detect = cyber_esp_detect,
+ .slave_alloc = esp_slave_alloc,
+ .slave_destroy = esp_slave_destroy,
+ .release = cyber_esp_release,
+ .queuecommand = esp_queue,
+ .eh_abort_handler = esp_abort,
+ .eh_bus_reset_handler = esp_reset,
+ .can_queue = 7,
+ .this_id = 7,
+ .sg_tablesize = SG_ALL,
+ .cmd_per_lun = 1,
+ .use_clustering = ENABLE_CLUSTERING
+};
+
+
+#include "scsi_module.c"
+
+MODULE_LICENSE("GPL");
diff --git a/trunk/drivers/scsi/cyberstormII.c b/trunk/drivers/scsi/cyberstormII.c
new file mode 100644
index 000000000000..e336e853e66f
--- /dev/null
+++ b/trunk/drivers/scsi/cyberstormII.c
@@ -0,0 +1,314 @@
+/* cyberstormII.c: Driver for CyberStorm SCSI Mk II
+ *
+ * Copyright (C) 1996 Jesper Skov (jskov@cygnus.co.uk)
+ *
+ * This driver is based on cyberstorm.c
+ */
+
+/* TODO:
+ *
+ * 1) Figure out how to make a cleaner merge with the sparc driver with regard
+ * to the caches and the Sparc MMU mapping.
+ * 2) Make as few routines required outside the generic driver. A lot of the
+ * routines in this file used to be inline!
+ */
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "scsi.h"
+#include
+#include "NCR53C9x.h"
+
+#include
+#include
+#include
+#include
+
+#include
+
+/* The controller registers can be found in the Z2 config area at these
+ * offsets:
+ */
+#define CYBERII_ESP_ADDR 0x1ff03
+#define CYBERII_DMA_ADDR 0x1ff43
+
+
+/* The CyberStorm II DMA interface */
+struct cyberII_dma_registers {
+ volatile unsigned char cond_reg; /* DMA cond (ro) [0x000] */
+#define ctrl_reg cond_reg /* DMA control (wo) [0x000] */
+ unsigned char dmapad4[0x3f];
+ volatile unsigned char dma_addr0; /* DMA address (MSB) [0x040] */
+ unsigned char dmapad1[3];
+ volatile unsigned char dma_addr1; /* DMA address [0x044] */
+ unsigned char dmapad2[3];
+ volatile unsigned char dma_addr2; /* DMA address [0x048] */
+ unsigned char dmapad3[3];
+ volatile unsigned char dma_addr3; /* DMA address (LSB) [0x04c] */
+};
+
+/* DMA control bits */
+#define CYBERII_DMA_LED 0x02 /* HD led control 1 = on */
+
+static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count);
+static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp);
+static void dma_dump_state(struct NCR_ESP *esp);
+static void dma_init_read(struct NCR_ESP *esp, __u32 addr, int length);
+static void dma_init_write(struct NCR_ESP *esp, __u32 addr, int length);
+static void dma_ints_off(struct NCR_ESP *esp);
+static void dma_ints_on(struct NCR_ESP *esp);
+static int dma_irq_p(struct NCR_ESP *esp);
+static void dma_led_off(struct NCR_ESP *esp);
+static void dma_led_on(struct NCR_ESP *esp);
+static int dma_ports_p(struct NCR_ESP *esp);
+static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write);
+
+static volatile unsigned char cmd_buffer[16];
+ /* This is where all commands are put
+ * before they are transferred to the ESP chip
+ * via PIO.
+ */
+
+/***************************************************************** Detection */
+int __init cyberII_esp_detect(struct scsi_host_template *tpnt)
+{
+ struct NCR_ESP *esp;
+ struct zorro_dev *z = NULL;
+ unsigned long address;
+ struct ESP_regs *eregs;
+
+ if ((z = zorro_find_device(ZORRO_PROD_PHASE5_CYBERSTORM_MK_II, z))) {
+ unsigned long board = z->resource.start;
+ if (request_mem_region(board+CYBERII_ESP_ADDR,
+ sizeof(struct ESP_regs), "NCR53C9x")) {
+ /* Do some magic to figure out if the CyberStorm Mk II
+ * is equipped with a SCSI controller
+ */
+ address = (unsigned long)ZTWO_VADDR(board);
+ eregs = (struct ESP_regs *)(address + CYBERII_ESP_ADDR);
+
+ esp = esp_allocate(tpnt, (void *)board + CYBERII_ESP_ADDR, 0);
+
+ esp_write(eregs->esp_cfg1, (ESP_CONFIG1_PENABLE | 7));
+ udelay(5);
+ if(esp_read(eregs->esp_cfg1) != (ESP_CONFIG1_PENABLE | 7)) {
+ esp_deallocate(esp);
+ scsi_unregister(esp->ehost);
+ release_mem_region(board+CYBERII_ESP_ADDR,
+ sizeof(struct ESP_regs));
+ return 0; /* Bail out if address did not hold data */
+ }
+
+ /* Do command transfer with programmed I/O */
+ esp->do_pio_cmds = 1;
+
+ /* Required functions */
+ esp->dma_bytes_sent = &dma_bytes_sent;
+ esp->dma_can_transfer = &dma_can_transfer;
+ esp->dma_dump_state = &dma_dump_state;
+ esp->dma_init_read = &dma_init_read;
+ esp->dma_init_write = &dma_init_write;
+ esp->dma_ints_off = &dma_ints_off;
+ esp->dma_ints_on = &dma_ints_on;
+ esp->dma_irq_p = &dma_irq_p;
+ esp->dma_ports_p = &dma_ports_p;
+ esp->dma_setup = &dma_setup;
+
+ /* Optional functions */
+ esp->dma_barrier = 0;
+ esp->dma_drain = 0;
+ esp->dma_invalidate = 0;
+ esp->dma_irq_entry = 0;
+ esp->dma_irq_exit = 0;
+ esp->dma_led_on = &dma_led_on;
+ esp->dma_led_off = &dma_led_off;
+ esp->dma_poll = 0;
+ esp->dma_reset = 0;
+
+ /* SCSI chip speed */
+ esp->cfreq = 40000000;
+
+ /* The DMA registers on the CyberStorm are mapped
+ * relative to the device (i.e. in the same Zorro
+ * I/O block).
+ */
+ esp->dregs = (void *)(address + CYBERII_DMA_ADDR);
+
+ /* ESP register base */
+ esp->eregs = eregs;
+
+ /* Set the command buffer */
+ esp->esp_command = cmd_buffer;
+ esp->esp_command_dvma = virt_to_bus((void *)cmd_buffer);
+
+ esp->irq = IRQ_AMIGA_PORTS;
+ request_irq(IRQ_AMIGA_PORTS, esp_intr, IRQF_SHARED,
+ "CyberStorm SCSI Mk II", esp->ehost);
+
+ /* Figure out our scsi ID on the bus */
+ esp->scsi_id = 7;
+
+ /* We don't have a differential SCSI-bus. */
+ esp->diff = 0;
+
+ esp_initialize(esp);
+
+ printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps, esps_in_use);
+ esps_running = esps_in_use;
+ return esps_in_use;
+ }
+ }
+ return 0;
+}
+
+/************************************************************* DMA Functions */
+static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count)
+{
+ /* Since the CyberStorm DMA is fully dedicated to the ESP chip,
+ * the number of bytes sent (to the ESP chip) equals the number
+ * of bytes in the FIFO - there is no buffering in the DMA controller.
+ * XXXX Do I read this right? It is from host to ESP, right?
+ */
+ return fifo_count;
+}
+
+static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp)
+{
+ /* I don't think there's any limit on the CyberDMA. So we use what
+ * the ESP chip can handle (24 bit).
+ */
+ unsigned long sz = sp->SCp.this_residual;
+ if(sz > 0x1000000)
+ sz = 0x1000000;
+ return sz;
+}
+
+static void dma_dump_state(struct NCR_ESP *esp)
+{
+ ESPLOG(("esp%d: dma -- cond_reg<%02x>\n",
+ esp->esp_id, ((struct cyberII_dma_registers *)
+ (esp->dregs))->cond_reg));
+ ESPLOG(("intreq:<%04x>, intena:<%04x>\n",
+ amiga_custom.intreqr, amiga_custom.intenar));
+}
+
+static void dma_init_read(struct NCR_ESP *esp, __u32 addr, int length)
+{
+ struct cyberII_dma_registers *dregs =
+ (struct cyberII_dma_registers *) esp->dregs;
+
+ cache_clear(addr, length);
+
+ addr &= ~(1);
+ dregs->dma_addr0 = (addr >> 24) & 0xff;
+ dregs->dma_addr1 = (addr >> 16) & 0xff;
+ dregs->dma_addr2 = (addr >> 8) & 0xff;
+ dregs->dma_addr3 = (addr ) & 0xff;
+}
+
+static void dma_init_write(struct NCR_ESP *esp, __u32 addr, int length)
+{
+ struct cyberII_dma_registers *dregs =
+ (struct cyberII_dma_registers *) esp->dregs;
+
+ cache_push(addr, length);
+
+ addr |= 1;
+ dregs->dma_addr0 = (addr >> 24) & 0xff;
+ dregs->dma_addr1 = (addr >> 16) & 0xff;
+ dregs->dma_addr2 = (addr >> 8) & 0xff;
+ dregs->dma_addr3 = (addr ) & 0xff;
+}
+
+static void dma_ints_off(struct NCR_ESP *esp)
+{
+ disable_irq(esp->irq);
+}
+
+static void dma_ints_on(struct NCR_ESP *esp)
+{
+ enable_irq(esp->irq);
+}
+
+static int dma_irq_p(struct NCR_ESP *esp)
+{
+ /* It's important to check the DMA IRQ bit in the correct way! */
+ return (esp_read(esp->eregs->esp_status) & ESP_STAT_INTR);
+}
+
+static void dma_led_off(struct NCR_ESP *esp)
+{
+ ((struct cyberII_dma_registers *)(esp->dregs))->ctrl_reg &= ~CYBERII_DMA_LED;
+}
+
+static void dma_led_on(struct NCR_ESP *esp)
+{
+ ((struct cyberII_dma_registers *)(esp->dregs))->ctrl_reg |= CYBERII_DMA_LED;
+}
+
+static int dma_ports_p(struct NCR_ESP *esp)
+{
+ return ((amiga_custom.intenar) & IF_PORTS);
+}
+
+static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write)
+{
+ /* On the Sparc, DMA_ST_WRITE means "move data from device to memory"
+ * so when (write) is true, it actually means READ!
+ */
+ if(write){
+ dma_init_read(esp, addr, count);
+ } else {
+ dma_init_write(esp, addr, count);
+ }
+}
+
+#define HOSTS_C
+
+int cyberII_esp_release(struct Scsi_Host *instance)
+{
+#ifdef MODULE
+ unsigned long address = (unsigned long)((struct NCR_ESP *)instance->hostdata)->edev;
+
+ esp_deallocate((struct NCR_ESP *)instance->hostdata);
+ esp_release();
+ release_mem_region(address, sizeof(struct ESP_regs));
+ free_irq(IRQ_AMIGA_PORTS, esp_intr);
+#endif
+ return 1;
+}
+
+
+static struct scsi_host_template driver_template = {
+ .proc_name = "esp-cyberstormII",
+ .proc_info = esp_proc_info,
+ .name = "CyberStorm Mk II SCSI",
+ .detect = cyberII_esp_detect,
+ .slave_alloc = esp_slave_alloc,
+ .slave_destroy = esp_slave_destroy,
+ .release = cyberII_esp_release,
+ .queuecommand = esp_queue,
+ .eh_abort_handler = esp_abort,
+ .eh_bus_reset_handler = esp_reset,
+ .can_queue = 7,
+ .this_id = 7,
+ .sg_tablesize = SG_ALL,
+ .cmd_per_lun = 1,
+ .use_clustering = ENABLE_CLUSTERING
+};
+
+
+#include "scsi_module.c"
+
+MODULE_LICENSE("GPL");
diff --git a/trunk/drivers/scsi/dc395x.c b/trunk/drivers/scsi/dc395x.c
index e351db6c0077..22ef3716e786 100644
--- a/trunk/drivers/scsi/dc395x.c
+++ b/trunk/drivers/scsi/dc395x.c
@@ -4267,7 +4267,7 @@ static int __devinit adapter_sg_tables_alloc(struct AdapterCtlBlk *acb)
const unsigned srbs_per_page = PAGE_SIZE/SEGMENTX_LEN;
int srb_idx = 0;
unsigned i = 0;
- struct SGentry *uninitialized_var(ptr);
+ struct SGentry *ptr;
for (i = 0; i < DC395x_MAX_SRB_CNT; i++)
acb->srb_array[i].segment_x = NULL;
diff --git a/trunk/drivers/scsi/dec_esp.c b/trunk/drivers/scsi/dec_esp.c
new file mode 100644
index 000000000000..d42ad663ffee
--- /dev/null
+++ b/trunk/drivers/scsi/dec_esp.c
@@ -0,0 +1,687 @@
+/*
+ * dec_esp.c: Driver for SCSI chips on IOASIC based TURBOchannel DECstations
+ * and TURBOchannel PMAZ-A cards
+ *
+ * TURBOchannel changes by Harald Koerfgen
+ * PMAZ-A support by David Airlie
+ *
+ * based on jazz_esp.c:
+ * Copyright (C) 1997 Thomas Bogendoerfer (tsbogend@alpha.franken.de)
+ *
+ * jazz_esp is based on David S. Miller's ESP driver and cyber_esp
+ *
+ * 20000819 - Small PMAZ-AA fixes by Florian Lohoff
+ * Be warned the PMAZ-AA works currently as a single card.
+ * Dont try to put multiple cards in one machine - They are
+ * both detected but it may crash under high load garbling your
+ * data.
+ * 20001005 - Initialization fixes for 2.4.0-test9
+ * Florian Lohoff
+ *
+ * Copyright (C) 2002, 2003, 2005, 2006 Maciej W. Rozycki
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define DEC_SCSI_SREG 0
+#define DEC_SCSI_DMAREG 0x40000
+#define DEC_SCSI_SRAM 0x80000
+#define DEC_SCSI_DIAG 0xC0000
+
+#include "scsi.h"
+#include
+#include "NCR53C9x.h"
+
+static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count);
+static void dma_drain(struct NCR_ESP *esp);
+static int dma_can_transfer(struct NCR_ESP *esp, struct scsi_cmnd *sp);
+static void dma_dump_state(struct NCR_ESP *esp);
+static void dma_init_read(struct NCR_ESP *esp, u32 vaddress, int length);
+static void dma_init_write(struct NCR_ESP *esp, u32 vaddress, int length);
+static void dma_ints_off(struct NCR_ESP *esp);
+static void dma_ints_on(struct NCR_ESP *esp);
+static int dma_irq_p(struct NCR_ESP *esp);
+static int dma_ports_p(struct NCR_ESP *esp);
+static void dma_setup(struct NCR_ESP *esp, u32 addr, int count, int write);
+static void dma_mmu_get_scsi_one(struct NCR_ESP *esp, struct scsi_cmnd * sp);
+static void dma_mmu_get_scsi_sgl(struct NCR_ESP *esp, struct scsi_cmnd * sp);
+static void dma_advance_sg(struct scsi_cmnd * sp);
+
+static void pmaz_dma_drain(struct NCR_ESP *esp);
+static void pmaz_dma_init_read(struct NCR_ESP *esp, u32 vaddress, int length);
+static void pmaz_dma_init_write(struct NCR_ESP *esp, u32 vaddress, int length);
+static void pmaz_dma_ints_off(struct NCR_ESP *esp);
+static void pmaz_dma_ints_on(struct NCR_ESP *esp);
+static void pmaz_dma_setup(struct NCR_ESP *esp, u32 addr, int count, int write);
+static void pmaz_dma_mmu_get_scsi_one(struct NCR_ESP *esp, struct scsi_cmnd * sp);
+
+#define TC_ESP_RAM_SIZE 0x20000
+#define ESP_TGT_DMA_SIZE ((TC_ESP_RAM_SIZE/7) & ~(sizeof(int)-1))
+#define ESP_NCMD 7
+
+#define TC_ESP_DMAR_MASK 0x1ffff
+#define TC_ESP_DMAR_WRITE 0x80000000
+#define TC_ESP_DMA_ADDR(x) ((unsigned)(x) & TC_ESP_DMAR_MASK)
+
+u32 esp_virt_buffer;
+int scsi_current_length;
+
+volatile unsigned char cmd_buffer[16];
+volatile unsigned char pmaz_cmd_buffer[16];
+ /* This is where all commands are put
+ * before they are trasfered to the ESP chip
+ * via PIO.
+ */
+
+static irqreturn_t scsi_dma_merr_int(int, void *);
+static irqreturn_t scsi_dma_err_int(int, void *);
+static irqreturn_t scsi_dma_int(int, void *);
+
+static struct scsi_host_template dec_esp_template = {
+ .module = THIS_MODULE,
+ .name = "NCR53C94",
+ .info = esp_info,
+ .queuecommand = esp_queue,
+ .eh_abort_handler = esp_abort,
+ .eh_bus_reset_handler = esp_reset,
+ .slave_alloc = esp_slave_alloc,
+ .slave_destroy = esp_slave_destroy,
+ .proc_info = esp_proc_info,
+ .proc_name = "dec_esp",
+ .can_queue = 7,
+ .sg_tablesize = SG_ALL,
+ .cmd_per_lun = 1,
+ .use_clustering = DISABLE_CLUSTERING,
+};
+
+static struct NCR_ESP *dec_esp_platform;
+
+/***************************************************************** Detection */
+static int dec_esp_platform_probe(void)
+{
+ struct NCR_ESP *esp;
+ int err = 0;
+
+ if (IOASIC) {
+ esp = esp_allocate(&dec_esp_template, NULL, 1);
+
+ /* Do command transfer with programmed I/O */
+ esp->do_pio_cmds = 1;
+
+ /* Required functions */
+ esp->dma_bytes_sent = &dma_bytes_sent;
+ esp->dma_can_transfer = &dma_can_transfer;
+ esp->dma_dump_state = &dma_dump_state;
+ esp->dma_init_read = &dma_init_read;
+ esp->dma_init_write = &dma_init_write;
+ esp->dma_ints_off = &dma_ints_off;
+ esp->dma_ints_on = &dma_ints_on;
+ esp->dma_irq_p = &dma_irq_p;
+ esp->dma_ports_p = &dma_ports_p;
+ esp->dma_setup = &dma_setup;
+
+ /* Optional functions */
+ esp->dma_barrier = 0;
+ esp->dma_drain = &dma_drain;
+ esp->dma_invalidate = 0;
+ esp->dma_irq_entry = 0;
+ esp->dma_irq_exit = 0;
+ esp->dma_poll = 0;
+ esp->dma_reset = 0;
+ esp->dma_led_off = 0;
+ esp->dma_led_on = 0;
+
+ /* virtual DMA functions */
+ esp->dma_mmu_get_scsi_one = &dma_mmu_get_scsi_one;
+ esp->dma_mmu_get_scsi_sgl = &dma_mmu_get_scsi_sgl;
+ esp->dma_mmu_release_scsi_one = 0;
+ esp->dma_mmu_release_scsi_sgl = 0;
+ esp->dma_advance_sg = &dma_advance_sg;
+
+
+ /* SCSI chip speed */
+ esp->cfreq = 25000000;
+
+ esp->dregs = 0;
+
+ /* ESP register base */
+ esp->eregs = (void *)CKSEG1ADDR(dec_kn_slot_base +
+ IOASIC_SCSI);
+
+ /* Set the command buffer */
+ esp->esp_command = (volatile unsigned char *) cmd_buffer;
+
+ /* get virtual dma address for command buffer */
+ esp->esp_command_dvma = virt_to_phys(cmd_buffer);
+
+ esp->irq = dec_interrupt[DEC_IRQ_ASC];
+
+ esp->scsi_id = 7;
+
+ /* Check for differential SCSI-bus */
+ esp->diff = 0;
+
+ err = request_irq(esp->irq, esp_intr, IRQF_DISABLED,
+ "ncr53c94", esp->ehost);
+ if (err)
+ goto err_alloc;
+ err = request_irq(dec_interrupt[DEC_IRQ_ASC_MERR],
+ scsi_dma_merr_int, IRQF_DISABLED,
+ "ncr53c94 error", esp->ehost);
+ if (err)
+ goto err_irq;
+ err = request_irq(dec_interrupt[DEC_IRQ_ASC_ERR],
+ scsi_dma_err_int, IRQF_DISABLED,
+ "ncr53c94 overrun", esp->ehost);
+ if (err)
+ goto err_irq_merr;
+ err = request_irq(dec_interrupt[DEC_IRQ_ASC_DMA], scsi_dma_int,
+ IRQF_DISABLED, "ncr53c94 dma", esp->ehost);
+ if (err)
+ goto err_irq_err;
+
+ esp_initialize(esp);
+
+ err = scsi_add_host(esp->ehost, NULL);
+ if (err) {
+ printk(KERN_ERR "ESP: Unable to register adapter\n");
+ goto err_irq_dma;
+ }
+
+ scsi_scan_host(esp->ehost);
+
+ dec_esp_platform = esp;
+ }
+
+ return 0;
+
+err_irq_dma:
+ free_irq(dec_interrupt[DEC_IRQ_ASC_DMA], esp->ehost);
+err_irq_err:
+ free_irq(dec_interrupt[DEC_IRQ_ASC_ERR], esp->ehost);
+err_irq_merr:
+ free_irq(dec_interrupt[DEC_IRQ_ASC_MERR], esp->ehost);
+err_irq:
+ free_irq(esp->irq, esp->ehost);
+err_alloc:
+ esp_deallocate(esp);
+ scsi_host_put(esp->ehost);
+ return err;
+}
+
+static int __init dec_esp_probe(struct device *dev)
+{
+ struct NCR_ESP *esp;
+ resource_size_t start, len;
+ int err;
+
+ esp = esp_allocate(&dec_esp_template, NULL, 1);
+
+ dev_set_drvdata(dev, esp);
+
+ start = to_tc_dev(dev)->resource.start;
+ len = to_tc_dev(dev)->resource.end - start + 1;
+
+ if (!request_mem_region(start, len, dev->bus_id)) {
+ printk(KERN_ERR "%s: Unable to reserve MMIO resource\n",
+ dev->bus_id);
+ err = -EBUSY;
+ goto err_alloc;
+ }
+
+ /* Store base addr into esp struct. */
+ esp->slot = start;
+
+ esp->dregs = 0;
+ esp->eregs = (void *)CKSEG1ADDR(start + DEC_SCSI_SREG);
+ esp->do_pio_cmds = 1;
+
+ /* Set the command buffer. */
+ esp->esp_command = (volatile unsigned char *)pmaz_cmd_buffer;
+
+ /* Get virtual dma address for command buffer. */
+ esp->esp_command_dvma = virt_to_phys(pmaz_cmd_buffer);
+
+ esp->cfreq = tc_get_speed(to_tc_dev(dev)->bus);
+
+ esp->irq = to_tc_dev(dev)->interrupt;
+
+ /* Required functions. */
+ esp->dma_bytes_sent = &dma_bytes_sent;
+ esp->dma_can_transfer = &dma_can_transfer;
+ esp->dma_dump_state = &dma_dump_state;
+ esp->dma_init_read = &pmaz_dma_init_read;
+ esp->dma_init_write = &pmaz_dma_init_write;
+ esp->dma_ints_off = &pmaz_dma_ints_off;
+ esp->dma_ints_on = &pmaz_dma_ints_on;
+ esp->dma_irq_p = &dma_irq_p;
+ esp->dma_ports_p = &dma_ports_p;
+ esp->dma_setup = &pmaz_dma_setup;
+
+ /* Optional functions. */
+ esp->dma_barrier = 0;
+ esp->dma_drain = &pmaz_dma_drain;
+ esp->dma_invalidate = 0;
+ esp->dma_irq_entry = 0;
+ esp->dma_irq_exit = 0;
+ esp->dma_poll = 0;
+ esp->dma_reset = 0;
+ esp->dma_led_off = 0;
+ esp->dma_led_on = 0;
+
+ esp->dma_mmu_get_scsi_one = pmaz_dma_mmu_get_scsi_one;
+ esp->dma_mmu_get_scsi_sgl = 0;
+ esp->dma_mmu_release_scsi_one = 0;
+ esp->dma_mmu_release_scsi_sgl = 0;
+ esp->dma_advance_sg = 0;
+
+ err = request_irq(esp->irq, esp_intr, IRQF_DISABLED, "PMAZ_AA",
+ esp->ehost);
+ if (err) {
+ printk(KERN_ERR "%s: Unable to get IRQ %d\n",
+ dev->bus_id, esp->irq);
+ goto err_resource;
+ }
+
+ esp->scsi_id = 7;
+ esp->diff = 0;
+ esp_initialize(esp);
+
+ err = scsi_add_host(esp->ehost, dev);
+ if (err) {
+ printk(KERN_ERR "%s: Unable to register adapter\n",
+ dev->bus_id);
+ goto err_irq;
+ }
+
+ scsi_scan_host(esp->ehost);
+
+ return 0;
+
+err_irq:
+ free_irq(esp->irq, esp->ehost);
+
+err_resource:
+ release_mem_region(start, len);
+
+err_alloc:
+ esp_deallocate(esp);
+ scsi_host_put(esp->ehost);
+ return err;
+}
+
+static void __exit dec_esp_platform_remove(void)
+{
+ struct NCR_ESP *esp = dec_esp_platform;
+
+ free_irq(esp->irq, esp->ehost);
+ esp_deallocate(esp);
+ scsi_host_put(esp->ehost);
+ dec_esp_platform = NULL;
+}
+
+static void __exit dec_esp_remove(struct device *dev)
+{
+ struct NCR_ESP *esp = dev_get_drvdata(dev);
+
+ free_irq(esp->irq, esp->ehost);
+ esp_deallocate(esp);
+ scsi_host_put(esp->ehost);
+}
+
+
+/************************************************************* DMA Functions */
+static irqreturn_t scsi_dma_merr_int(int irq, void *dev_id)
+{
+ printk("Got unexpected SCSI DMA Interrupt! < ");
+ printk("SCSI_DMA_MEMRDERR ");
+ printk(">\n");
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t scsi_dma_err_int(int irq, void *dev_id)
+{
+ /* empty */
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t scsi_dma_int(int irq, void *dev_id)
+{
+ u32 scsi_next_ptr;
+
+ scsi_next_ptr = ioasic_read(IO_REG_SCSI_DMA_P);
+
+ /* next page */
+ scsi_next_ptr = (((scsi_next_ptr >> 3) + PAGE_SIZE) & PAGE_MASK) << 3;
+ ioasic_write(IO_REG_SCSI_DMA_BP, scsi_next_ptr);
+ fast_iob();
+
+ return IRQ_HANDLED;
+}
+
+static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count)
+{
+ return fifo_count;
+}
+
+static void dma_drain(struct NCR_ESP *esp)
+{
+ u32 nw, data0, data1, scsi_data_ptr;
+ u16 *p;
+
+ nw = ioasic_read(IO_REG_SCSI_SCR);
+
+ /*
+ * Is there something in the dma buffers left?
+ */
+ if (nw) {
+ scsi_data_ptr = ioasic_read(IO_REG_SCSI_DMA_P) >> 3;
+ p = phys_to_virt(scsi_data_ptr);
+ switch (nw) {
+ case 1:
+ data0 = ioasic_read(IO_REG_SCSI_SDR0);
+ p[0] = data0 & 0xffff;
+ break;
+ case 2:
+ data0 = ioasic_read(IO_REG_SCSI_SDR0);
+ p[0] = data0 & 0xffff;
+ p[1] = (data0 >> 16) & 0xffff;
+ break;
+ case 3:
+ data0 = ioasic_read(IO_REG_SCSI_SDR0);
+ data1 = ioasic_read(IO_REG_SCSI_SDR1);
+ p[0] = data0 & 0xffff;
+ p[1] = (data0 >> 16) & 0xffff;
+ p[2] = data1 & 0xffff;
+ break;
+ default:
+ printk("Strange: %d words in dma buffer left\n", nw);
+ break;
+ }
+ }
+}
+
+static int dma_can_transfer(struct NCR_ESP *esp, struct scsi_cmnd * sp)
+{
+ return sp->SCp.this_residual;
+}
+
+static void dma_dump_state(struct NCR_ESP *esp)
+{
+}
+
+static void dma_init_read(struct NCR_ESP *esp, u32 vaddress, int length)
+{
+ u32 scsi_next_ptr, ioasic_ssr;
+ unsigned long flags;
+
+ if (vaddress & 3)
+ panic("dec_esp.c: unable to handle partial word transfers, yet...");
+
+ dma_cache_wback_inv((unsigned long) phys_to_virt(vaddress), length);
+
+ spin_lock_irqsave(&ioasic_ssr_lock, flags);
+
+ fast_mb();
+ ioasic_ssr = ioasic_read(IO_REG_SSR);
+
+ ioasic_ssr &= ~IO_SSR_SCSI_DMA_EN;
+ ioasic_write(IO_REG_SSR, ioasic_ssr);
+
+ fast_wmb();
+ ioasic_write(IO_REG_SCSI_SCR, 0);
+ ioasic_write(IO_REG_SCSI_DMA_P, vaddress << 3);
+
+ /* prepare for next page */
+ scsi_next_ptr = ((vaddress + PAGE_SIZE) & PAGE_MASK) << 3;
+ ioasic_write(IO_REG_SCSI_DMA_BP, scsi_next_ptr);
+
+ ioasic_ssr |= (IO_SSR_SCSI_DMA_DIR | IO_SSR_SCSI_DMA_EN);
+ fast_wmb();
+ ioasic_write(IO_REG_SSR, ioasic_ssr);
+
+ fast_iob();
+ spin_unlock_irqrestore(&ioasic_ssr_lock, flags);
+}
+
+static void dma_init_write(struct NCR_ESP *esp, u32 vaddress, int length)
+{
+ u32 scsi_next_ptr, ioasic_ssr;
+ unsigned long flags;
+
+ if (vaddress & 3)
+ panic("dec_esp.c: unable to handle partial word transfers, yet...");
+
+ dma_cache_wback_inv((unsigned long) phys_to_virt(vaddress), length);
+
+ spin_lock_irqsave(&ioasic_ssr_lock, flags);
+
+ fast_mb();
+ ioasic_ssr = ioasic_read(IO_REG_SSR);
+
+ ioasic_ssr &= ~(IO_SSR_SCSI_DMA_DIR | IO_SSR_SCSI_DMA_EN);
+ ioasic_write(IO_REG_SSR, ioasic_ssr);
+
+ fast_wmb();
+ ioasic_write(IO_REG_SCSI_SCR, 0);
+ ioasic_write(IO_REG_SCSI_DMA_P, vaddress << 3);
+
+ /* prepare for next page */
+ scsi_next_ptr = ((vaddress + PAGE_SIZE) & PAGE_MASK) << 3;
+ ioasic_write(IO_REG_SCSI_DMA_BP, scsi_next_ptr);
+
+ ioasic_ssr |= IO_SSR_SCSI_DMA_EN;
+ fast_wmb();
+ ioasic_write(IO_REG_SSR, ioasic_ssr);
+
+ fast_iob();
+ spin_unlock_irqrestore(&ioasic_ssr_lock, flags);
+}
+
+static void dma_ints_off(struct NCR_ESP *esp)
+{
+ disable_irq(dec_interrupt[DEC_IRQ_ASC_DMA]);
+}
+
+static void dma_ints_on(struct NCR_ESP *esp)
+{
+ enable_irq(dec_interrupt[DEC_IRQ_ASC_DMA]);
+}
+
+static int dma_irq_p(struct NCR_ESP *esp)
+{
+ return (esp->eregs->esp_status & ESP_STAT_INTR);
+}
+
+static int dma_ports_p(struct NCR_ESP *esp)
+{
+ /*
+ * FIXME: what's this good for?
+ */
+ return 1;
+}
+
+static void dma_setup(struct NCR_ESP *esp, u32 addr, int count, int write)
+{
+ /*
+ * DMA_ST_WRITE means "move data from device to memory"
+ * so when (write) is true, it actually means READ!
+ */
+ if (write)
+ dma_init_read(esp, addr, count);
+ else
+ dma_init_write(esp, addr, count);
+}
+
+static void dma_mmu_get_scsi_one(struct NCR_ESP *esp, struct scsi_cmnd * sp)
+{
+ sp->SCp.ptr = (char *)virt_to_phys(sp->request_buffer);
+}
+
+static void dma_mmu_get_scsi_sgl(struct NCR_ESP *esp, struct scsi_cmnd * sp)
+{
+ int sz = sp->SCp.buffers_residual;
+ struct scatterlist *sg = sp->SCp.buffer;
+
+ while (sz >= 0) {
+ sg[sz].dma_address = page_to_phys(sg[sz].page) + sg[sz].offset;
+ sz--;
+ }
+ sp->SCp.ptr = (char *)(sp->SCp.buffer->dma_address);
+}
+
+static void dma_advance_sg(struct scsi_cmnd * sp)
+{
+ sp->SCp.ptr = (char *)(sp->SCp.buffer->dma_address);
+}
+
+static void pmaz_dma_drain(struct NCR_ESP *esp)
+{
+ memcpy(phys_to_virt(esp_virt_buffer),
+ (void *)CKSEG1ADDR(esp->slot + DEC_SCSI_SRAM +
+ ESP_TGT_DMA_SIZE),
+ scsi_current_length);
+}
+
+static void pmaz_dma_init_read(struct NCR_ESP *esp, u32 vaddress, int length)
+{
+ volatile u32 *dmareg =
+ (volatile u32 *)CKSEG1ADDR(esp->slot + DEC_SCSI_DMAREG);
+
+ if (length > ESP_TGT_DMA_SIZE)
+ length = ESP_TGT_DMA_SIZE;
+
+ *dmareg = TC_ESP_DMA_ADDR(ESP_TGT_DMA_SIZE);
+
+ iob();
+
+ esp_virt_buffer = vaddress;
+ scsi_current_length = length;
+}
+
+static void pmaz_dma_init_write(struct NCR_ESP *esp, u32 vaddress, int length)
+{
+ volatile u32 *dmareg =
+ (volatile u32 *)CKSEG1ADDR(esp->slot + DEC_SCSI_DMAREG);
+
+ memcpy((void *)CKSEG1ADDR(esp->slot + DEC_SCSI_SRAM +
+ ESP_TGT_DMA_SIZE),
+ phys_to_virt(vaddress), length);
+
+ wmb();
+ *dmareg = TC_ESP_DMAR_WRITE | TC_ESP_DMA_ADDR(ESP_TGT_DMA_SIZE);
+
+ iob();
+}
+
+static void pmaz_dma_ints_off(struct NCR_ESP *esp)
+{
+}
+
+static void pmaz_dma_ints_on(struct NCR_ESP *esp)
+{
+}
+
+static void pmaz_dma_setup(struct NCR_ESP *esp, u32 addr, int count, int write)
+{
+ /*
+ * DMA_ST_WRITE means "move data from device to memory"
+ * so when (write) is true, it actually means READ!
+ */
+ if (write)
+ pmaz_dma_init_read(esp, addr, count);
+ else
+ pmaz_dma_init_write(esp, addr, count);
+}
+
+static void pmaz_dma_mmu_get_scsi_one(struct NCR_ESP *esp, struct scsi_cmnd * sp)
+{
+ sp->SCp.ptr = (char *)virt_to_phys(sp->request_buffer);
+}
+
+
+#ifdef CONFIG_TC
+static int __init dec_esp_tc_probe(struct device *dev);
+static int __exit dec_esp_tc_remove(struct device *dev);
+
+static const struct tc_device_id dec_esp_tc_table[] = {
+ { "DEC ", "PMAZ-AA " },
+ { }
+};
+MODULE_DEVICE_TABLE(tc, dec_esp_tc_table);
+
+static struct tc_driver dec_esp_tc_driver = {
+ .id_table = dec_esp_tc_table,
+ .driver = {
+ .name = "dec_esp",
+ .bus = &tc_bus_type,
+ .probe = dec_esp_tc_probe,
+ .remove = __exit_p(dec_esp_tc_remove),
+ },
+};
+
+static int __init dec_esp_tc_probe(struct device *dev)
+{
+ int status = dec_esp_probe(dev);
+ if (!status)
+ get_device(dev);
+ return status;
+}
+
+static int __exit dec_esp_tc_remove(struct device *dev)
+{
+ put_device(dev);
+ dec_esp_remove(dev);
+ return 0;
+}
+#endif
+
+static int __init dec_esp_init(void)
+{
+ int status;
+
+ status = tc_register_driver(&dec_esp_tc_driver);
+ if (!status)
+ dec_esp_platform_probe();
+
+ if (nesps) {
+ pr_info("ESP: Total of %d ESP hosts found, "
+ "%d actually in use.\n", nesps, esps_in_use);
+ esps_running = esps_in_use;
+ }
+
+ return status;
+}
+
+static void __exit dec_esp_exit(void)
+{
+ dec_esp_platform_remove();
+ tc_unregister_driver(&dec_esp_tc_driver);
+}
+
+
+module_init(dec_esp_init);
+module_exit(dec_esp_exit);
diff --git a/trunk/drivers/scsi/fastlane.c b/trunk/drivers/scsi/fastlane.c
new file mode 100644
index 000000000000..4266a2139b5f
--- /dev/null
+++ b/trunk/drivers/scsi/fastlane.c
@@ -0,0 +1,421 @@
+/* fastlane.c: Driver for Phase5's Fastlane SCSI Controller.
+ *
+ * Copyright (C) 1996 Jesper Skov (jskov@cygnus.co.uk)
+ *
+ * This driver is based on the CyberStorm driver, hence the occasional
+ * reference to CyberStorm.
+ *
+ * Betatesting & crucial adjustments by
+ * Patrik Rak (prak3264@ss1000.ms.mff.cuni.cz)
+ *
+ */
+
+/* TODO:
+ *
+ * o According to the doc from laire, it is required to reset the DMA when
+ * the transfer is done. ATM we reset DMA just before every new
+ * dma_init_(read|write).
+ *
+ * 1) Figure out how to make a cleaner merge with the sparc driver with regard
+ * to the caches and the Sparc MMU mapping.
+ * 2) Make as few routines required outside the generic driver. A lot of the
+ * routines in this file used to be inline!
+ */
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "scsi.h"
+#include
+#include "NCR53C9x.h"
+
+#include
+#include
+
+#include
+#include
+
+#include
+
+/* Such day has just come... */
+#if 0
+/* Let this defined unless you really need to enable DMA IRQ one day */
+#define NODMAIRQ
+#endif
+
+/* The controller registers can be found in the Z2 config area at these
+ * offsets:
+ */
+#define FASTLANE_ESP_ADDR 0x1000001
+#define FASTLANE_DMA_ADDR 0x1000041
+
+
+/* The Fastlane DMA interface */
+struct fastlane_dma_registers {
+ volatile unsigned char cond_reg; /* DMA status (ro) [0x0000] */
+#define ctrl_reg cond_reg /* DMA control (wo) [0x0000] */
+ unsigned char dmapad1[0x3f];
+ volatile unsigned char clear_strobe; /* DMA clear (wo) [0x0040] */
+};
+
+
+/* DMA status bits */
+#define FASTLANE_DMA_MINT 0x80
+#define FASTLANE_DMA_IACT 0x40
+#define FASTLANE_DMA_CREQ 0x20
+
+/* DMA control bits */
+#define FASTLANE_DMA_FCODE 0xa0
+#define FASTLANE_DMA_MASK 0xf3
+#define FASTLANE_DMA_LED 0x10 /* HD led control 1 = on */
+#define FASTLANE_DMA_WRITE 0x08 /* 1 = write */
+#define FASTLANE_DMA_ENABLE 0x04 /* Enable DMA */
+#define FASTLANE_DMA_EDI 0x02 /* Enable DMA IRQ ? */
+#define FASTLANE_DMA_ESI 0x01 /* Enable SCSI IRQ */
+
+static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count);
+static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp);
+static void dma_dump_state(struct NCR_ESP *esp);
+static void dma_init_read(struct NCR_ESP *esp, __u32 addr, int length);
+static void dma_init_write(struct NCR_ESP *esp, __u32 vaddr, int length);
+static void dma_ints_off(struct NCR_ESP *esp);
+static void dma_ints_on(struct NCR_ESP *esp);
+static int dma_irq_p(struct NCR_ESP *esp);
+static void dma_irq_exit(struct NCR_ESP *esp);
+static void dma_led_off(struct NCR_ESP *esp);
+static void dma_led_on(struct NCR_ESP *esp);
+static int dma_ports_p(struct NCR_ESP *esp);
+static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write);
+
+static unsigned char ctrl_data = 0; /* Keep backup of the stuff written
+ * to ctrl_reg. Always write a copy
+ * to this register when writing to
+ * the hardware register!
+ */
+
+static volatile unsigned char cmd_buffer[16];
+ /* This is where all commands are put
+ * before they are transferred to the ESP chip
+ * via PIO.
+ */
+
+static inline void dma_clear(struct NCR_ESP *esp)
+{
+ struct fastlane_dma_registers *dregs =
+ (struct fastlane_dma_registers *) (esp->dregs);
+ unsigned long *t;
+
+ ctrl_data = (ctrl_data & FASTLANE_DMA_MASK);
+ dregs->ctrl_reg = ctrl_data;
+
+ t = (unsigned long *)(esp->edev);
+
+ dregs->clear_strobe = 0;
+ *t = 0 ;
+}
+
+/***************************************************************** Detection */
+int __init fastlane_esp_detect(struct scsi_host_template *tpnt)
+{
+ struct NCR_ESP *esp;
+ struct zorro_dev *z = NULL;
+ unsigned long address;
+
+ if ((z = zorro_find_device(ZORRO_PROD_PHASE5_BLIZZARD_1230_II_FASTLANE_Z3_CYBERSCSI_CYBERSTORM060, z))) {
+ unsigned long board = z->resource.start;
+ if (request_mem_region(board+FASTLANE_ESP_ADDR,
+ sizeof(struct ESP_regs), "NCR53C9x")) {
+ /* Check if this is really a fastlane controller. The problem
+ * is that also the cyberstorm and blizzard controllers use
+ * this ID value. Fortunately only Fastlane maps in Z3 space
+ */
+ if (board < 0x1000000) {
+ goto err_release;
+ }
+ esp = esp_allocate(tpnt, (void *)board + FASTLANE_ESP_ADDR, 0);
+
+ /* Do command transfer with programmed I/O */
+ esp->do_pio_cmds = 1;
+
+ /* Required functions */
+ esp->dma_bytes_sent = &dma_bytes_sent;
+ esp->dma_can_transfer = &dma_can_transfer;
+ esp->dma_dump_state = &dma_dump_state;
+ esp->dma_init_read = &dma_init_read;
+ esp->dma_init_write = &dma_init_write;
+ esp->dma_ints_off = &dma_ints_off;
+ esp->dma_ints_on = &dma_ints_on;
+ esp->dma_irq_p = &dma_irq_p;
+ esp->dma_ports_p = &dma_ports_p;
+ esp->dma_setup = &dma_setup;
+
+ /* Optional functions */
+ esp->dma_barrier = 0;
+ esp->dma_drain = 0;
+ esp->dma_invalidate = 0;
+ esp->dma_irq_entry = 0;
+ esp->dma_irq_exit = &dma_irq_exit;
+ esp->dma_led_on = &dma_led_on;
+ esp->dma_led_off = &dma_led_off;
+ esp->dma_poll = 0;
+ esp->dma_reset = 0;
+
+ /* Initialize the portBits (enable IRQs) */
+ ctrl_data = (FASTLANE_DMA_FCODE |
+#ifndef NODMAIRQ
+ FASTLANE_DMA_EDI |
+#endif
+ FASTLANE_DMA_ESI);
+
+
+ /* SCSI chip clock */
+ esp->cfreq = 40000000;
+
+
+ /* Map the physical address space into virtual kernel space */
+ address = (unsigned long)
+ z_ioremap(board, z->resource.end-board+1);
+
+ if(!address){
+ printk("Could not remap Fastlane controller memory!");
+ goto err_unregister;
+ }
+
+
+ /* The DMA registers on the Fastlane are mapped
+ * relative to the device (i.e. in the same Zorro
+ * I/O block).
+ */
+ esp->dregs = (void *)(address + FASTLANE_DMA_ADDR);
+
+ /* ESP register base */
+ esp->eregs = (struct ESP_regs *)(address + FASTLANE_ESP_ADDR);
+
+ /* Board base */
+ esp->edev = (void *) address;
+
+ /* Set the command buffer */
+ esp->esp_command = cmd_buffer;
+ esp->esp_command_dvma = virt_to_bus((void *)cmd_buffer);
+
+ esp->irq = IRQ_AMIGA_PORTS;
+ esp->slot = board+FASTLANE_ESP_ADDR;
+ if (request_irq(IRQ_AMIGA_PORTS, esp_intr, IRQF_SHARED,
+ "Fastlane SCSI", esp->ehost)) {
+ printk(KERN_WARNING "Fastlane: Could not get IRQ%d, aborting.\n", IRQ_AMIGA_PORTS);
+ goto err_unmap;
+ }
+
+ /* Controller ID */
+ esp->scsi_id = 7;
+
+ /* We don't have a differential SCSI-bus. */
+ esp->diff = 0;
+
+ dma_clear(esp);
+ esp_initialize(esp);
+
+ printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps, esps_in_use);
+ esps_running = esps_in_use;
+ return esps_in_use;
+ }
+ }
+ return 0;
+
+ err_unmap:
+ z_iounmap((void *)address);
+ err_unregister:
+ scsi_unregister (esp->ehost);
+ err_release:
+ release_mem_region(z->resource.start+FASTLANE_ESP_ADDR,
+ sizeof(struct ESP_regs));
+ return 0;
+}
+
+
+/************************************************************* DMA Functions */
+static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count)
+{
+ /* Since the Fastlane DMA is fully dedicated to the ESP chip,
+ * the number of bytes sent (to the ESP chip) equals the number
+ * of bytes in the FIFO - there is no buffering in the DMA controller.
+ * XXXX Do I read this right? It is from host to ESP, right?
+ */
+ return fifo_count;
+}
+
+static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp)
+{
+ unsigned long sz = sp->SCp.this_residual;
+ if(sz > 0xfffc)
+ sz = 0xfffc;
+ return sz;
+}
+
+static void dma_dump_state(struct NCR_ESP *esp)
+{
+ ESPLOG(("esp%d: dma -- cond_reg<%02x>\n",
+ esp->esp_id, ((struct fastlane_dma_registers *)
+ (esp->dregs))->cond_reg));
+ ESPLOG(("intreq:<%04x>, intena:<%04x>\n",
+ amiga_custom.intreqr, amiga_custom.intenar));
+}
+
+static void dma_init_read(struct NCR_ESP *esp, __u32 addr, int length)
+{
+ struct fastlane_dma_registers *dregs =
+ (struct fastlane_dma_registers *) (esp->dregs);
+ unsigned long *t;
+
+ cache_clear(addr, length);
+
+ dma_clear(esp);
+
+ t = (unsigned long *)((addr & 0x00ffffff) + esp->edev);
+
+ dregs->clear_strobe = 0;
+ *t = addr;
+
+ ctrl_data = (ctrl_data & FASTLANE_DMA_MASK) | FASTLANE_DMA_ENABLE;
+ dregs->ctrl_reg = ctrl_data;
+}
+
+static void dma_init_write(struct NCR_ESP *esp, __u32 addr, int length)
+{
+ struct fastlane_dma_registers *dregs =
+ (struct fastlane_dma_registers *) (esp->dregs);
+ unsigned long *t;
+
+ cache_push(addr, length);
+
+ dma_clear(esp);
+
+ t = (unsigned long *)((addr & 0x00ffffff) + (esp->edev));
+
+ dregs->clear_strobe = 0;
+ *t = addr;
+
+ ctrl_data = ((ctrl_data & FASTLANE_DMA_MASK) |
+ FASTLANE_DMA_ENABLE |
+ FASTLANE_DMA_WRITE);
+ dregs->ctrl_reg = ctrl_data;
+}
+
+
+static void dma_ints_off(struct NCR_ESP *esp)
+{
+ disable_irq(esp->irq);
+}
+
+static void dma_ints_on(struct NCR_ESP *esp)
+{
+ enable_irq(esp->irq);
+}
+
+static void dma_irq_exit(struct NCR_ESP *esp)
+{
+ struct fastlane_dma_registers *dregs =
+ (struct fastlane_dma_registers *) (esp->dregs);
+
+ dregs->ctrl_reg = ctrl_data & ~(FASTLANE_DMA_EDI|FASTLANE_DMA_ESI);
+#ifdef __mc68000__
+ nop();
+#endif
+ dregs->ctrl_reg = ctrl_data;
+}
+
+static int dma_irq_p(struct NCR_ESP *esp)
+{
+ struct fastlane_dma_registers *dregs =
+ (struct fastlane_dma_registers *) (esp->dregs);
+ unsigned char dma_status;
+
+ dma_status = dregs->cond_reg;
+
+ if(dma_status & FASTLANE_DMA_IACT)
+ return 0; /* not our IRQ */
+
+ /* Return non-zero if ESP requested IRQ */
+ return (
+#ifndef NODMAIRQ
+ (dma_status & FASTLANE_DMA_CREQ) &&
+#endif
+ (!(dma_status & FASTLANE_DMA_MINT)) &&
+ (esp_read(((struct ESP_regs *) (esp->eregs))->esp_status) & ESP_STAT_INTR));
+}
+
+static void dma_led_off(struct NCR_ESP *esp)
+{
+ ctrl_data &= ~FASTLANE_DMA_LED;
+ ((struct fastlane_dma_registers *)(esp->dregs))->ctrl_reg = ctrl_data;
+}
+
+static void dma_led_on(struct NCR_ESP *esp)
+{
+ ctrl_data |= FASTLANE_DMA_LED;
+ ((struct fastlane_dma_registers *)(esp->dregs))->ctrl_reg = ctrl_data;
+}
+
+static int dma_ports_p(struct NCR_ESP *esp)
+{
+ return ((amiga_custom.intenar) & IF_PORTS);
+}
+
+static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write)
+{
+ /* On the Sparc, DMA_ST_WRITE means "move data from device to memory"
+ * so when (write) is true, it actually means READ!
+ */
+ if(write){
+ dma_init_read(esp, addr, count);
+ } else {
+ dma_init_write(esp, addr, count);
+ }
+}
+
+#define HOSTS_C
+
+int fastlane_esp_release(struct Scsi_Host *instance)
+{
+#ifdef MODULE
+ unsigned long address = (unsigned long)((struct NCR_ESP *)instance->hostdata)->edev;
+ esp_deallocate((struct NCR_ESP *)instance->hostdata);
+ esp_release();
+ release_mem_region(address, sizeof(struct ESP_regs));
+ free_irq(IRQ_AMIGA_PORTS, esp_intr);
+#endif
+ return 1;
+}
+
+
+static struct scsi_host_template driver_template = {
+ .proc_name = "esp-fastlane",
+ .proc_info = esp_proc_info,
+ .name = "Fastlane SCSI",
+ .detect = fastlane_esp_detect,
+ .slave_alloc = esp_slave_alloc,
+ .slave_destroy = esp_slave_destroy,
+ .release = fastlane_esp_release,
+ .queuecommand = esp_queue,
+ .eh_abort_handler = esp_abort,
+ .eh_bus_reset_handler = esp_reset,
+ .can_queue = 7,
+ .this_id = 7,
+ .sg_tablesize = SG_ALL,
+ .cmd_per_lun = 1,
+ .use_clustering = ENABLE_CLUSTERING
+};
+
+#include "scsi_module.c"
+
+MODULE_LICENSE("GPL");
diff --git a/trunk/drivers/scsi/iscsi_tcp.c b/trunk/drivers/scsi/iscsi_tcp.c
index 8a178674cb18..b6f99dfbb038 100644
--- a/trunk/drivers/scsi/iscsi_tcp.c
+++ b/trunk/drivers/scsi/iscsi_tcp.c
@@ -629,9 +629,8 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
int rc;
if (tcp_conn->in.datalen) {
- iscsi_conn_printk(KERN_ERR, conn,
- "invalid R2t with datalen %d\n",
- tcp_conn->in.datalen);
+ printk(KERN_ERR "iscsi_tcp: invalid R2t with datalen %d\n",
+ tcp_conn->in.datalen);
return ISCSI_ERR_DATALEN;
}
@@ -645,9 +644,8 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
iscsi_update_cmdsn(session, (struct iscsi_nopin*)rhdr);
if (!ctask->sc || session->state != ISCSI_STATE_LOGGED_IN) {
- iscsi_conn_printk(KERN_INFO, conn,
- "dropping R2T itt %d in recovery.\n",
- ctask->itt);
+ printk(KERN_INFO "iscsi_tcp: dropping R2T itt %d in "
+ "recovery...\n", ctask->itt);
return 0;
}
@@ -657,8 +655,7 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
r2t->exp_statsn = rhdr->statsn;
r2t->data_length = be32_to_cpu(rhdr->data_length);
if (r2t->data_length == 0) {
- iscsi_conn_printk(KERN_ERR, conn,
- "invalid R2T with zero data len\n");
+ printk(KERN_ERR "iscsi_tcp: invalid R2T with zero data len\n");
__kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t,
sizeof(void*));
return ISCSI_ERR_DATALEN;
@@ -671,10 +668,9 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
r2t->data_offset = be32_to_cpu(rhdr->data_offset);
if (r2t->data_offset + r2t->data_length > scsi_bufflen(ctask->sc)) {
- iscsi_conn_printk(KERN_ERR, conn,
- "invalid R2T with data len %u at offset %u "
- "and total length %d\n", r2t->data_length,
- r2t->data_offset, scsi_bufflen(ctask->sc));
+ printk(KERN_ERR "iscsi_tcp: invalid R2T with data len %u at "
+ "offset %u and total length %d\n", r2t->data_length,
+ r2t->data_offset, scsi_bufflen(ctask->sc));
__kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t,
sizeof(void*));
return ISCSI_ERR_DATALEN;
@@ -740,9 +736,8 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
/* verify PDU length */
tcp_conn->in.datalen = ntoh24(hdr->dlength);
if (tcp_conn->in.datalen > conn->max_recv_dlength) {
- iscsi_conn_printk(KERN_ERR, conn,
- "iscsi_tcp: datalen %d > %d\n",
- tcp_conn->in.datalen, conn->max_recv_dlength);
+ printk(KERN_ERR "iscsi_tcp: datalen %d > %d\n",
+ tcp_conn->in.datalen, conn->max_recv_dlength);
return ISCSI_ERR_DATALEN;
}
@@ -824,12 +819,10 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
* For now we fail until we find a vendor that needs it
*/
if (ISCSI_DEF_MAX_RECV_SEG_LEN < tcp_conn->in.datalen) {
- iscsi_conn_printk(KERN_ERR, conn,
- "iscsi_tcp: received buffer of "
- "len %u but conn buffer is only %u "
- "(opcode %0x)\n",
- tcp_conn->in.datalen,
- ISCSI_DEF_MAX_RECV_SEG_LEN, opcode);
+ printk(KERN_ERR "iscsi_tcp: received buffer of len %u "
+ "but conn buffer is only %u (opcode %0x)\n",
+ tcp_conn->in.datalen,
+ ISCSI_DEF_MAX_RECV_SEG_LEN, opcode);
rc = ISCSI_ERR_PROTO;
break;
}
@@ -1503,25 +1496,30 @@ iscsi_tcp_conn_create(struct iscsi_cls_session *cls_session, uint32_t conn_idx)
tcp_conn->tx_hash.tfm = crypto_alloc_hash("crc32c", 0,
CRYPTO_ALG_ASYNC);
tcp_conn->tx_hash.flags = 0;
- if (IS_ERR(tcp_conn->tx_hash.tfm))
+ if (IS_ERR(tcp_conn->tx_hash.tfm)) {
+ printk(KERN_ERR "Could not create connection due to crc32c "
+ "loading error %ld. Make sure the crc32c module is "
+ "built as a module or into the kernel\n",
+ PTR_ERR(tcp_conn->tx_hash.tfm));
goto free_tcp_conn;
+ }
tcp_conn->rx_hash.tfm = crypto_alloc_hash("crc32c", 0,
CRYPTO_ALG_ASYNC);
tcp_conn->rx_hash.flags = 0;
- if (IS_ERR(tcp_conn->rx_hash.tfm))
+ if (IS_ERR(tcp_conn->rx_hash.tfm)) {
+ printk(KERN_ERR "Could not create connection due to crc32c "
+ "loading error %ld. Make sure the crc32c module is "
+ "built as a module or into the kernel\n",
+ PTR_ERR(tcp_conn->rx_hash.tfm));
goto free_tx_tfm;
+ }
return cls_conn;
free_tx_tfm:
crypto_free_hash(tcp_conn->tx_hash.tfm);
free_tcp_conn:
- iscsi_conn_printk(KERN_ERR, conn,
- "Could not create connection due to crc32c "
- "loading error. Make sure the crc32c "
- "module is built as a module or into the "
- "kernel\n");
kfree(tcp_conn);
tcp_conn_alloc_fail:
iscsi_conn_teardown(cls_conn);
@@ -1629,8 +1627,7 @@ iscsi_tcp_conn_bind(struct iscsi_cls_session *cls_session,
/* lookup for existing socket */
sock = sockfd_lookup((int)transport_eph, &err);
if (!sock) {
- iscsi_conn_printk(KERN_ERR, conn,
- "sockfd_lookup failed %d\n", err);
+ printk(KERN_ERR "iscsi_tcp: sockfd_lookup failed %d\n", err);
return -EEXIST;
}
/*
diff --git a/trunk/drivers/scsi/libiscsi.c b/trunk/drivers/scsi/libiscsi.c
index 59f8445eab0d..553168ae44f1 100644
--- a/trunk/drivers/scsi/libiscsi.c
+++ b/trunk/drivers/scsi/libiscsi.c
@@ -160,7 +160,7 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
hdr->opcode = ISCSI_OP_SCSI_CMD;
hdr->flags = ISCSI_ATTR_SIMPLE;
int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun);
- hdr->itt = build_itt(ctask->itt, session->age);
+ hdr->itt = build_itt(ctask->itt, conn->id, session->age);
hdr->data_length = cpu_to_be32(scsi_bufflen(sc));
hdr->cmdsn = cpu_to_be32(session->cmdsn);
session->cmdsn++;
@@ -416,9 +416,8 @@ static void iscsi_scsi_cmd_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
if (datalen < 2) {
invalid_datalen:
- iscsi_conn_printk(KERN_ERR, conn,
- "Got CHECK_CONDITION but invalid data "
- "buffer size of %d\n", datalen);
+ printk(KERN_ERR "iscsi: Got CHECK_CONDITION but "
+ "invalid data buffer size of %d\n", datalen);
sc->result = DID_BAD_TARGET << 16;
goto out;
}
@@ -495,7 +494,7 @@ static void iscsi_send_nopout(struct iscsi_conn *conn, struct iscsi_nopin *rhdr)
mtask = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)&hdr, NULL, 0);
if (!mtask) {
- iscsi_conn_printk(KERN_ERR, conn, "Could not send nopout\n");
+ printk(KERN_ERR "Could not send nopout\n");
return;
}
@@ -523,10 +522,9 @@ static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
if (ntoh24(reject->dlength) >= sizeof(struct iscsi_hdr)) {
memcpy(&rejected_pdu, data, sizeof(struct iscsi_hdr));
itt = get_itt(rejected_pdu.itt);
- iscsi_conn_printk(KERN_ERR, conn,
- "itt 0x%x had pdu (op 0x%x) rejected "
- "due to DataDigest error.\n", itt,
- rejected_pdu.opcode);
+ printk(KERN_ERR "itt 0x%x had pdu (op 0x%x) rejected "
+ "due to DataDigest error.\n", itt,
+ rejected_pdu.opcode);
}
}
return 0;
@@ -543,8 +541,8 @@ static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
* queuecommand or send generic. session lock must be held and verify
* itt must have been called.
*/
-static int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
- char *data, int datalen)
+int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
+ char *data, int datalen)
{
struct iscsi_session *session = conn->session;
int opcode = hdr->opcode & ISCSI_OPCODE_MASK, rc = 0;
@@ -674,6 +672,7 @@ static int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
return rc;
}
+EXPORT_SYMBOL_GPL(__iscsi_complete_pdu);
int iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
char *data, int datalen)
@@ -698,13 +697,18 @@ int iscsi_verify_itt(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
if (hdr->itt != RESERVED_ITT) {
if (((__force u32)hdr->itt & ISCSI_AGE_MASK) !=
(session->age << ISCSI_AGE_SHIFT)) {
- iscsi_conn_printk(KERN_ERR, conn,
- "received itt %x expected session "
- "age (%x)\n", (__force u32)hdr->itt,
- session->age & ISCSI_AGE_MASK);
+ printk(KERN_ERR "iscsi: received itt %x expected "
+ "session age (%x)\n", (__force u32)hdr->itt,
+ session->age & ISCSI_AGE_MASK);
return ISCSI_ERR_BAD_ITT;
}
+ if (((__force u32)hdr->itt & ISCSI_CID_MASK) !=
+ (conn->id << ISCSI_CID_SHIFT)) {
+ printk(KERN_ERR "iscsi: received itt %x, expected "
+ "CID (%x)\n", (__force u32)hdr->itt, conn->id);
+ return ISCSI_ERR_BAD_ITT;
+ }
itt = get_itt(hdr->itt);
} else
itt = ~0U;
@@ -713,17 +717,16 @@ int iscsi_verify_itt(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
ctask = session->cmds[itt];
if (!ctask->sc) {
- iscsi_conn_printk(KERN_INFO, conn, "dropping ctask "
- "with itt 0x%x\n", ctask->itt);
+ printk(KERN_INFO "iscsi: dropping ctask with "
+ "itt 0x%x\n", ctask->itt);
/* force drop */
return ISCSI_ERR_NO_SCSI_CMD;
}
if (ctask->sc->SCp.phase != session->age) {
- iscsi_conn_printk(KERN_ERR, conn,
- "iscsi: ctask's session age %d, "
- "expected %d\n", ctask->sc->SCp.phase,
- session->age);
+ printk(KERN_ERR "iscsi: ctask's session age %d, "
+ "expected %d\n", ctask->sc->SCp.phase,
+ session->age);
return ISCSI_ERR_SESSION_FAILED;
}
}
@@ -768,7 +771,7 @@ static void iscsi_prep_mtask(struct iscsi_conn *conn,
*/
nop->cmdsn = cpu_to_be32(session->cmdsn);
if (hdr->itt != RESERVED_ITT) {
- hdr->itt = build_itt(mtask->itt, session->age);
+ hdr->itt = build_itt(mtask->itt, conn->id, session->age);
/*
* TODO: We always use immediate, so we never hit this.
* If we start to send tmfs or nops as non-immediate then
@@ -994,7 +997,6 @@ enum {
FAILURE_SESSION_IN_RECOVERY,
FAILURE_SESSION_RECOVERY_TIMEOUT,
FAILURE_SESSION_LOGGING_OUT,
- FAILURE_SESSION_NOT_READY,
};
int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
@@ -1015,12 +1017,6 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
session = iscsi_hostdata(host->hostdata);
spin_lock(&session->lock);
- reason = iscsi_session_chkready(session_to_cls(session));
- if (reason) {
- sc->result = reason;
- goto fault;
- }
-
/*
* ISCSI_STATE_FAILED is a temp. state. The recovery
* code will decide what is best to do with command queued
@@ -1037,23 +1033,18 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
switch (session->state) {
case ISCSI_STATE_IN_RECOVERY:
reason = FAILURE_SESSION_IN_RECOVERY;
- sc->result = DID_IMM_RETRY << 16;
- break;
+ goto reject;
case ISCSI_STATE_LOGGING_OUT:
reason = FAILURE_SESSION_LOGGING_OUT;
- sc->result = DID_IMM_RETRY << 16;
- break;
+ goto reject;
case ISCSI_STATE_RECOVERY_FAILED:
reason = FAILURE_SESSION_RECOVERY_TIMEOUT;
- sc->result = DID_NO_CONNECT << 16;
break;
case ISCSI_STATE_TERMINATE:
reason = FAILURE_SESSION_TERMINATE;
- sc->result = DID_NO_CONNECT << 16;
break;
default:
reason = FAILURE_SESSION_FREED;
- sc->result = DID_NO_CONNECT << 16;
}
goto fault;
}
@@ -1061,7 +1052,6 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
conn = session->leadconn;
if (!conn) {
reason = FAILURE_SESSION_FREED;
- sc->result = DID_NO_CONNECT << 16;
goto fault;
}
@@ -1101,7 +1091,9 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
fault:
spin_unlock(&session->lock);
- debug_scsi("iscsi: cmd 0x%x is not queued (%d)\n", sc->cmnd[0], reason);
+ printk(KERN_ERR "iscsi: cmd 0x%x is not queued (%d)\n",
+ sc->cmnd[0], reason);
+ sc->result = (DID_NO_CONNECT << 16);
scsi_set_resid(sc, scsi_bufflen(sc));
sc->scsi_done(sc);
spin_lock(host->host_lock);
@@ -1168,8 +1160,7 @@ int iscsi_eh_host_reset(struct scsi_cmnd *sc)
mutex_lock(&session->eh_mutex);
spin_lock_bh(&session->lock);
if (session->state == ISCSI_STATE_LOGGED_IN)
- iscsi_session_printk(KERN_INFO, session,
- "host reset succeeded\n");
+ printk(KERN_INFO "iscsi: host reset succeeded\n");
else
goto failed;
spin_unlock_bh(&session->lock);
@@ -1248,8 +1239,7 @@ static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn,
* Fail commands. session lock held and recv side suspended and xmit
* thread flushed
*/
-static void fail_all_commands(struct iscsi_conn *conn, unsigned lun,
- int error)
+static void fail_all_commands(struct iscsi_conn *conn, unsigned lun)
{
struct iscsi_cmd_task *ctask, *tmp;
@@ -1261,7 +1251,7 @@ static void fail_all_commands(struct iscsi_conn *conn, unsigned lun,
if (lun == ctask->sc->device->lun || lun == -1) {
debug_scsi("failing pending sc %p itt 0x%x\n",
ctask->sc, ctask->itt);
- fail_command(conn, ctask, error << 16);
+ fail_command(conn, ctask, DID_BUS_BUSY << 16);
}
}
@@ -1269,7 +1259,7 @@ static void fail_all_commands(struct iscsi_conn *conn, unsigned lun,
if (lun == ctask->sc->device->lun || lun == -1) {
debug_scsi("failing requeued sc %p itt 0x%x\n",
ctask->sc, ctask->itt);
- fail_command(conn, ctask, error << 16);
+ fail_command(conn, ctask, DID_BUS_BUSY << 16);
}
}
@@ -1367,10 +1357,10 @@ static void iscsi_check_transport_timeouts(unsigned long data)
last_recv = conn->last_recv;
if (time_before_eq(last_recv + timeout + (conn->ping_timeout * HZ),
jiffies)) {
- iscsi_conn_printk(KERN_ERR, conn, "ping timeout of %d secs "
- "expired, last rx %lu, last ping %lu, "
- "now %lu\n", conn->ping_timeout, last_recv,
- conn->last_ping, jiffies);
+ printk(KERN_ERR "ping timeout of %d secs expired, "
+ "last rx %lu, last ping %lu, now %lu\n",
+ conn->ping_timeout, last_recv,
+ conn->last_ping, jiffies);
spin_unlock(&session->lock);
iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
return;
@@ -1383,11 +1373,14 @@ static void iscsi_check_transport_timeouts(unsigned long data)
iscsi_send_nopout(conn, NULL);
}
next_timeout = last_recv + timeout + (conn->ping_timeout * HZ);
- } else
+ } else {
next_timeout = last_recv + timeout;
+ }
- debug_scsi("Setting next tmo %lu\n", next_timeout);
- mod_timer(&conn->transport_timer, next_timeout);
+ if (next_timeout) {
+ debug_scsi("Setting next tmo %lu\n", next_timeout);
+ mod_timer(&conn->transport_timer, next_timeout);
+ }
done:
spin_unlock(&session->lock);
}
@@ -1580,7 +1573,7 @@ int iscsi_eh_device_reset(struct scsi_cmnd *sc)
/* need to grab the recv lock then session lock */
write_lock_bh(conn->recv_lock);
spin_lock(&session->lock);
- fail_all_commands(conn, sc->device->lun, DID_ERROR);
+ fail_all_commands(conn, sc->device->lun);
conn->tmf_state = TMF_INITIAL;
spin_unlock(&session->lock);
write_unlock_bh(conn->recv_lock);
@@ -1951,10 +1944,9 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
}
spin_unlock_irqrestore(session->host->host_lock, flags);
msleep_interruptible(500);
- iscsi_conn_printk(KERN_INFO, conn, "iscsi conn_destroy(): "
- "host_busy %d host_failed %d\n",
- session->host->host_busy,
- session->host->host_failed);
+ printk(KERN_INFO "iscsi: scsi conn_destroy(): host_busy %d "
+ "host_failed %d\n", session->host->host_busy,
+ session->host->host_failed);
/*
* force eh_abort() to unblock
*/
@@ -1983,28 +1975,27 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn)
struct iscsi_session *session = conn->session;
if (!session) {
- iscsi_conn_printk(KERN_ERR, conn,
- "can't start unbound connection\n");
+ printk(KERN_ERR "iscsi: can't start unbound connection\n");
return -EPERM;
}
if ((session->imm_data_en || !session->initial_r2t_en) &&
session->first_burst > session->max_burst) {
- iscsi_conn_printk(KERN_INFO, conn, "invalid burst lengths: "
- "first_burst %d max_burst %d\n",
- session->first_burst, session->max_burst);
+ printk("iscsi: invalid burst lengths: "
+ "first_burst %d max_burst %d\n",
+ session->first_burst, session->max_burst);
return -EINVAL;
}
if (conn->ping_timeout && !conn->recv_timeout) {
- iscsi_conn_printk(KERN_ERR, conn, "invalid recv timeout of "
- "zero. Using 5 seconds\n.");
+ printk(KERN_ERR "iscsi: invalid recv timeout of zero "
+ "Using 5 seconds\n.");
conn->recv_timeout = 5;
}
if (conn->recv_timeout && !conn->ping_timeout) {
- iscsi_conn_printk(KERN_ERR, conn, "invalid ping timeout of "
- "zero. Using 5 seconds.\n");
+ printk(KERN_ERR "iscsi: invalid ping timeout of zero "
+ "Using 5 seconds.\n");
conn->ping_timeout = 5;
}
@@ -2028,9 +2019,11 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn)
conn->stop_stage = 0;
conn->tmf_state = TMF_INITIAL;
session->age++;
- if (session->age == 16)
- session->age = 0;
- break;
+ spin_unlock_bh(&session->lock);
+
+ iscsi_unblock_session(session_to_cls(session));
+ wake_up(&conn->ehwait);
+ return 0;
case STOP_CONN_TERM:
conn->stop_stage = 0;
break;
@@ -2039,8 +2032,6 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn)
}
spin_unlock_bh(&session->lock);
- iscsi_unblock_session(session_to_cls(session));
- wake_up(&conn->ehwait);
return 0;
}
EXPORT_SYMBOL_GPL(iscsi_conn_start);
@@ -2132,8 +2123,7 @@ static void iscsi_start_session_recovery(struct iscsi_session *session,
* flush queues.
*/
spin_lock_bh(&session->lock);
- fail_all_commands(conn, -1,
- STOP_CONN_RECOVER ? DID_BUS_BUSY : DID_ERROR);
+ fail_all_commands(conn, -1);
flush_control_queues(session, conn);
spin_unlock_bh(&session->lock);
mutex_unlock(&session->eh_mutex);
@@ -2150,8 +2140,7 @@ void iscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag)
iscsi_start_session_recovery(session, conn, flag);
break;
default:
- iscsi_conn_printk(KERN_ERR, conn,
- "invalid stop flag %d\n", flag);
+ printk(KERN_ERR "iscsi: invalid stop flag %d\n", flag);
}
}
EXPORT_SYMBOL_GPL(iscsi_conn_stop);
diff --git a/trunk/drivers/scsi/mac_esp.c b/trunk/drivers/scsi/mac_esp.c
new file mode 100644
index 000000000000..bcb49021b7e2
--- /dev/null
+++ b/trunk/drivers/scsi/mac_esp.c
@@ -0,0 +1,751 @@
+/*
+ * 68k mac 53c9[46] scsi driver
+ *
+ * copyright (c) 1998, David Weis weisd3458@uni.edu
+ *
+ * debugging on Quadra 800 and 660AV Michael Schmitz, Dave Kilzer 7/98
+ *
+ * based loosely on cyber_esp.c
+ */
+
+/* these are unused for now */
+#define myreadl(addr) (*(volatile unsigned int *) (addr))
+#define mywritel(b, addr) ((*(volatile unsigned int *) (addr)) = (b))
+
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "scsi.h"
+#include
+#include "NCR53C9x.h"
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#include
+
+/* #define DEBUG_MAC_ESP */
+
+extern void esp_handle(struct NCR_ESP *esp);
+extern void mac_esp_intr(int irq, void *dev_id);
+
+static int dma_bytes_sent(struct NCR_ESP * esp, int fifo_count);
+static int dma_can_transfer(struct NCR_ESP * esp, Scsi_Cmnd *sp);
+static void dma_dump_state(struct NCR_ESP * esp);
+static void dma_init_read(struct NCR_ESP * esp, char * vaddress, int length);
+static void dma_init_write(struct NCR_ESP * esp, char * vaddress, int length);
+static void dma_ints_off(struct NCR_ESP * esp);
+static void dma_ints_on(struct NCR_ESP * esp);
+static int dma_irq_p(struct NCR_ESP * esp);
+static int dma_irq_p_quick(struct NCR_ESP * esp);
+static void dma_led_off(struct NCR_ESP * esp);
+static void dma_led_on(struct NCR_ESP *esp);
+static int dma_ports_p(struct NCR_ESP *esp);
+static void dma_setup(struct NCR_ESP * esp, __u32 addr, int count, int write);
+static void dma_setup_quick(struct NCR_ESP * esp, __u32 addr, int count, int write);
+
+static int esp_dafb_dma_irq_p(struct NCR_ESP * espdev);
+static int esp_iosb_dma_irq_p(struct NCR_ESP * espdev);
+
+static volatile unsigned char cmd_buffer[16];
+ /* This is where all commands are put
+ * before they are transferred to the ESP chip
+ * via PIO.
+ */
+
+static int esp_initialized = 0;
+
+static int setup_num_esps = -1;
+static int setup_disconnect = -1;
+static int setup_nosync = -1;
+static int setup_can_queue = -1;
+static int setup_cmd_per_lun = -1;
+static int setup_sg_tablesize = -1;
+#ifdef SUPPORT_TAGS
+static int setup_use_tagged_queuing = -1;
+#endif
+static int setup_hostid = -1;
+
+/*
+ * Experimental ESP inthandler; check macints.c to make sure dev_id is
+ * set up properly!
+ */
+
+void mac_esp_intr(int irq, void *dev_id)
+{
+ struct NCR_ESP *esp = (struct NCR_ESP *) dev_id;
+ int irq_p = 0;
+
+ /* Handle the one ESP interrupt showing at this IRQ level. */
+ if(((esp)->irq & 0xff) == irq) {
+ /*
+ * Debug ..
+ */
+ irq_p = esp->dma_irq_p(esp);
+ printk("mac_esp: irq_p %x current %p disconnected %p\n",
+ irq_p, esp->current_SC, esp->disconnected_SC);
+
+ /*
+ * Mac: if we're here, it's an ESP interrupt for sure!
+ */
+ if((esp->current_SC || esp->disconnected_SC)) {
+ esp->dma_ints_off(esp);
+
+ ESPIRQ(("I%d(", esp->esp_id));
+ esp_handle(esp);
+ ESPIRQ((")"));
+
+ esp->dma_ints_on(esp);
+ }
+ }
+}
+
+/*
+ * Debug hooks; use for playing with the interrupt flag testing and interrupt
+ * acknowledge on the various machines
+ */
+
+void scsi_esp_polled(int irq, void *dev_id)
+{
+ if (esp_initialized == 0)
+ return;
+
+ mac_esp_intr(irq, dev_id);
+}
+
+void fake_intr(int irq, void *dev_id)
+{
+#ifdef DEBUG_MAC_ESP
+ printk("mac_esp: got irq\n");
+#endif
+
+ mac_esp_intr(irq, dev_id);
+}
+
+irqreturn_t fake_drq(int irq, void *dev_id)
+{
+ printk("mac_esp: got drq\n");
+ return IRQ_HANDLED;
+}
+
+#define DRIVER_SETUP
+
+/*
+ * Function : mac_esp_setup(char *str)
+ *
+ * Purpose : booter command line initialization of the overrides array,
+ *
+ * Inputs : str - parameters, separated by commas.
+ *
+ * Currently unused in the new driver; need to add settable parameters to the
+ * detect function.
+ *
+ */
+
+static int __init mac_esp_setup(char *str) {
+#ifdef DRIVER_SETUP
+ /* Format of mac53c9x parameter is:
+ * mac53c9x=