]> git.neil.brown.name Git - history.git/commitdiff
Import 2.0.22 2.0.22
authorAlan Cox <alan@lxorguk.ukuu.org.uk>
Fri, 23 Nov 2007 20:11:20 +0000 (15:11 -0500)
committerAlan Cox <alan@lxorguk.ukuu.org.uk>
Fri, 23 Nov 2007 20:11:20 +0000 (15:11 -0500)
38 files changed:
CREDITS
Documentation/Configure.help
Documentation/IO-mapping.txt [new file with mode: 0644]
Documentation/cdrom/ide-cd
Documentation/ide.txt
Makefile
arch/i386/kernel/process.c
arch/i386/kernel/traps.c
arch/i386/math-emu/fpu_emu.h
drivers/block/floppy.c
drivers/block/ide-tape.c
drivers/block/ide-tape.h
drivers/block/ide.c
drivers/block/ide.h
drivers/block/triton.c
drivers/char/cyclades.c
drivers/char/pcxx.c
drivers/char/pty.c
drivers/net/eql.c
drivers/net/ne.c
drivers/scsi/advansys.c
drivers/scsi/advansys.h
drivers/scsi/ncr53c8xx.c
drivers/scsi/scsi.c
drivers/scsi/st.c
drivers/sound/audio.c
drivers/sound/configure.c
include/linux/icmp.h
init/main.c
kernel/fork.c
net/bridge/br.c
net/ipv4/arp.c
net/ipv4/icmp.c
net/ipv4/raw.c
net/ipv4/tcp.c
net/ipv4/udp.c
net/unix/af_unix.c
scripts/mkdep.c

diff --git a/CREDITS b/CREDITS
index 7b7e338e7cf0e25e52f0a3aa62301db19d1e9114..873d2d70c570211ae835aa8d0e6fc804102f9fc0 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -1088,13 +1088,12 @@ E: snprobst@immd4.informatik.uni-erlangen.de
 D: The Linux Support Team Erlangen
 
 N: Daniel Quinlan
-E: Daniel.Quinlan@linux.org
-W: http://www.bucknell.edu/~quinlan
+E: quinlan@pathname.com
+W: http://www.pathname.com/~quinlan/
 D: FSSTND coordinator; FHS editor
 D: random Linux documentation, patches, and hacks
-S: Box C-5083
-S: Bucknell University
-S: Lewisburg, Pennsylvania 17837
+S: 4390 Albany Dr. #41A
+S: San Jose, California 95129
 S: USA
 
 N: Eric S. Raymond
index 53a77a5b26c8ba4563f9e5bb7412f2837e696195..bda2615581dbf51446d525e5143bd2a3e6c01cac 100644 (file)
@@ -3,13 +3,12 @@
 # This version of the Linux kernel configuration help texts
 # corresponds to the kernel versions 2.0.x.
 #
-# International versions available on the WWW:
-#   - http://www.eis.or.jp/muse/kikutani/Configure.help-1.2.x.euc 
-# is a Japanese translation of a previous version of this file,
-# written by kikutani@eis.or.jp.
+# International versions of this file available on the WWW:
+#   - http://jf.gee.kyoto-u.ac.jp/JF/JF-ftp/euc/Configure.help.euc
+# is a Japanese translation, maintained by Tetsuyasu YAMADA
+# (tetsu@cauchy.nslab.ntt.jp). 
 #   - http://nevod.perm.su/service/linux/doc/kernel/Configure.help 
-# is a Russian translation of this file, maintained by
-# kaf@linux.nevod.perm.su.
+# is a Russian translation, maintained by kaf@linux.nevod.perm.su.
 #
 # Information about what a kernel is, what it does, how to patch and
 # compile it and much more is contained in the Kernel-HOWTO, available
@@ -115,18 +114,15 @@ CONFIG_BLK_DEV_INITRD
 
 Loop device support
 CONFIG_BLK_DEV_LOOP
-  Enabling this option will allow you to mount a file as a file system.
-  This is useful if you want to check an ISO9660 file system before
-  burning the CD, or want to use floppy images without first writing
-  them to floppy.
-  This option also allows one to mount a filesystem with encryption.
-  To use these features, you need a recent version of mount, such as
-  the one found at ftp.win.tue.nl:/pub/linux/util/mount-2.5X.tar.gz.
-  If you want to use encryption, you might also be interested in the
-  (old) DES package ftp.funet.fi:/pub/OS/Linux/BETA/loop/des.1.tar.gz.
-  Note that this loop device has nothing to do with the loopback
-  device used for network connections from the machine to itself.
-  Most users will answer N here.
+  Enabling this option will allow you to mount a file as a file
+  system.  This is useful if you want to check an ISO9660 file system
+  before burning the CD, or want to use floppy images without first
+  writing them to floppy.  This option also allows one to mount a
+  filesystem with encryption.  To use these features, you need a
+  recent version of mount (check the file Documentation/Changes for
+  location and latest version).  Note that this loop device has
+  nothing to do with the loopback device used for network connections
+  from the machine to itself.  Most users will answer N here.
 
 Enhanced IDE/MFM/RLL disk/cdrom/tape support
 CONFIG_BLK_DEV_IDE 
@@ -566,10 +562,9 @@ CONFIG_BLK_DEV_TRITON
   If your PCI system uses an IDE harddrive (as opposed to SCSI, say)
   and includes the Intel 430FX PCI Triton chipset, you will want to
   enable this option to allow use of bus-mastering DMA data transfers.
-  Read the comments at the beginning of drivers/block/triton.c.  The
-  hdparm utility can be obtained via ftp (user: anonymous) from
-  sunsite.unc.edu:/pub/Linux/kernel/patches/diskdrives/.  It is safe
-  to say Y.
+  Read the comments at the beginning of drivers/block/triton.c.  Check
+  the file Documentation/Changes for location and latest version of
+  the hdparm utility. It is safe to say Y to this question.
 
 System V IPC
 CONFIG_SYSVIPC
@@ -593,56 +588,55 @@ CONFIG_BINFMT_ELF
   executables used across different architectures and operating
   systems. This option will enable your kernel to run ELF binaries and
   enlarge it by about 2kB. ELF support under Linux is quickly
-  replacing the traditional Linux a.out format because it is portable
-  (this does *not* mean that you will be able to run executables from
-  different architectures or operating systems!) and makes building
-  run-time libraries very easy. Many new executables are distributed
-  solely in ELF format. You definitely want to say Y here. Information
-  about ELF is on the WWW at
+  replacing the traditional Linux a.out formats (QMAGIC and ZMAGIC)
+  because it is portable (this does *not* mean that you will be able
+  to run executables from different architectures or operating
+  systems!) and makes building run-time libraries very easy. Many new
+  executables are distributed solely in ELF format. You definitely
+  want to say Y here. Information about ELF is on the WWW at
   http://www.sjc.ox.ac.uk/users/barlow/elf-howto.html (To browse the
   WWW, you need to have access to a machine on the Internet that has
   one of the programs lynx, netscape or Mosaic).  If you find that
   after upgrading to Linux kernel 1.3 and saying Y here, you still
   can't run any ELF binaries (they just crash), then you'll have to
-  install the newest ELF runtime libraries, including ld.so (available
-  via ftp (user: anonymous) from
-  tsx-11.mit.edu:/pub/linux/packages/GCC). Also note that ELF binary
-  support was broken in kernel versions 1.3.0 - 1.3.2. Either use a
-  newer 1.3 kernel or one of the stable 1.2 versions. If you want to
-  compile this as a module ( = code which can be inserted in and
-  removed from the running kernel whenever you want), say M here and
-  read Documentation/modules.txt. Saying M or N here is dangerous
-  because some crucial programs on your system might be in ELF
-  format. 
+  install the newest ELF runtime libraries, including ld.so (check the
+  file Documentation/Changes for location and latest version). If you
+  want to compile this as a module ( = code which can be inserted in
+  and removed from the running kernel whenever you want), say M here
+  and read Documentation/modules.txt. Saying M or N here is dangerous
+  because some crucial programs on your system might be in ELF format.
 
 Compile kernel as ELF - if your GCC is ELF-GCC
 CONFIG_KERNEL_ELF
   The gcc version 2.7.0 and newer produces the new ELF binary format
-  as default. If you have such a compiler (try "gcc -v"), say Y
-  here, otherwise N.
+  as default. If you have such a compiler (try "gcc -v"), say Y here,
+  otherwise N.  
   It is possible, albeit almost pointless, to compile the kernel in
-  a.out format even if your compiler produces ELF as default. For
-  that, you would have to say N here and change the variables LD and
-  CC in the toplevel Makefile. Similarly, if your compiler produces
-  a.out by default but is able to produce ELF, you can compile the
-  kernel in ELF by saying Y here and editing the variables CC
-  and LD in the toplevel Makefile.
+  a.out (i.e. QMAGIC) format even if your compiler produces ELF as
+  default. For that, you would have to say N here and change the
+  variables LD and CC in the toplevel Makefile. Similarly, if your
+  compiler produces a.out by default but is able to produce ELF, you
+  can compile the kernel in ELF by saying Y here and editing the
+  variables CC and LD in the toplevel Makefile.
 
 Kernel support for A.OUT binaries
 CONFIG_BINFMT_AOUT
-  A.OUT (Assembler.OUTput) format is a format for libraries and
-  executables used in the earliest versions of UNIX. Linux used this
-  format until it was replaced with the ELF format.
-  As more and more programs are converted to ELF, the use for A.OUT
+  A.out (Assembler.OUTput) is a set of formats for libraries and
+  executables used in the earliest versions of UNIX. Linux used the
+  a.out formats QMAGIC and ZMAGIC until they were replaced with the
+  ELF format.
+  As more and more programs are converted to ELF, the use for a.out
   will gradually diminish. If you disable this option it will reduce
   your kernel by one page. This is not much and by itself does not
-  warrant removing support. However its removal is a good idea when
-  you wish to ensure that absolutely none of your programs will use
-  this older executable format. If you don't know what to answer at
-  this point then answer Y. You may answer M for module support and
-  later load the module when you find a program which needs a.out
-  format. Saying M or N here is dangerous, because some crucial
-  programs on your system might be in A.OUT format.
+  warrant removing support. However its removal is a good idea if you
+  wish to ensure that absolutely none of your programs will use this
+  older executable format. If you don't know what to answer at this
+  point then answer Y. If someone told you "You need a kernel with
+  QMAGIC support" then you'll have to say Y here. You may answer M 
+  to compile a.out support as a module and later load the module when
+  you want to use a program or library in a.out format. Saying M or N
+  here is dangerous though, because some crucial programs on your
+  system might still be in A.OUT format.
 
 Kernel support for JAVA binaries
 CONFIG_BINFMT_JAVA
@@ -664,7 +658,7 @@ CONFIG_BINFMT_JAVA
   warrant removing support. However its removal is a good idea if you
   do not have the JDK installed. If you don't know what to answer at
   this point then answer Y. You may answer M for module support and
-  later load the module when you install the JDK or find a interesting
+  later load the module when you install the JDK or find an interesting
   Java program that you can't live without.
 
 Processor type
@@ -699,7 +693,7 @@ CONFIG_CPU_LITTLE_ENDIAN
   opposed to mips-linux-gcc or mips-linuxelf-gcc), say Y here,
   otherwise N. Most MIPS machines use little-endian code, but it might
   be necessary to run older Mips systems, such as the Sony News and
-  MIPS RC3xxx in big endian mode.
+  MIPS RC3xxx, in big endian mode.
 
 Enable loadable module support
 CONFIG_MODULES
@@ -717,14 +711,13 @@ CONFIG_MODVERSIONS
   kernel. Enabling this option makes it possible, and safe, to use the
   same modules even after compiling a new kernel; this requires the
   program modprobe. All the software needed for module support is in
-  the modules package in sunsite.unc.edu:/pub/Linux/kernel, available
-  via ftp (user: anonymous) to be extracted with "tar xzvf filename".
-  NOTE: if you say Y here but don't have the program genksyms (which
-  is also contained in the above mentioned modules package), then the
-  building of your kernel will fail.
-  If you are going to use modules that are generated from non-kernel
-  sources, you would benefit from this option. Otherwise it's not that
-  important. So, N ought to be a safe bet.
+  the modules package (check the file Documentation/Changes for
+  location and latest version).  NOTE: if you say Y here but don't
+  have the program genksyms (which is also contained in the above
+  mentioned modules package), then the building of your kernel will
+  fail.  If you are going to use modules that are generated from
+  non-kernel sources, you would benefit from this option. Otherwise
+  it's not that important. So, N ought to be a safe bet.
 
 Kernel daemon support
 CONFIG_KERNELD
@@ -840,19 +833,20 @@ CONFIG_IP_FIREWALL
   about 2kB. You may need to read the FIREWALL-HOWTO, available via
   ftp (user: anonymous) in
   sunsite.unc.edu:/pub/Linux/docs/HOWTO. Also, you will need the
-  ipfwadm tool (available via ftp (user: anonymous) from ftp.xos.nl) 
-  to allow selective blocking of internet traffic based
-  on type, origin and destination.  You need to enable IP firewalling
-  in order to be able to use IP masquerading (i.e. local computers can
-  chat with an outside host, but that outside host is made to think
-  that it is talking to the firewall box. Makes the local network
-  completely invisible and avoids the need to allocate valid IP host
-  addresses for the machines on the local net) or to use the IP packet
-  accounting to see what is using all your network bandwidth.
-  This option is also needed when you want to enable the transparent
-  proxying support (makes the computers on the local network think
-  they're talking to a remote computer, while in reality the traffic
-  is redirected by your Linux firewall to a local proxy server).
+  ipfwadm tool (check the file Documentation/Changes for location and
+  latest version) to allow selective blocking of internet traffic
+  based on type, origin and destination.  You need to enable IP
+  firewalling in order to be able to use IP masquerading (i.e. local
+  computers can chat with an outside host, but that outside host is
+  made to think that it is talking to the firewall box. Makes the
+  local network completely invisible and avoids the need to allocate
+  valid IP host addresses for the machines on the local net) or to use
+  the IP packet accounting to see what is using all your network
+  bandwidth.  This option is also needed when you want to enable the
+  transparent proxying support (makes the computers on the local
+  network think they're talking to a remote computer, while in reality
+  the traffic is redirected by your Linux firewall to a local proxy
+  server).
 
 IP: accounting
 CONFIG_IP_ACCT
@@ -863,7 +857,8 @@ CONFIG_IP_ACCT
   firewalling. The data is accessible with "cat /proc/net/ip_acct", so
   you want to say Y to the /proc filesystem below, if you say Y
   here. To specify what exactly should be recorded, you need the tool
-  ipfwadm (available from ftp.xos.nl if you don't have a copy already).
+  ipfwadm (check the file Documentation/Changes for location and
+  latest version).
 
 IP: tunneling
 CONFIG_NET_IPIP
@@ -977,17 +972,25 @@ CONFIG_INET_PCTCP
 
 Reverse ARP
 CONFIG_INET_RARP
-  Since you asked: if there's a diskless machine on your local network
-  that know its hardware ethernet address but doesn't know its IP
-  address upon startup, it can send out a Reverse Address Resolution
-  Protocol request to find out its own IP address. If you want your
-  Linux box to be able to *answer* such requests, say Y here; you'd
-  have to run the program rarp ("man rarp") on your box.  Superior
-  solutions to the same problem are given by the protocols BOOTP and
-  DHCP. If you want to compile RARP support as a module ( = code which
-  can be inserted in and removed from the running kernel whenever you
-  want), say M here and read Documentation/modules.txt.  If you don't
-  understand a word, say N and rest in peace.
+  Since you asked: if there are (usually diskless or portable)
+  machines on your local network that know their hardware ethernet
+  addresses but don't know their IP addresses upon startup, they can
+  send out a Reverse Address Resolution Protocol (RARP) request to
+  find out their own IP addresses. Diskless Sun 3 machines use this
+  procedure at boot time. If you want your Linux box to be able to
+  *answer* such requests, say Y here; you'd have to run the program
+  rarp ("man rarp") on your box. If you actually want to use a
+  diskless Sun 3 machine as an Xterminal to Linux, say Y here and
+  fetch Linux-Xkernel from
+  ftp://sunsite.unc.edu/pub/Linux/system/Network/boot.net/.  Superior
+  solutions to the problem of booting and configuring machines over a
+  net connection are given by the protocol BOOTP and its successor
+  DHCP. See the DHCP FAQ
+  http://web.syr.edu/~jmwobus/comfaqs/dhcp.faq.html for details.  If
+  you want to compile RARP support as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read Documentation/modules.txt.  If you don't
+  understand a word of the above, say N and rest in peace.
 
 Assume subnets are local
 CONFIG_INET_SNARL
@@ -1734,7 +1737,8 @@ CONFIG_DUMMY
   module ( = code which can be inserted in and removed from the
   running kernel whenever you want), say M here and read
   Documentation/modules.txt. If you want to use more than one dummy
-  device at a time, you need to compile it as a module.
+  device at a time, you need to compile it as a module. Instead of
+  'dummy', it will they will then be called 'dummy0', 'dummy1' etc.
   
 SLIP (serial line) support
 CONFIG_SLIP
@@ -1974,7 +1978,7 @@ CONFIG_DLCI_MAX
 
 Sangoma S502A FRAD support
 CONFIG_SDLA
-  Say Y here if you need a driver for the Sangoma S502A, S502E and
+  Say Y here if you need a driver for the Sangoma S502A, S502E, and
   S508 Frame Relay Access Devices. These are multi-protocol
   cards, but only frame relay is supported by the driver at this
   time. Please read Documentation/framerelay.txt. This driver is also
@@ -2978,25 +2982,25 @@ CONFIG_ROOT_NFS
 BOOTP support
 CONFIG_RNFS_BOOTP
   If you want your Linux box to mount its whole root filesystem from
-  some other computer over the net via NFS and you want the address
-  of your computer to be discovered automatically using the BOOTP
-  protocol (a special protocol designed for doing this job), say Y
-  here. In case the boot ROM of your network card was designed for
-  booting Linux and does BOOTP itself, providing all necessary
-  information on the kernel command line, you can say N here.
-  If unsure, say Y. Note that in case you want to use BOOTP, a BOOTP
+  some other computer over the net via NFS and you want the IP address
+  of your computer to be discovered automatically at boot time using
+  the BOOTP protocol (a special protocol designed for doing this job),
+  say Y here. In case the boot ROM of your network card was designed
+  for booting Linux and does BOOTP itself, providing all necessary
+  information on the kernel command line, you can say N here.  If
+  unsure, say Y. Note that in case you want to use BOOTP, a BOOTP
   server must be operating on your network. Read
   Documentation/nfsroot.txt for details.
 
 RARP support
 CONFIG_RNFS_RARP
   If you want your Linux box to mount its whole root filesystem from
-  some other computer over the net via NFS and you want the address
-  of your computer to be discovered automatically using the RARP
-  protocol (an older protocol which is being obsoleted by BOOTP), say
-  Y here. Note that in case you want to use RARP, a RARP server must be
-  operating on your network. Read Documentation/nfsroot.txt for
-  details. 
+  some other computer over the net via NFS and you want the IP address
+  of your computer to be discovered automatically at boot time using
+  the RARP protocol (an older protocol which is being obsoleted by
+  BOOTP), say Y here. Note that in case you want to use RARP, a RARP
+  server must be operating on your network. Read
+  Documentation/nfsroot.txt for details.
 
 ISO9660 cdrom filesystem support
 CONFIG_ISO9660_FS
diff --git a/Documentation/IO-mapping.txt b/Documentation/IO-mapping.txt
new file mode 100644 (file)
index 0000000..ceac953
--- /dev/null
@@ -0,0 +1,202 @@
+
+[ This is a mail-message in response to a query on IO mapping, thus the
+  strange format for a "document" ]
+
+The aha1542 is a bus-master device, and your patch makes the driver give the
+controller the physical address of the buffers, which is correct on x86
+(because all bus master devices see the physical memory mappings directly). 
+
+However, on many setups, there are actually _three_ different ways of looking
+at memory addresses, and in this case we actually want the third, the
+so-called "bus address". 
+
+Essentially, the three ways of addressing memory are (this is "real memory",
+ie normal RAM, see later about other details): 
+
+ - CPU untranslated. This is the "physical" address, ie physical address 
+   0 is what the CPU sees when it drives zeroes on the memory bus.
+
+ - CPU translated address. This is the "virtual" address, and is 
+   completely internal to the CPU itself with the CPU doing the appropriate
+   translations into "CPU untranslated". 
+
+ - bus address. This is the address of memory as seen by OTHER devices, 
+   not the CPU. Now, in theory there could be many different bus 
+   addresses, with each device seeing memory in some device-specific way, but
+   happily most hardware designers aren't actually actively trying to make
+   things any more complex than necessary, so you can assume that all 
+   external hardware sees the memory the same way. 
+
+Now, on normal PC's the bus address is exactly the same as the physical
+address, and things are very simple indeed. However, they are that simple
+because the memory and the devices share the same address space, and that is
+not generally necessarily true on other PCI/ISA setups. 
+
+Now, just as an example, on the PReP (PowerPC Reference Platform), the 
+CPU sees a memory map something like this (this is from memory):
+
+       0-2GB   "real memory"
+       2GB-3GB "system IO" (ie inb/out type accesses on x86)
+       3GB-4GB "IO memory" (ie shared memory over the IO bus)
+
+Now, that looks simple enough. However, when you look at the same thing from
+the viewpoint of the devices, you have the reverse, and the physical memory
+address 0 actually shows up as address 2GB for any IO master.
+
+So when the CPU wants any bus master to write to physical memory 0, it 
+has to give the master address 0x80000000 as the memory address.
+
+So, for example, depending on how the kernel is actually mapped on the 
+PPC, you can end up with a setup like this:
+
+ physical address:     0
+ virtual address:      0xC0000000
+ bus address:          0x80000000
+
+where all the addresses actually point to the same thing, it's just seen 
+through different translations..
+
+Similarly, on the alpha, the normal translation is
+
+ physical address:     0
+ virtual address:      0xfffffc0000000000
+ bus address:          0x40000000
+
+(but there are also alpha's where the physical address and the bus address
+are the same). 
+
+Anyway, the way to look up all these translations, you do
+
+       #include <asm/io.h>
+
+       phys_addr = virt_to_phys(virt_addr);
+       virt_addr = phys_to_virt(phys_addr);
+        bus_addr = virt_to_bus(virt_addr);
+       virt_addr = bus_to_virt(bus_addr);
+
+Now, when do you need these?
+
+You want the _virtual_ address when you are actually going to access that 
+pointer from the kernel. So you can have something like this:
+
+       /*
+        * this is the hardware "mailbox" we use to communicate with
+        * the controller. The controller sees this directly.
+        */
+       struct mailbox {
+               __u32 status;
+               __u32 bufstart;
+               __u32 buflen;
+               ..
+       } mbox;
+
+               unsigned char * retbuffer;
+
+               /* get the address from the controller */
+               retbuffer = bus_to_virt(mbox.bufstart);
+               switch (retbuffer[0]) {
+                       case STATUS_OK:
+                               ...
+
+on the other hand, you want the bus address when you have a buffer that 
+you want to give to the controller:
+
+       /* ask the controller to read the sense status into "sense_buffer" */
+       mbox.bufstart = virt_to_bus(&sense_buffer);
+       mbox.buflen = sizeof(sense_buffer);
+       mbox.status = 0;
+       notify_controller(&mbox);
+
+And you generally _never_ want to use the physical address, because you can't
+use that from the CPU (the CPU only uses translated virtual addresses), and
+you can't use it from the bus master. 
+
+So why do we care about the physical address at all? We do need the physical
+address in some cases, it's just not very often in normal code.  The physical
+address is needed if you use memory mappings, for example, because the
+"remap_page_range()" mm function wants the physical address of the memory to
+be remapped (the memory management layer doesn't know about devices outside
+the CPU, so it shouldn't need to know about "bus addresses" etc). 
+
+NOTE NOTE NOTE! The above is only one part of the whole equation. The above
+only talks about "real memory", ie CPU memory, ie RAM. 
+
+There is a completely different type of memory too, and that's the "shared
+memory" on the PCI or ISA bus. That's generally not RAM (although in the case
+of a video graphics card it can be normal DRAM that is just used for a frame
+buffer), but can be things like a packet buffer in a network card etc. 
+
+This memory is called "PCI memory" or "shared memory" or "IO memory" or
+whatever, and there is only one way to access it: the readb/writeb and
+related functions. You should never take the address of such memory, because
+there is really nothing you can do with such an address: it's not
+conceptually in the same memory space as "real memory" at all, so you cannot
+just dereference a pointer. (Sadly, on x86 it _is_ in the same memory space,
+so on x86 it actually works to just deference a pointer, but it's not
+portable). 
+
+For such memory, you can do things like
+
+ - reading:
+       /*
+        * read first 32 bits from ISA memory at 0xC0000, aka
+        * C000:0000 in DOS terms
+        */
+       unsigned int signature = readl(0xC0000);
+
+ - remapping and writing:
+       /*
+        * remap framebuffer PCI memory area at 0xFC000000,
+        * size 1MB, so that we can access it: We can directly
+        * access only the 640k-1MB area, so anything else
+        * has to be remapped.
+        */
+       char * baseptr = ioremap(0xFC000000, 1024*1024);
+
+       /* write a 'A' to the offset 10 of the area */
+       writeb('A',baseptr+10);
+
+       /* unmap when we unload the driver */
+       iounmap(baseptr);
+
+ - copying and clearing:
+       /* get the 6-byte ethernet address at ISA address E000:0040 */
+       memcpy_fromio(kernel_buffer, 0xE0040, 6);
+       /* write a packet to the driver */
+       memcpy_toio(0xE1000, skb->data, skb->len);
+       /* clear the frame buffer */
+       memset_io(0xA0000, 0, 0x10000);
+
+Ok, that just about covers the basics of accessing IO portably.  Questions?
+Comments? You may think that all the above is overly complex, but one day you
+might find yourself with a 500MHz alpha in front of you, and then you'll be
+happy that your driver works ;)
+
+Note that kernel versions 2.0.x (and earlier) mistakenly called the
+ioremap() function "vremap()".  ioremap() is the proper name, but I
+didn't think straight when I wrote it originally.  People who have to
+support both can do something like:
+       /* support old naming sillyness */
+       #if LINUX_VERSION_CODE < 0x020100                                     
+       #define ioremap vremap
+       #define iounmap vfree                                                     
+       #endif
+at the top of their source files, and then they can use the right names
+even on 2.0.x systems. 
+
+And the above sounds worse than it really is.  Most real drivers really
+don't do all that complex things (or rather: the complexity is not so
+much in the actual IO accesses as in error handling and timeouts etc). 
+It's generally not hard to fix drivers, and in many cases the code
+actually looks better afterwards:
+
+       unsigned long signature = *(unsigned int *) 0xC0000;
+               vs
+       unsigned long signature = readl(0xC0000);
+
+I think the second version actually is more readable, no?
+
+               Linus
+
index 0edbd21bda94e11b3f3e05c3e2c6dc8ad4a863cc..22842fbd0e94308ce9b400b719977089394c3d79 100644 (file)
@@ -352,6 +352,14 @@ e. Directory listings are unpredictably truncated, and `dmesg' shows
     bug.
 
 
+f. Data corruption.
+
+  - Random data corruption was occasionally observed with the Hitachi
+    CDR-7730 cdrom. If you experience data corruption, using "hdx=slow"
+    as a command line parameter may work around the problem, at the
+    expense of low system performance.
+
+
 6. cdload.c
 -----------
 
index 2af4dd7a1683ac4fb8aa64850ef249fc8132a558..277382b8c069c77e0be40b1cdddc02f75917cd7a 100644 (file)
@@ -255,6 +255,8 @@ Summary of ide driver parameters for kernel "command line":
                                Not fully supported by all chipset types,
                                and quite likely to cause trouble with
                                older/odd IDE drives.
+ "hdx=slow"            : insert a huge pause after each access to the data
+                               port. Should be used only as a last resort.
 
  "idebus=xx"           : inform IDE driver of VESA/PCI bus speed in Mhz,
                                where "xx" is between 20 and 66 inclusive,
index 600f7c2001be30a749a2d6bcad917d0c8991d4d7..589b30e27c3a73e68b31544d2f85d821ad6344c4 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 0
-SUBLEVEL = 21
+SUBLEVEL = 22
 
 ARCH = i386
 
index 89fe7b19eacb412094e26104b54ec4ac7ccd54d4..d16871ea3781c52599f997c4f494bea4a95ffbda 100644 (file)
@@ -182,6 +182,17 @@ int cpu_idle(void *unused)
  * and if it doesn't work, we do some other stupid things.
  */
 static long no_idt[2] = {0, 0};
+static int reboot_mode = 0;
+
+void reboot_setup(char *str, int *ints)
+{
+       int mode = 0;
+
+       /* "w" for "warm" reboot (no memory testing etc) */
+       if (str[0] == 'w')
+               mode = 0x1234;
+       reboot_mode = mode;
+}
 
 static inline void kb_wait(void)
 {
@@ -199,7 +210,7 @@ void hard_reset_now(void)
        sti();
 /* rebooting needs to touch the page at absolute addr 0 */
        pg0[0] = 7;
-       *((unsigned short *)0x472) = 0x1234;
+       *((unsigned short *)0x472) = reboot_mode;
        for (;;) {
                for (i=0; i<100; i++) {
                        kb_wait();
index 9492dae65c3f45c0986cc37d8e11d853b2a94d77..86b4b6a8c0721d661e8a9d0baf52c488dcdfd660 100644 (file)
@@ -173,13 +173,9 @@ DO_ERROR( 9, SIGFPE,  "coprocessor segment overrun", coprocessor_segment_overrun
 DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS, current)
 DO_ERROR(11, SIGBUS,  "segment not present", segment_not_present, current)
 DO_ERROR(12, SIGBUS,  "stack segment", stack_segment, current)
+DO_ERROR(15, SIGSEGV, "reserved", reserved, current)
 DO_ERROR(17, SIGSEGV, "alignment check", alignment_check, current)
 
-asmlinkage void do_reserved(struct pt_regs * regs, long error_code)
-{
-       printk("Uhhuh.. Reserved trap code, whazzup? (%ld)\n", error_code);
-}
-
 asmlinkage void do_general_protection(struct pt_regs * regs, long error_code)
 {
        if (regs->eflags & VM_MASK) {
index 68c51cd9e4604af0e56ba55adf6edd924521cb41..b8385db1fe5b66d9b116089b5f04d2ad4dbcc98e 100644 (file)
@@ -97,9 +97,9 @@ extern char emulating;
 
 struct address {
   unsigned int offset;
-  unsigned int selector:16;
-  unsigned int opcode:11;
-  unsigned int empty:5;
+  unsigned short selector;
+  unsigned short opcode:11,
+                empty:5;
 };
 typedef void (*FUNC)(void);
 typedef struct fpu_reg FPU_REG;
index dfa48f764b807ce320bfe770968f4bcc61cb9edd..3c2ec0af0c955a791d8960a0c4ada10d22fff7bc 100644 (file)
@@ -2087,7 +2087,7 @@ static void setup_format_params(int track)
 
        /* determine interleave */
        il = 1;
-       if (_floppy->sect > DP->interleave_sect && F_SIZECODE == 2)
+       if (_floppy->fmt_gap < 0x22)
                il++;
 
        /* initialize field */
index d557b2f9c7634986e8f4652e7e05cbffd0edf44a..4fafda17c8ff9552d1ecfa8f0f87e04fbd932288 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/block/ide-tape.c      Version 1.7 - ALPHA     Sep  10, 1996
+ * linux/drivers/block/ide-tape.c      Version 1.8 - ALPHA     Sep  26, 1996
  *
  * Copyright (C) 1995, 1996 Gadi Oxman <gadio@netvision.net.il>
  *
  * Ver 1.6   Aug 16 96   Fixed FPU usage in the driver.
  *                       Fixed end of media bug.
  * Ver 1.7   Sep 10 96   Minor changes for the CONNER CTT8000-A model.
+ * Ver 1.8   Sep 26 96   Attempt to find a better balance between good
+ *                        interactive response and high system throughput.
  *
  * We are currently in an *alpha* stage. The driver is not complete and not
  * much tested. I would strongly suggest to:
@@ -1228,6 +1230,10 @@ void idetape_setup (ide_drive_t *drive)
 {
        idetape_tape_t *tape=&(drive->tape);
        unsigned int allocation_length;
+#if IDETAPE_ANTICIPATE_READ_WRITE_DSC
+       ide_hwif_t *hwif = HWIF(drive);
+       unsigned long t1, tmid, tn;
+#endif /* IDETAPE_ANTICIPATE_READ_WRITE_DSC */
 
 #if IDETAPE_DEBUG_LOG
        printk ("ide-tape: Reached idetape_setup\n");
@@ -1310,10 +1316,28 @@ void idetape_setup (ide_drive_t *drive)
         *      constantly streaming.
         */
 
-       if (tape->max_number_of_stages) 
-               tape->best_dsc_rw_frequency = (unsigned long) ((tape->capabilities.buffer_size * 32 * HZ) / (tape->capabilities.speed * 125));
-       else
-               tape->best_dsc_rw_frequency = (unsigned long) ((tape->data_buffer_size * HZ) / (tape->capabilities.speed * 1000));
+       /*
+        *      We will ignore the above algorithm for now, as it can have
+        *      a bad effect on interactive response under some conditions.
+        *      The following attempts to find a balance between good latency
+        *      and good system throughput. It will be nice to have all this
+        *      configurable in run time at some point.
+        */
+       t1 = (tape->data_buffer_size * HZ) / (tape->capabilities.speed * 1000);
+       tmid = (tape->capabilities.buffer_size * 32 * HZ) / (tape->capabilities.speed * 125);
+       tn = (IDETAPE_FIFO_THRESHOLD * tape->data_buffer_size * HZ) / (tape->capabilities.speed * 1000);
+
+       if (tape->max_number_of_stages) {
+               if (drive->using_dma)
+                       tape->best_dsc_rw_frequency = tmid;
+               else {
+                       if (hwif->drives[drive->select.b.unit ^ 1].present || hwif->next != hwif)
+                               tape->best_dsc_rw_frequency = IDETAPE_MIN ((tn + tmid) / 2, tmid);
+                       else
+                               tape->best_dsc_rw_frequency = IDETAPE_MIN (tn, tmid);
+               }
+       } else
+               tape->best_dsc_rw_frequency = t1;
 
        /*
         *      Ensure that the number we got makes sense.
@@ -1336,8 +1360,10 @@ void idetape_setup (ide_drive_t *drive)
        tape->best_dsc_rw_frequency=IDETAPE_DSC_READ_WRITE_FALLBACK_FREQUENCY;
 #endif /* IDETAPE_ANTICIPATE_READ_WRITE_DSC */
 
-       printk ("ide-tape: Tape speed - %d KBps. Recommended transfer unit - %d bytes.\n",tape->capabilities.speed,tape->data_buffer_size);
-
+       printk (KERN_INFO "ide-tape: %s <-> %s, %dKBps, %d*%dkB buffer, %dkB pipeline, %lums tDSC%s\n",
+               drive->name, "ht0", tape->capabilities.speed, (tape->capabilities.buffer_size * 512) / tape->data_buffer_size,
+               tape->data_buffer_size / 1024, tape->max_number_of_stages * tape->data_buffer_size / 1024,
+               tape->best_dsc_rw_frequency * 1000 / HZ, drive->using_dma ? ", DMA":"");
        return;
 }
 
index 7786d270a841b01b856b7a407412868769e11777..971c63ec4ef23c8ce763171479b4c26594c2601f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/block/ide-tape.h      Version 1.7 - ALPHA     Sep  10, 1996
+ * linux/drivers/block/ide-tape.h      Version 1.8 - ALPHA     Sep  26, 1996
  *
  * Copyright (C) 1995, 1996 Gadi Oxman <gadio@netvision.net.il>
  */
 
 #define IDETAPE_ANTICIPATE_READ_WRITE_DSC      1
 
+/*
+ *     The following parameter is used to select the point in the internal
+ *     tape fifo in which we will start to refill the buffer. Decreasing
+ *     the following parameter will improve the system's latency and
+ *     interactive response, while using a high value might improve sytem
+ *     throughput.
+ */
+#define        IDETAPE_FIFO_THRESHOLD                  2
+
 /*
  *     DSC timings.
  */
index 4e247cd4e08bf629bc768a4e43aa494fe51e8a0f..441d22059ba2c6ab2bd8593effc1814945fc7882 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/block/ide.c  Version 5.51  Aug  10, 1996
+ *  linux/drivers/block/ide.c  Version 5.52  Sep  24, 1996
  *
  *  Copyright (C) 1994-1996  Linus Torvalds & authors (see below)
  */
  * Version 5.50                allow values as small as 20 for idebus=
  * Version 5.51                force non io_32bit in drive_cmd_intr()
  *                     change delay_10ms() to delay_50ms() to fix problems
+ * Version 5.52                fix incorrect invalidation of removable devices
+ *                     add "hdx=slow" command line option
  *
  *  Some additional driver compile-time options are in ide.h
  *
@@ -485,8 +487,18 @@ void ide_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
                } else
 #endif /* SUPPORT_VLB_SYNC */
                        insl(data_reg, buffer, wcount);
-       } else
-               insw(data_reg, buffer, wcount<<1);
+       } else {
+#if SUPPORT_SLOW_DATA_PORTS
+               if (drive->slow) {
+                       unsigned short *ptr = (unsigned short *) buffer;
+                       while (wcount--) {
+                               *ptr++ = inw_p(data_reg);
+                               *ptr++ = inw_p(data_reg);
+                       }
+               } else
+#endif /* SUPPORT_SLOW_DATA_PORTS */
+                       insw(data_reg, buffer, wcount<<1);
+       }
 }
 
 /*
@@ -509,8 +521,18 @@ void ide_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
                } else
 #endif /* SUPPORT_VLB_SYNC */
                        outsl(data_reg, buffer, wcount);
-       } else
-               outsw(data_reg, buffer, wcount<<1);
+       } else {
+#if SUPPORT_SLOW_DATA_PORTS
+               if (drive->slow) {
+                       unsigned short *ptr = (unsigned short *) buffer;
+                       while (wcount--) {
+                               outw_p(*ptr++, data_reg);
+                               outw_p(*ptr++, data_reg);
+                       }
+               } else
+#endif /* SUPPORT_SLOW_DATA_PORTS */
+                       outsw(data_reg, buffer, wcount<<1);
+       }
 }
 
 /*
@@ -684,6 +706,7 @@ static void atapi_reset_pollfunc (ide_drive_t *drive)
                hwgroup->poll_timeout = 0;      /* end of polling */
                printk("%s: ATAPI reset timed-out, status=0x%02x\n", drive->name, stat);
                do_reset1 (drive, 1);   /* do it the old fashioned way */
+               return;
        }
        hwgroup->poll_timeout = 0;      /* done polling */
 }
@@ -1874,7 +1897,7 @@ static int ide_open(struct inode * inode, struct file * filp)
        if (drive->media == ide_tape)
                return idetape_blkdev_open (inode, filp, drive);
 #endif /* CONFIG_BLK_DEV_IDETAPE */
-       if (drive->removable) {
+       if (drive->removable && drive->usage == 1) {
                byte door_lock[] = {WIN_DOORLOCK,0,0,0};
                struct request rq;
                check_disk_change(inode->i_rdev);
@@ -1955,7 +1978,7 @@ static int revalidate_disk(kdev_t i_rdev)
        for (p = 0; p < (1<<PARTN_BITS); ++p) {
                if (drive->part[p].nr_sects > 0) {
                        kdev_t devp = MKDEV(major, minor+p);
-                       sync_dev           (devp);
+                       fsync_dev          (devp);
                        invalidate_inodes  (devp);
                        invalidate_buffers (devp);
                }
@@ -2865,7 +2888,8 @@ void ide_setup (char *s)
         */
        if (s[0] == 'h' && s[1] == 'd' && s[2] >= 'a' && s[2] <= max_drive) {
                const char *hd_words[] = {"none", "noprobe", "nowerr", "cdrom",
-                               "serialize", "autotune", "noautotune", NULL};
+                               "serialize", "autotune", "noautotune",
+                               "slow", NULL};
                unit = s[2] - 'a';
                hw   = unit / MAX_DRIVES;
                unit = unit % MAX_DRIVES;
@@ -2895,6 +2919,9 @@ void ide_setup (char *s)
                        case -7: /* "noautotune" */
                                drive->autotune = 2;
                                goto done;
+                       case -8: /* "slow" */
+                               drive->slow = 1;
+                               goto done;
                        case 3: /* cyl,head,sect */
                                drive->media    = ide_disk;
                                drive->cyl      = drive->bios_cyl  = vals[0];
index 772f2c6d7d0992f3d32e1a8d8720ab4549f71492..98ec3d939870d5ccff4da9394b1d8c905e010db6 100644 (file)
@@ -25,6 +25,9 @@
 #undef REALLY_FAST_IO                  /* define if ide ports are perfect */
 #define INITIAL_MULT_COUNT     0       /* off=0; on=2,4,8,16,32, etc.. */
 
+#ifndef SUPPORT_SLOW_DATA_PORTS                /* 1 to support slow data ports */
+#define SUPPORT_SLOW_DATA_PORTS        1       /* 0 to reduce kernel size */
+#endif
 #ifndef SUPPORT_VLB_SYNC               /* 1 to support weird 32-bit chips */
 #define SUPPORT_VLB_SYNC       1       /* 0 to reduce kernel size */
 #endif
@@ -327,6 +330,7 @@ typedef struct ide_drive_s {
        unsigned no_unmask      : 1;    /* disallow setting unmask bit */
        unsigned no_io_32bit    : 1;    /* disallow enabling 32bit I/O */
        unsigned nobios         : 1;    /* flag: do not probe bios for drive */
+       unsigned slow           : 1;    /* flag: slow data port */
        unsigned autotune       : 2;    /* 1=autotune, 2=noautotune, 0=default */
 #if FAKE_FDISK_FOR_EZDRIVE
        unsigned remap_0_to_1   : 1;    /* flag: partitioned with ezdrive */
index 1a6d5961725382a5e955412b69684b8226464db1..bbbeec8c7cb3e0c7ed309010eca33674dc32556c 100644 (file)
  */
 const char *good_dma_drives[] = {"Micropolis 2112A",
                                 "CONNER CTMA 4000",
-                                "CONNER CTT8000-A"};
+                                "CONNER CTT8000-A",
+                                NULL};
 
 /*
  * Our Physical Region Descriptor (PRD) table should be large enough
index dbeadbddd8d8878c736237145991eeafa6d9d128..235b33e4e93e882735b2db3fbe0e67ac92a28bec 100644 (file)
@@ -1,5 +1,5 @@
 static char rcsid[] =
-"$Revision: 1.36.3.7A $$Date: 1996/07/27 10:25:50 $";
+"$Revision: 1.36.3.9 $$Date: 1996/10/07 19:47:13 $";
 /*
  *  linux/drivers/char/cyclades.c
  *
@@ -24,6 +24,14 @@ static char rcsid[] =
  *   int cy_open(struct tty_struct *tty, struct file *filp);
  *
  * $Log: cyclades.c,v $
+ * Revision 1.36.3.9  1996/10/07 19:47:13  bentson
+ * add MOD_DEC_USE_COUNT in one return from cy_close (as
+ * noted by Jon Lewis <jlewis@INORGANIC5.FDT.NET>)
+ *
+ * Revision 1.36.3.8  1996/06/07 16:29:00  bentson
+ * starting minor number at zero; added missing verify_area
+ * as noted by Heiko Eissfeldt <heiko@colossus.escape.de>
+ *
  * Revision 1.36.3.7  1996/04/19 21:06:18  bentson
  * remove unneeded boot message & fix CLOCAL hardware flow
  * control (Miquel van Smoorenburg <miquels@Q.cistron.nl>);
@@ -2355,6 +2363,7 @@ cy_close(struct tty_struct * tty, struct file * filp)
 
     /* If the TTY is being hung up, nothing to do */
     if (tty_hung_up_p(filp)) {
+       MOD_DEC_USE_COUNT;
        restore_flags(flags);
        return;
     }
index b839d1cddff9ac49937d9edd1b5d91bbb10d3c69..b2c5f9abb0bfcd796942a53f0ae6e25abb9d1f1e 100644 (file)
@@ -1120,10 +1120,12 @@ int pcxe_init(void)
        pcxe_termios = kmalloc(sizeof(struct termios *) * nbdevs, GFP_KERNEL);
        if (!pcxe_termios)
                panic("Unable to allocate pcxe_termios struct");
+       memset(pcxe_termios,0,sizeof(struct termios *)*nbdevs);
 
        pcxe_termios_locked = kmalloc(sizeof(struct termios *) * nbdevs, GFP_KERNEL);
        if (!pcxe_termios_locked)
                panic("Unable to allocate pcxe_termios_locked struct");
+       memset(pcxe_termios_locked,0,sizeof(struct termios *)*nbdevs);
 
        init_bh(DIGI_BH,do_pcxe_bh);
        enable_bh(DIGI_BH);
index 989d949e9f84e125f30a3871fab7b571f860e314..53968b33c54464536c0ec44d9c66a4b5e00b7349 100644 (file)
@@ -181,66 +181,41 @@ static void pty_flush_buffer(struct tty_struct *tty)
 
 int pty_open(struct tty_struct *tty, struct file * filp)
 {
-#if PTY_SLAVE_WAITS_ON_OPEN
-       struct wait_queue wait = { current, NULL };
-#endif
        int     retval;
        int     line;
        struct  pty_struct *pty;
-       
+
+       retval = -ENODEV;
        if (!tty || !tty->link)
-               return -ENODEV;
+               goto out;
        line = MINOR(tty->device) - tty->driver.minor_start;
        if ((line < 0) || (line >= NR_PTYS))
-               return -ENODEV;
+               goto out;
        pty = pty_state + line;
        tty->driver_data = pty;
 
        if (!tmp_buf) {
-               unsigned long page = get_free_page(GFP_KERNEL);
+               unsigned long page = __get_free_page(GFP_KERNEL);
                if (!tmp_buf) {
+                       retval = -ENOMEM;
                        if (!page)
-                               return -ENOMEM;
+                               goto out;
                        tmp_buf = (unsigned char *) page;
+                       memset((void *) page, 0, PAGE_SIZE);
                } else
                        free_page(page);
        }
+       retval = -EIO;
+       if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
+               goto out;
+       if (tty->link->count != 1)
+               goto out;
 
        clear_bit(TTY_OTHER_CLOSED, &tty->link->flags);
        wake_up_interruptible(&pty->open_wait);
        set_bit(TTY_THROTTLED, &tty->flags);
-       if (filp->f_flags & O_NDELAY)
-               return 0;
-       /*
-        * If we're opening the master pty, just return.  If we're
-        * trying to open the slave pty, then we have to wait for the
-        * master pty to open.
-        */
-       if (tty->driver.subtype == PTY_TYPE_MASTER)
-               return 0;
        retval = 0;
-#if PTY_SLAVE_WAITS_ON_OPEN
-       add_wait_queue(&pty->open_wait, &wait);
-       while (1) {
-               if (current->signal & ~current->blocked) {
-                       retval = -ERESTARTSYS;
-                       break;
-               }
-               /*
-                * Block until the master is open...
-                */
-               current->state = TASK_INTERRUPTIBLE;
-               if (tty->link->count &&
-                   !test_bit(TTY_OTHER_CLOSED, &tty->flags))
-                       break;
-               schedule();
-       }
-       current->state = TASK_RUNNING;
-       remove_wait_queue(&pty->open_wait, &wait);
-#else
-       if (!tty->link->count || test_bit(TTY_OTHER_CLOSED, &tty->flags))
-               retval = -EPERM;
-#endif
+out:
        return retval;
 }
 
index 5c6e38d48f7b1df9b52303fd4a2e908bb14d0a83..5caef729b12d4e3001257596880fd3ac72d07517 100644 (file)
@@ -17,7 +17,7 @@
  */
 
 static const char *version = 
-       "Equalizer1996: $Revision: 1.2 $ $Date: 1996/04/11 17:51:52 $ Simon Janes (simon@ncm.com)\n";
+       "Equalizer1996: $Revision: 1.2.1 $ $Date: 1996/09/22 13:52:00 $ Simon Janes (simon@ncm.com)\n";
 
 /*
  * Sources:
@@ -459,28 +459,35 @@ static int eql_enslave(struct device *dev, slaving_request_t *srqp)
 
        if (master_dev != 0 && slave_dev != 0)
        {
-               if (! eql_is_master (slave_dev)  &&   /* slave is not a master */
-                       ! eql_is_slave (slave_dev)      ) /* slave is not already a slave */
-               {
-                       slave_t *s = eql_new_slave ();
-                       equalizer_t *eql = (equalizer_t *) master_dev->priv;
-                       s->dev = slave_dev;
-                       s->priority = srq.priority;
-                       s->priority_bps = srq.priority;
-                       s->priority_Bps = srq.priority / 8;
-                       slave_dev->flags |= IFF_SLAVE;
-                       eql_insert_slave (eql->queue, s);
-                       return 0;
+               if ((master_dev->flags & IFF_UP) == IFF_UP)
+                {
+                       /*slave is not a master & not already a slave:*/
+                       if (! eql_is_master (slave_dev)  &&
+                           ! eql_is_slave (slave_dev) )
+                       {
+                               slave_t *s = eql_new_slave ();
+                               equalizer_t *eql = 
+                                       (equalizer_t *) master_dev->priv;
+                               s->dev = slave_dev;
+                               s->priority = srq.priority;
+                               s->priority_bps = srq.priority;
+                               s->priority_Bps = srq.priority / 8;
+                               slave_dev->flags |= IFF_SLAVE;
+                               eql_insert_slave (eql->queue, s);
+                               return 0;
+                       }
+#ifdef EQL_DEBUG
+                       else if (eql_debug >= 20)
+                               printk ("EQL enslave: slave is master or slave is already slave\n");
+#endif  
                }
 #ifdef EQL_DEBUG
-       if (eql_debug >= 20)
-               printk ("EQL enslave: slave is master or slave is already slave\n");
+               else if (eql_debug >= 20)
+                       printk ("EQL enslave: master device not up!\n");
 #endif  
-
-               return -EINVAL;
        }
 #ifdef EQL_DEBUG
-       if (eql_debug >= 20)
+       else if (eql_debug >= 20)
                printk ("EQL enslave: master or slave are NULL");
 #endif  
        return -EINVAL;
index 6ac4c2aa6dcef7a0f1bdd9048540d2145ef85a47..76ee26a4f9aea4e55addaa62bd46a754a4b16f37 100644 (file)
@@ -299,14 +299,21 @@ static int ne_probe1(struct device *dev, int ioaddr)
            wordlength = 1;
     }
 
+    /* At this point, wordlength *only* tells us if the SA_prom is doubled
+       up or not because some broken PCI cards don't respect the byte-wide
+       request in program_seq above, and hence don't have doubled up values. 
+       These broken cards would otherwise be detected as an ne1000.  */
+
+    if (wordlength == 2)
+       for (i = 0; i < 16; i++)
+               SA_prom[i] = SA_prom[i+i];
+    
+    if (pci_irq_line)
+       wordlength = 2;         /* Catch broken cards mentioned above. */
+
     if (wordlength == 2) {
        /* We must set the 8390 for word mode. */
        outb_p(0x49, ioaddr + EN0_DCFG);
-       /* We used to reset the ethercard here, but it doesn't seem
-          to be necessary. */
-       /* Un-double the SA_prom values. */
-       for (i = 0; i < 16; i++)
-           SA_prom[i] = SA_prom[i+i];
        start_page = NESM_START_PG;
        stop_page = NESM_STOP_PG;
     } else {
index bd377431d4858191520f170caaaec32d3ef554a3..c7f037b8d36211e8abce7dbe979325ce8c10e174 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: advansys.c,v 1.15 1996/08/12 17:20:23 bobf Exp bobf $ */
+/* $Id: advansys.c,v 1.20 1996/09/26 00:47:54 bobf Exp bobf $ */
 /*
  * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters
  * 
@@ -18,9 +18,9 @@
  */
 
 /*
- * The driver has been run with the v1.2.13, v1.3.57, and v2.0.11 kernels.
+ * The driver has been run with the v1.2.13, v1.3.57, and v2.0.21 kernels.
  */
-#define ASC_VERSION "1.5"    /* AdvanSys Driver Version */
+#define ASC_VERSION "1.7"    /* AdvanSys Driver Version */
 
 /*
 
 
   A. Adapters Supported by this Driver
   B. Linux v1.2.X - Directions for Adding the AdvanSys Driver
-  C. Linux v1.3.X, v2.X.X - Directions for Adding the AdvanSys Driver
-  D. Source Comments
-  E. Driver Compile Time Options and Debugging
-  F. Driver LILO Option
-  G. Release History
-  H. Known Problems or Issues
-  I. Credits
-  J. AdvanSys Contact Information
+  C. Linux v1.3.1 - v1.3.57 - Directions for Adding the AdvanSys Driver
+  D. Linux v1.3.58 and Newer - Upgrading the AdvanSys Driver
+  E. Source Comments
+  F. Driver Compile Time Options and Debugging
+  G. Driver LILO Option
+  H. Release History
+  I. Known Problems or Issues
+  J. Credits
+  K. AdvanSys Contact Information
 
   A. Adapters Supported by this Driver
  
@@ -47,8 +48,8 @@
      Descriptor Block) requests that can be stored in the RISC chip
      cache and board LRAM. A CDB is a single SCSI command. The driver
      detect routine will display the number of CDBs available for each
-     adapter detected. This value can be lowered in the BIOS by changing
-     the 'Host Queue Size' adapter setting.
+     adapter detected. The number of CDBs used by the driver can be
+     lowered in the BIOS by changing the 'Host Queue Size' adapter setting.
 
      Connectivity Products:
         ABP510/5150 - Bus-Master ISA (240 CDB) (Footnote 1)
         ABP5142 - Bus-Master ISA PnP with floppy (16 CDB)
         ABP920 - Bus-Master PCI (16 CDB)
         ABP930 - Bus-Master PCI (16 CDB)
+        ABP930U - Bus-Master PCI Ultra (16 CDB)
         ABP960 - Bus-Master PCI MAC/PC (16 CDB) (Footnote 2)
-  
+        ABP960U - Bus-Master PCI MAC/PC Ultra (16 CDB)
+     
      Single Channel Products:
         ABP542 - Bus-Master ISA with floppy (240 CDB)
         ABP742 - Bus-Master EISA (240 CDB)
@@ -65,6 +68,7 @@
         ABP940 - Bus-Master PCI (240 CDB)
         ABP940U - Bus-Master PCI Ultra (240 CDB)
         ABP970 - Bus-Master PCI MAC/PC (240 CDB)
+        ABP970U - Bus-Master PCI MAC/PC Ultra (240 CDB)
      
      Dual Channel Products:
         ABP752 - Dual Channel Bus-Master EISA (240 CDB Per Channel)
         ABP950 - Dual Channel Bus-Master PCI (240 CDB Per Channel)
      
      Footnotes:
-       1. These boards have been shipped by HP with the 4020i CD-R drive.
-          They have no BIOS so they cannot control a boot device, but they
-          can control secondary devices.
+       1. This board has been shipped by HP with the 4020i CD-R drive.
+          The board has no BIOS so it cannot control a boot device, but
+          it can control any secondary SCSI device.
    
-       2. This board has been shipped by Iomega with the Jaz Jet drive.
+       2. This board has been sold by Iomega as a Jaz Jet PCI adapter.
   
   B. Linux v1.2.X - Directions for Adding the AdvanSys Driver
 
      These directions apply to v1.2.13. For versions that follow v1.2.13.
      but precede v1.3.57 some of the changes for Linux v1.3.X listed
-     below may need to be modified or included.
+     below may need to be modified or included. A patch is available
+     for v1.2.13 from the AdvanSys WWW and FTP sites.
  
      There are two source files: advansys.h and advansys.c. Copy
      both of these files to the directory /usr/src/linux/drivers/scsi.
         'make modules_install'. Use 'insmod' and 'rmmod' to install
         and remove advansys.o.
  
-  C. Linux v1.3.X, v2.X.X - Directions for Adding the AdvanSys Driver
+  C. Linux v1.3.1 - v1.3.57 - Directions for Adding the AdvanSys Driver
 
      These directions apply to v1.3.57. For versions that precede v1.3.57
-     some of these changes may need to be modified or eliminated. Beginning
-     with v1.3.58 this driver is included with the Linux distribution.
+     some of these changes may need to be modified or eliminated. A patch
+     is available for v1.3.57 from the AdvanSys WWW and FTP sites.
+     Beginning with v1.3.58 this driver is included with the Linux
+     distribution eliminating the need for making any changes.
 
      There are two source files: advansys.h and advansys.c. Copy
      both of these files to the directory /usr/src/linux/drivers/scsi.
         'make modules_install'. Use 'insmod' and 'rmmod' to install
         and remove advansys.o.
 
-  D. Source Comments
+  D. Linux v1.3.58 and Newer - Upgrading the AdvanSys Driver
+
+     To upgrade the AdvanSys driver in a Linux v1.3.58 and newer
+     kernel, first check the version of the current driver. The
+     version is defined by the manifest constant ASC_VERSION at
+     the beginning of advansys.c. The new driver should have a
+     ASC_VERSION value greater than the current version. To install
+     the new driver rename advansys.c and advansys.h in the Linux
+     kernel source tree drivers/scsi directory to different names
+     or save them to a different directory in case you want to revert
+     to the old version of the driver. After the old driver is saved
+     copy the new advansys.c and advansys.h to drivers/scsi, rebuild
+     the kernel, and install the new kernel. No other changes are needed.
+
+  E. Source Comments
  
      1. Use tab stops set to 4 for the source files. For vi use 'se tabstops=4'.
  
            --- Asc Library Constants and Macros
            --- Asc Library Functions
  
-  E. Driver Compile Time Options and Debugging
+  F. Driver Compile Time Options and Debugging
  
      In this source file the following constants can be defined. They are
      defined in the source below. Both of these options are enabled by
      2. ADVANSYS_STATS - enable statistics
  
         Statistics are maintained on a per adapter basis. Driver entry
-        point call counts and tranfer size counts are maintained.
+        point call counts and transfer size counts are maintained.
         Statistics are only available for kernels greater than or equal
         to v1.3.0 with the CONFIG_PROC_FS (/proc) file system configured.
 
         contain adapter and device configuration information.
 
 
-  F. Driver LILO Option
+  G. Driver LILO Option
  
      If init/main.c is modified as described in the 'Directions for Adding
      the AdvanSys Driver to Linux' section (B.4.) above, the driver will
      the 'Driver Compile Time Options and Debugging' section above for
      more information.
 
-  G. Release History
+  H. Release History
 
      BETA-1.0 (12/23/95): 
          First Release
             request_irq and supplying a dev_id pointer to both request_irq()
             and free_irq().
          3. In AscSearchIOPortAddr11() restore a call to check_region() which
-            should be used before any I/O port probing.
+            should be used before I/O port probing.
          4. Fix bug in asc_prt_hex() which resulted in the displaying
             the wrong data.
          5. Incorporate miscellaneous Asc Library bug fixes and new microcode.
             made in v1.3.89. The advansys_select_queue_depths() function
             was added for the v1.3.89 changes.
 
-  H. Known Problems or Issues
+     1.6 (9/10/96):
+         1. Incorporate miscellaneous Asc Library bug fixes and new microcode.
+
+     1.7 (9/25/96):
+         1. Enable clustering and optimize the setting of the maximum number
+            of scatter gather elements for any particular board. Clustering
+            increases CPU utilization, but results in a relatively larger
+            increase in I/O throughput.
+         2. Improve the performance of the request queuing functions by
+            adding a last pointer to the queue structure.
+         3. Correct problems with reset and abort request handling that
+            could have hung or crashed Linux.
+         4. Add more information to the adapter /proc file:
+            /proc/scsi/advansys[0...].
+         5. Remove the request timeout issue form the driver issues list.
+         6. Miscellaneous documentation additions and changes.
+
+  I. Known Problems or Issues
 
-     1. For the first scsi command sent to a device the driver increases
-        the timeout value. This gives the driver more time to perform
-        its own initialization for the board and each device. The timeout
-        value is only changed on the first scsi command for each device
-        and never thereafter. The same change is made for reset commands.
+         None
 
-  I. Credits
+  J. Credits
 
      Nathan Hartwell <mage@cdc3.cdc.net> provided the directions and
      basis for the Linux v1.3.X changes which were included in the
      Thomas E Zerucha <zerucha@shell.portal.com> pointed out a bug
      in advansys_biosparam() which was fixed in the 1.3 release.
 
-  J. AdvanSys Contact Information
+  K. AdvanSys Contact Information
  
      Mail:                   Advanced System Products, Inc.
                              1150 Ringwood Court
  */
 
 #define ASC_LIB_VERSION_MAJOR  1
-#define ASC_LIB_VERSION_MINOR  21
-#define ASC_LIB_SERIAL_NUMBER  88
+#define ASC_LIB_VERSION_MINOR  22
+#define ASC_LIB_SERIAL_NUMBER  89
 
 typedef unsigned char uchar;
 
@@ -581,6 +615,11 @@ typedef unsigned char uchar;
 #define ASC_PCI_ID2FUNC( id )   (((id) >> 8) & 0x7)
 #define ASC_PCI_MKID( bus, dev, func ) ((((dev) & 0x1F) << 11) | (((func) & 0x7) << 8) | ((bus) & 0xFF))
 
+#define  Asc_DvcLib_Status   int
+#define  ASC_DVCLIB_CALL_DONE     (1)
+#define  ASC_DVCLIB_CALL_FAILED   (0)
+#define  ASC_DVCLIB_CALL_ERROR    (-1)
+
 #define Lptr
 #define dosfar
 #define far
@@ -592,8 +631,8 @@ typedef unsigned char uchar;
 #define outp(port, byte)    outb((byte), (port))
 #define outpw(port, word)   outw((word), (port))
 #define outpl(port, long)   outl((long), (port))
-#define ASC_MAX_SG_QUEUE       5
-#define ASC_MAX_SG_LIST                (1 + ((ASC_SG_LIST_PER_Q) * (ASC_MAX_SG_QUEUE)))
+#define ASC_MAX_SG_QUEUE       7
+#define ASC_MAX_SG_LIST                SG_ALL
 
 #define CC_INIT_INQ_DISPLAY     FALSE
 #define CC_CLEAR_LRAM_SRB_PTR   FALSE
@@ -609,8 +648,6 @@ typedef unsigned char uchar;
 #define CC_MEMORY_MAPPED_IO    FALSE
 #define CC_INCLUDE_EEP_CONFIG  TRUE
 #define CC_PCI_ULTRA           TRUE
-#define CC_INIT_TARGET_READ_CAPACITY    TRUE
-#define CC_INIT_TARGET_TEST_UNIT_READY  TRUE
 #define CC_ASC_SCSI_Q_USRDEF         FALSE
 #define CC_ASC_SCSI_REQ_Q_USRDEF     FALSE
 #define CC_ASCISR_CHECK_INT_PENDING  TRUE
@@ -619,13 +656,10 @@ typedef unsigned char uchar;
 #define CC_DISABLE_PCI_PARITY_INT    TRUE
 #define CC_INCLUDE_EEP_CONFIG        TRUE
 #define CC_INIT_INQ_DISPLAY          FALSE
-#define CC_INIT_TARGET_TEST_UNIT_READY  TRUE
-#define CC_INIT_TARGET_START_UNIT       TRUE
 #define CC_PLEXTOR_VL                FALSE
 #define CC_TMP_USE_EEP_SDTR          FALSE
 #define CC_CHK_COND_REDO_SDTR        TRUE
 #define CC_SET_PCI_LATENCY_TIMER_ZERO  TRUE
-#define CC_FIX_QUANTUM_XP34301_1071  FALSE
 #define CC_DISABLE_ASYN_FIX_WANGTEK_TAPE  TRUE
 
 #define ASC_CS_TYPE  unsigned short
@@ -666,6 +700,8 @@ typedef unsigned char uchar;
 #define ASC_CHIP_MAX_VER_EISA (0x47)
 #define ASC_CHIP_VER_EISA_BIT (0x40)
 #define ASC_CHIP_LATEST_VER_EISA   ( ( ASC_CHIP_MIN_VER_EISA - 1 ) + 3 )
+#define ASC_MAX_LIB_SUPPORTED_ISA_CHIP_VER   0x21
+#define ASC_MAX_LIB_SUPPORTED_PCI_CHIP_VER   0x0A
 #define ASC_MAX_VL_DMA_ADDR     (0x07FFFFFFL)
 #define ASC_MAX_VL_DMA_COUNT    (0x07FFFFFFL)
 #define ASC_MAX_PCI_DMA_ADDR    (0xFFFFFFFFL)
@@ -1313,6 +1349,7 @@ typedef struct asc_risc_sg_list_q {
 #define ASC_IERR_SCAM                 0x0800
 #define ASC_IERR_SET_SDTR             0x1000
 #define ASC_IERR_RW_LRAM              0x8000
+#define ASC_DVCLIB_STATUS             0x00
 #define ASC_DEF_IRQ_NO  10
 #define ASC_MAX_IRQ_NO  15
 #define ASC_MIN_IRQ_NO  10
@@ -1343,10 +1380,10 @@ typedef struct asc_risc_sg_list_q {
 #define ASC_IOADR_DEF   ASC_IOADR_8
 #define ASC_LIB_SCSIQ_WK_SP        256
 #define ASC_MAX_SYN_XFER_NO        16
-#define ASC_SYN_XFER_NO            8
 #define ASC_SYN_MAX_OFFSET         0x0F
 #define ASC_DEF_SDTR_OFFSET        0x0F
 #define ASC_DEF_SDTR_INDEX         0x00
+#define ASC_SDTR_ULTRA_PCI_10MB_INDEX  0x02
 #define SYN_XFER_NS_0  25
 #define SYN_XFER_NS_1  30
 #define SYN_XFER_NS_2  35
@@ -1462,9 +1499,9 @@ typedef struct asc_dvc_var {
        ASC_SCSI_BIT_ID_TYPE no_scam;
        ASC_SCSI_BIT_ID_TYPE pci_fix_asyn_xfer;
        uchar               max_sdtr_index;
-       uchar               res4;
+       uchar               host_init_sdtr_index;
        ulong               drv_ptr;
-       ulong               res6;
+       ulong               uc_break;
        ulong               res7;
        ulong               res8;
 } ASC_DVC_VAR;
@@ -1500,7 +1537,7 @@ typedef struct asc_cap_info_array {
 #define ASC_CNTL_INIT_VERBOSE      ( ushort )0x0800
 #define ASC_CNTL_SCSI_PARITY       ( ushort )0x1000
 #define ASC_CNTL_BURST_MODE        ( ushort )0x2000
-#define ASC_CNTL_USE_8_IOP_BASE    ( ushort )0x4000
+#define ASC_CNTL_SDTR_ENABLE_ULTRA ( ushort )0x4000
 #define ASC_EEP_DVC_CFG_BEG_VL    2
 #define ASC_EEP_MAX_DVC_ADDR_VL   15
 #define ASC_EEP_DVC_CFG_BEG      32
@@ -1537,15 +1574,23 @@ typedef struct asceep_config {
 #define ASC_EEP_CMD_WRITE_ABLE    0x30
 #define ASC_EEP_CMD_WRITE_DISABLE 0x00
 #define ASC_OVERRUN_BSIZE  0x00000048UL
+#define ASC_CTRL_BREAK_ONCE        0x0001
+#define ASC_CTRL_BREAK_STAY_IDLE   0x0002
 #define ASCV_MSGOUT_BEG         0x0000
 #define ASCV_MSGOUT_SDTR_PERIOD (ASCV_MSGOUT_BEG+3)
 #define ASCV_MSGOUT_SDTR_OFFSET (ASCV_MSGOUT_BEG+4)
+#define ASCV_BREAK_SAVED_CODE   ( ushort )0x0006
 #define ASCV_MSGIN_BEG          (ASCV_MSGOUT_BEG+8)
 #define ASCV_MSGIN_SDTR_PERIOD  (ASCV_MSGIN_BEG+3)
 #define ASCV_MSGIN_SDTR_OFFSET  (ASCV_MSGIN_BEG+4)
 #define ASCV_SDTR_DATA_BEG      (ASCV_MSGIN_BEG+8)
 #define ASCV_SDTR_DONE_BEG      (ASCV_SDTR_DATA_BEG+8)
 #define ASCV_MAX_DVC_QNG_BEG    ( ushort )0x0020
+#define ASCV_BREAK_ADDR           ( ushort )0x0028
+#define ASCV_BREAK_NOTIFY_COUNT   ( ushort )0x002A
+#define ASCV_BREAK_CONTROL        ( ushort )0x002C
+#define ASCV_BREAK_HIT_COUNT      ( ushort )0x002E
+
 #define ASCV_ASCDVC_ERR_CODE_W  ( ushort )0x0030
 #define ASCV_MCODE_CHKSUM_W   ( ushort )0x0032
 #define ASCV_MCODE_SIZE_W     ( ushort )0x0034
@@ -2052,7 +2097,11 @@ int                 AscRestoreNewMicroCode(ASC_DVC_VAR asc_ptr_type *, ASC_MC_SA
 #define ASC_NUM_BUS                            4
 
 /* Reference Scsi_Host hostdata */
-#define ASC_BOARDP(host) ((struct asc_board *) &((host)->hostdata))
+#define ASC_BOARDP(host) ((asc_board_t *) &((host)->hostdata))
+
+/* asc_board_t flags */
+#define ASC_HOST_IN_RESET              0x01
+#define ASC_HOST_IN_ABORT              0x02
 
 #define NO_ISA_DMA                             0xff            /* No ISA DMA Channel Used */
 
@@ -2102,6 +2151,12 @@ typedef Scsi_Cmnd                        REQ, *REQP;
 #define ASC_FRONT              1
 #define ASC_BACK               2
 
+/* asc_dequeue_list() argument */
+#define ASC_TID_ALL            (-1)
+
+/* Return non-zero, if the queue is empty. */
+#define ASC_QUEUE_EMPTY(ascq)  ((ascq)->q_tidmask == 0)
+
 /* PCI configuration declarations */
 
 #define PCI_BASE_CLASS_PREDEFINED                      0x00
@@ -2364,6 +2419,7 @@ struct asc_stats {
        ulong   check_interrupt;/* # advansys_interrupt() check pending calls */
        ulong   interrupt;              /* # advansys_interrupt() interrupts */
        ulong   callback;               /* # calls asc_isr_callback() */
+       ulong   done;                   /* # calls request scsi_done */
        /* AscExeScsiQueue() Statistics */
        ulong   asc_noerror;    /* # AscExeScsiQueue() ASC_NOERROR returns. */
        ulong   asc_busy;               /* # AscExeScsiQueue() ASC_BUSY returns. */
@@ -2374,7 +2430,7 @@ struct asc_stats {
        ulong   cont_xfer;              /* # contiguous transfer 512-bytes */
        ulong   sg_cnt;                 /* # scatter-gather I/O requests received */
        ulong   sg_elem;                /* # scatter-gather elements */
-       ulong   sg_xfer;                /* # scatter-gather tranfer 512-bytes */
+       ulong   sg_xfer;                /* # scatter-gather transfer 512-bytes */
        /* Device SCSI Command Queuing Statistics */
        ASC_SCSI_BIT_ID_TYPE queue_full;
        ushort  queue_full_cnt[ASC_MAX_TID+1];
@@ -2385,11 +2441,12 @@ struct asc_stats {
  * Request queuing structure
  */
 typedef struct asc_queue {
-       ASC_SCSI_BIT_ID_TYPE    tidmask;                                  /* queue mask */
-       REQP                                    queue[ASC_MAX_TID+1];     /* queue linked list */
+       ASC_SCSI_BIT_ID_TYPE    q_tidmask;                                /* queue mask */
+       REQP                                    q_first[ASC_MAX_TID+1];   /* first queued request */
+       REQP                                    q_last[ASC_MAX_TID+1];    /* last queued request */
 #ifdef ADVANSYS_STATS
-       short                                   cur_count[ASC_MAX_TID+1]; /* current queue count */
-       short                                   max_count[ASC_MAX_TID+1]; /* maximum queue count */
+       short                                   q_cur_cnt[ASC_MAX_TID+1]; /* current queue count */
+       short                                   q_max_cnt[ASC_MAX_TID+1]; /* maximum queue count */
 #endif /* ADVANSYS_STATS */
 } asc_queue_t;
 
@@ -2400,28 +2457,25 @@ typedef struct asc_queue {
  * of the 'Scsi_Host' structure starting at the 'hostdata'
  * field. It is guaranteed to be allocated from DMA-able memory.
  */
-struct asc_board {
-       int                                      id;                                      /* Board Id */
-       /* Asc Library */
-       ASC_DVC_VAR                      asc_dvc_var;                     /* Board configuration */
-       ASC_DVC_CFG                      asc_dvc_cfg;                     /* Device configuration */
-       /* Queued Commands */
-       asc_queue_t                      active;                                  /* Active command queue */
-       asc_queue_t                      pending;                                 /* Pending command queue */
-       /* Target Initialization */
-       ASC_SCSI_BIT_ID_TYPE init_tidmask;                        /* Target initialized mask */
-       ASC_SCSI_REQ_Q           scsireqq;
-       ASC_CAP_INFO             cap_info;
-       ASC_SCSI_INQUIRY         inquiry;
-       ASCEEP_CONFIG            eep_config;                      /* EEPROM configuration */
+typedef struct asc_board {
+       int                                      id;                            /* Board Id */
+       uint                             flags;                         /* Board flags */
+       ASC_DVC_VAR                      asc_dvc_var;           /* Board configuration */
+       ASC_DVC_CFG                      asc_dvc_cfg;           /* Device configuration */
+       asc_queue_t                      active;                        /* Active command queue */
+       asc_queue_t                      waiting;                       /* Waiting command queue */
+       ASC_SCSI_BIT_ID_TYPE init_tidmask;              /* Target initialized mask */
+       ASCEEP_CONFIG            eep_config;            /* EEPROM configuration */
+       asc_queue_t                      scsi_done_q;           /* Completion command queue */
+       ulong                            reset_jiffies;         /* Saved time of last reset */
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
        /* /proc/scsi/advansys/[0...] */
-       char                             *prtbuf;                                 /* Statistics Print Buffer */
+       char                             *prtbuf;                       /* Statistics Print Buffer */
 #endif /* version >= v1.3.0 */
 #ifdef ADVANSYS_STATS
-       struct asc_stats         asc_stats;                               /* Board statistics */
+       struct asc_stats         asc_stats;                     /* Board statistics */
 #endif /* ADVANSYS_STATS */
-};
+} asc_board_t;
 
 /*
  * PCI configuration structures
@@ -2494,12 +2548,22 @@ struct proc_dir_entry proc_scsi_advansys =
 STATIC int asc_board_count = 0;
 STATIC struct Scsi_Host        *asc_host[ASC_NUM_BOARD_SUPPORTED] = { 0 };
 
-/* Global list of commands needing done function. */
-STATIC Scsi_Cmnd *asc_scsi_done = NULL;
-
 /* Overrun buffer shared between all boards. */
 STATIC uchar overrun_buf[ASC_OVERRUN_BSIZE] = { 0 };
 
+/*
+ * Global structures used for device initialization.
+ */
+STATIC ASC_SCSI_REQ_Q   asc_scsireqq = { { 0 } };
+STATIC ASC_CAP_INFO             asc_cap_info = { 0 };
+STATIC ASC_SCSI_INQUIRY         asc_inquiry = { { 0 } };
+
+/*
+ * Global structures required to issue a command.
+ */
+STATIC ASC_SCSI_Q asc_scsi_q = { { 0 } };
+STATIC ASC_SG_HEAD asc_sg_head = { 0 };
+
 /* List of supported bus types. */
 STATIC ushort asc_bus[ASC_NUM_BUS] = {
        ASC_IS_ISA,
@@ -2549,6 +2613,7 @@ STATIC void               advansys_select_queue_depths(struct Scsi_Host *,
                                                                                                Scsi_Device *);
 #endif /* version >= v1.3.89 */
 STATIC void            advansys_command_done(Scsi_Cmnd *);
+STATIC void            asc_scsi_done_list(Scsi_Cmnd *);
 STATIC int                     asc_execute_scsi_cmnd(Scsi_Cmnd *);
 STATIC void            asc_isr_callback(ASC_DVC_VAR *, ASC_QDONE_INFO *);
 STATIC int                     asc_init_dev(ASC_DVC_VAR *, Scsi_Cmnd *);
@@ -2561,11 +2626,13 @@ STATIC uchar            asc_get_cfg_byte(PCI_DATA *);
 STATIC void            asc_put_cfg_byte(PCI_DATA *, uchar);
 void                           asc_enqueue(asc_queue_t *, REQP, int);
 REQP                           asc_dequeue(asc_queue_t *, int);
+REQP                           asc_dequeue_list(asc_queue_t *, REQP *, int);
 int                                    asc_rmqueue(asc_queue_t *, REQP);
 int                                    asc_isqueued(asc_queue_t *, REQP);
 void                           asc_execute_queue(asc_queue_t *);
 STATIC int                     asc_prt_board_devices(struct Scsi_Host *, char *, int);
 STATIC int                     asc_prt_board_eeprom(struct Scsi_Host *, char *, int);
+STATIC int                     asc_prt_driver_conf(struct Scsi_Host *, char *, int);
 STATIC int                     asc_prt_board_info(struct Scsi_Host *, char *, int);
 STATIC int                     asc_proc_copy(off_t, off_t, char *, int , char *, int);
 STATIC int                     asc_prt_line(char *, int, char *fmt, ...);
@@ -2618,7 +2685,7 @@ advansys_proc_info(char *buffer, char **start, off_t offset, int length,
                                   int hostno, int inout)
 {
        struct Scsi_Host        *shp;
-       struct asc_board        *boardp;
+       asc_board_t             *boardp;
        int                                     i;
        char                            *cp;
        int                                     cplen;
@@ -2738,6 +2805,22 @@ advansys_proc_info(char *buffer, char **start, off_t offset, int length,
        advoffset += cplen;
        curbuf += cnt;
 
+       /*
+        * Display driver configuration and information for the board.
+        */
+       cp = boardp->prtbuf;
+       cplen = asc_prt_driver_conf(shp, cp, ASC_PRTBUF_SIZE);
+       ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
+       cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
+       totcnt += cnt;
+       leftlen -= cnt;
+       if (leftlen == 0) {
+               ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
+               return totcnt;
+       }
+       advoffset += cplen;
+       curbuf += cnt;
+
 #ifdef ADVANSYS_STATS
        /*
         * Display driver statistics for the board.
@@ -2800,7 +2883,7 @@ advansys_detect(Scsi_Host_Template *tpnt)
        int                                     iop;
        int                                     bus;
        struct Scsi_Host        *shp;
-       struct asc_board        *boardp;
+       asc_board_t                     *boardp;
        ASC_DVC_VAR                     *asc_dvc_varp;
        int                                     ioport = 0;
        int                                     share_irq = FALSE;
@@ -2966,14 +3049,14 @@ advansys_detect(Scsi_Host_Template *tpnt)
                         * initialize it.
                         */
                        ASC_DBG(2, "advansys_detect: scsi_register()\n");
-                       shp = scsi_register(tpnt, sizeof(struct asc_board));
+                       shp = scsi_register(tpnt, sizeof(asc_board_t));
 
                        /* Save a pointer to the Scsi_host of each board found. */
                        asc_host[asc_board_count++] = shp;
 
                        /* Initialize private per board data */
                        boardp = ASC_BOARDP(shp);
-                       memset(boardp, 0, sizeof(struct asc_board));
+                       memset(boardp, 0, sizeof(asc_board_t));
                        boardp->id = asc_board_count - 1;
                        asc_dvc_varp = &boardp->asc_dvc_var;
                        asc_dvc_varp->cfg = &boardp->asc_dvc_cfg;
@@ -2984,7 +3067,7 @@ advansys_detect(Scsi_Host_Template *tpnt)
                        if ((boardp->prtbuf =
                                kmalloc(ASC_PRTBUF_SIZE, GFP_ATOMIC)) == NULL) {
                                ASC_PRINT3(
-"advansys_detect: Board %d: kmalloc(%d, %d) returned NULL\n",
+"advansys_detect: board %d: kmalloc(%d, %d) returned NULL\n",
                                        boardp->id, ASC_PRTBUF_SIZE, GFP_ATOMIC);
                                scsi_unregister(shp);
                                asc_board_count--;
@@ -3021,7 +3104,7 @@ advansys_detect(Scsi_Host_Template *tpnt)
                                break;
                        default:
                                ASC_PRINT2(
-"advansys_detect: Board %d: unknown adapter type: %d",
+"advansys_detect: board %d: unknown adapter type: %d",
                                        boardp->id, asc_dvc_varp->bus_type);
                                shp->unchecked_isa_dma = TRUE;
                                share_irq = FALSE;
@@ -3042,38 +3125,38 @@ advansys_detect(Scsi_Host_Template *tpnt)
                                break;
                        case ASC_WARN_IO_PORT_ROTATE:
                                ASC_PRINT1(
-"AscInitGetConfig: Board: %d: I/O port address modified\n",
+"AscInitGetConfig: board %d: I/O port address modified\n",
                                        boardp->id);
                                break;
                        case ASC_WARN_AUTO_CONFIG:
                                ASC_PRINT1(
-"AscInitGetConfig: Board %d: I/O port increment switch enabled\n",
+"AscInitGetConfig: board %d: I/O port increment switch enabled\n",
                                        boardp->id);
                                break;
                        case ASC_WARN_EEPROM_CHKSUM:
                                ASC_PRINT1(
-"AscInitGetConfig: Board %d: EEPROM checksum error\n",
+"AscInitGetConfig: board %d: EEPROM checksum error\n",
                                        boardp->id);
                                break;
                        case ASC_WARN_IRQ_MODIFIED:
                                ASC_PRINT1(
-"AscInitGetConfig: Board %d: IRQ modified\n",
+"AscInitGetConfig: board %d: IRQ modified\n",
                                        boardp->id);
                                break;
                        case ASC_WARN_CMD_QNG_CONFLICT:
                                ASC_PRINT1(
-"AscInitGetConfig: Board %d: tag queuing enabled w/o disconnects\n",
+"AscInitGetConfig: board %d: tag queuing enabled w/o disconnects\n",
                                        boardp->id);
                                break;
                        default:
                                ASC_PRINT2(
-"AscInitGetConfig: Board %d: unknown warning: %x\n",
+"AscInitGetConfig: board %d: unknown warning: %x\n",
                                        boardp->id, ret);
                                break;
                        }
                        if (asc_dvc_varp->err_code != 0) {
                                ASC_PRINT3(
-"AscInitGetConfig: Board %d error: init_state %x, err_code %x\n",
+"AscInitGetConfig: board %d error: init_state %x, err_code %x\n",
                                        boardp->id, asc_dvc_varp->init_state,
                                        asc_dvc_varp->err_code);
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
@@ -3117,38 +3200,38 @@ advansys_detect(Scsi_Host_Template *tpnt)
                                break;
                        case ASC_WARN_IO_PORT_ROTATE:
                                ASC_PRINT1(
-"AscInitSetConfig: Board %d: I/O port address modified\n",
+"AscInitSetConfig: board %d: I/O port address modified\n",
                                        boardp->id);
                                break;
                        case ASC_WARN_AUTO_CONFIG:
                                ASC_PRINT1(
-"AscInitSetConfig: Board %d: I/O port increment switch enabled\n",
+"AscInitSetConfig: board %d: I/O port increment switch enabled\n",
                                        boardp->id);
                                break;
                        case ASC_WARN_EEPROM_CHKSUM:
                                ASC_PRINT1(
-"AscInitSetConfig: Board %d: EEPROM checksum error\n",
+"AscInitSetConfig: board %d: EEPROM checksum error\n",
                                        boardp->id);
                                break;
                        case ASC_WARN_IRQ_MODIFIED:
                                ASC_PRINT1(
-"AscInitSetConfig: Board %d: IRQ modified\n",
+"AscInitSetConfig: board %d: IRQ modified\n",
                                        boardp->id);
                                break;
                        case ASC_WARN_CMD_QNG_CONFLICT:
                                ASC_PRINT1(
-"AscInitSetConfig: Board %d: tag queuing w/o disconnects\n",
+"AscInitSetConfig: board %d: tag queuing w/o disconnects\n",
                                        boardp->id);
                                break;
                        default:
                                ASC_PRINT2(
-"AscInitSetConfig: Board %d: unknown warning: %x\n",
+"AscInitSetConfig: board %d: unknown warning: %x\n",
                                        boardp->id, ret);
                                break;
                        }
                        if (asc_dvc_varp->err_code != 0) {
                                ASC_PRINT3(
-"AscInitSetConfig: Board %d error: init_state %x, err_code %x\n",
+"AscInitSetConfig: board %d error: init_state %x, err_code %x\n",
                                        boardp->id, asc_dvc_varp->init_state,
                                        asc_dvc_varp->err_code);
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
@@ -3168,6 +3251,16 @@ advansys_detect(Scsi_Host_Template *tpnt)
                                shp->irq = asc_dvc_varp->irq_no;
                        }
 
+                       /*
+                        * One host supports one channel. There are two different
+                        * hosts for each channel of a dual channel board.
+                        */
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
+                       shp->max_channel = 0;
+#endif /* version >= v1.3.89 */
+                       shp->max_id = ASC_MAX_TID + 1;
+                       shp->max_lun = ASC_MAX_LUN + 1;
+
                        shp->io_port = asc_dvc_varp->iop_base;
                        shp->n_io_port = ASC_IOADR_GAP;
                        shp->this_id = asc_dvc_varp->cfg->chip_scsi_id;
@@ -3196,7 +3289,6 @@ advansys_detect(Scsi_Host_Template *tpnt)
                        shp->cmd_per_lun = 0; /* 'cmd_per_lun' is no longer used. */
 #endif /* version >= v1.3.89 */
 
-                       
                        /*
                         * Maximum number of scatter-gather elements adapter can handle.
                         *
@@ -3206,8 +3298,27 @@ advansys_detect(Scsi_Host_Template *tpnt)
 #ifdef MODULE
                        shp->sg_tablesize = 8;
 #else /* MODULE */
-                       shp->sg_tablesize = ASC_MAX_SG_LIST;
+                       /*
+                        * Allow two commands with 'sg_tablesize' scatter-gather
+                        * elements to be executed simultaneously. This value is
+                        * the theoretical hardware limit. It may be decreased
+                        * below.
+                        */
+                       shp->sg_tablesize =
+                               (((asc_dvc_varp->max_total_qng - 2) / 2) *
+                               ASC_SG_LIST_PER_Q) + 1;
 #endif /* MODULE */
+
+                       /*
+                        * The value of 'sg_tablesize' can not exceed the SCSI
+                        * mid-level driver definition of SG_ALL. SG_ALL also
+                        * must not be exceeded, because it is used to define the
+                        * size of the scatter-gather table in 'struct asc_sg_head'.
+                        */
+                       if (shp->sg_tablesize > SG_ALL) {
+                               shp->sg_tablesize = SG_ALL;
+                       }
+
                        ASC_DBG1(1, "advansys_detect: sg_tablesize: %d\n",
                                shp->sg_tablesize);
 
@@ -3231,7 +3342,7 @@ advansys_detect(Scsi_Host_Template *tpnt)
                                shp->dma_channel = asc_dvc_varp->cfg->isa_dma_channel;
                                if ((ret = request_dma(shp->dma_channel, "advansys")) != 0) {
                                        ASC_PRINT3(
-"advansys_detect: Board %d: request_dma() %d failed %d\n",
+"advansys_detect: board %d: request_dma() %d failed %d\n",
                                                boardp->id, shp->dma_channel, ret);
                                        release_region(shp->io_port, shp->n_io_port);
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
@@ -3255,7 +3366,7 @@ advansys_detect(Scsi_Host_Template *tpnt)
                                                        "advansys", boardp)) != 0) {
 #endif /* version >= v1.3.70 */
                                ASC_PRINT2(
-"advansys_detect: Board %d: request_irq() failed %d\n",
+"advansys_detect: board %d: request_irq() failed %d\n",
                                        boardp->id, ret);
                                release_region(shp->io_port, shp->n_io_port);
                                if (shp->dma_channel != NO_ISA_DMA) {
@@ -3275,7 +3386,7 @@ advansys_detect(Scsi_Host_Template *tpnt)
                        ASC_DBG(2, "advansys_detect: AscInitAsc1000Driver()\n");
                        if (AscInitAsc1000Driver(asc_dvc_varp)) {
                                ASC_PRINT3(
-"AscInitAsc1000Driver: Board %d error: init_state %x, err_code %x\n",
+"AscInitAsc1000Driver: board %d: error: init_state %x, err_code %x\n",
                                        boardp->id, asc_dvc_varp->init_state,
                                        asc_dvc_varp->err_code);
                                release_region(shp->io_port, shp->n_io_port);
@@ -3309,7 +3420,7 @@ advansys_detect(Scsi_Host_Template *tpnt)
 int
 advansys_release(struct Scsi_Host *shp)
 {
-       struct asc_board        *boardp;
+       asc_board_t     *boardp;
 
        ASC_DBG(1, "advansys_release: begin\n");
        boardp = ASC_BOARDP(shp);
@@ -3344,18 +3455,23 @@ advansys_release(struct Scsi_Host *shp)
 const char *
 advansys_info(struct Scsi_Host *shp)
 {
-       static char             info[ASC_INFO_SIZE];
-       struct asc_board        *boardp;
-       ASC_DVC_VAR                     *asc_dvc_varp;
-       char                            *busname;
+       static char     info[ASC_INFO_SIZE];
+       asc_board_t             *boardp;
+       ASC_DVC_VAR             *asc_dvc_varp;
+       char                    *busname;
 
        boardp = ASC_BOARDP(shp);
        asc_dvc_varp = &boardp->asc_dvc_var;
        ASC_DBG(1, "advansys_info: begin\n");
        if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
+               if ((asc_dvc_varp->bus_type & ASC_IS_ISAPNP) == ASC_IS_ISAPNP) {
+                       busname = "ISA PnP";
+               } else {
+                       busname = "ISA";
+               }
                sprintf(info,
-                       "AdvanSys SCSI %s: ISA (%u CDB): BIOS %X, IO %X-%X, IRQ %u, DMA %u",
-                       ASC_VERSION, boardp->asc_dvc_var.max_total_qng,
+                       "AdvanSys SCSI %s: %s %u CDB: BIOS %X, IO %X-%X, IRQ %u, DMA %u",
+                       ASC_VERSION, busname, boardp->asc_dvc_var.max_total_qng,
                        (unsigned) shp->base, shp->io_port,
                        shp->io_port + (shp->n_io_port - 1), shp->irq, shp->dma_channel);
        } else {
@@ -3364,16 +3480,21 @@ advansys_info(struct Scsi_Host *shp)
                } else if (asc_dvc_varp->bus_type & ASC_IS_EISA) {
                        busname = "EISA";
                } else if (asc_dvc_varp->bus_type & ASC_IS_PCI) {
-                       busname = "PCI";
+                       if ((asc_dvc_varp->bus_type & ASC_IS_PCI_ULTRA)
+                               == ASC_IS_PCI_ULTRA) {
+                               busname = "PCI Ultra";
+                       } else {
+                               busname = "PCI";
+                       }
                } else {
                        busname = "?";
                        ASC_PRINT2(
-"advansys_info: Board %d: unknown bus type %d\n",
+"advansys_info: board %d: unknown bus type %d\n",
                                boardp->id, asc_dvc_varp->bus_type);
                }
                /* No DMA channel for non-ISA busses. */
                sprintf(info,
-                       "AdvanSys SCSI %s: %s (%u CDB): BIOS %X, IO %X-%X, IRQ %u",
+                       "AdvanSys SCSI %s: %s %u CDB: BIOS %X, IO %X-%X, IRQ %u",
                        ASC_VERSION, busname, boardp->asc_dvc_var.max_total_qng,
                        (unsigned) shp->base, shp->io_port,
                        shp->io_port + (shp->n_io_port - 1), shp->irq);
@@ -3416,52 +3537,88 @@ advansys_command(Scsi_Cmnd *scp)
 int
 advansys_queuecommand(Scsi_Cmnd *scp, void (*done)(Scsi_Cmnd *))
 {
-       struct Scsi_Host                *shp;
-       struct asc_board                *boardp;
-       int                                             flags = 0;
-       int                                             interrupts_disabled;
+       struct Scsi_Host        *shp;
+       asc_board_t                     *boardp;
+       int                                     flags;
+       Scsi_Cmnd                       *done_scp;
 
        shp = scp->host;
        boardp = ASC_BOARDP(shp);
        ASC_STATS(shp, queuecommand);
 
        /*
-        * If there are any pending commands for this board before trying
-        * to execute them, disable interrupts to preserve request ordering.
-        *
-        * The typical case will be no pending commands and interrupts
-        * not disabled.
+        * Disable interrupts to preserve request ordering and provide
+        * mutually exclusive access to global structures used to initiate
+        * a request.
         */
-       if (boardp->pending.tidmask == 0) {
-               interrupts_disabled = ASC_FALSE;
-       } else {
-               /* Disable interrupts */
-               interrupts_disabled = ASC_TRUE;
-               save_flags(flags);
-               cli();
-               ASC_DBG1(1, "advansys_queuecommand: asc_execute_queue() %x\n",
-                       boardp->pending.tidmask);
-               asc_execute_queue(&boardp->pending);
-       }
+       save_flags(flags);
+       cli();
 
        /*
-        * Save the function pointer to Linux mid-level 'done' function and
-        * execute the command.
+        * Block new commands while handling a reset or abort request.
         */
-       scp->scsi_done = done;
-       if (asc_execute_scsi_cmnd(scp) == ASC_BUSY) {
-               if (interrupts_disabled == ASC_FALSE) {
-                       save_flags(flags);
-                       cli();
-                       interrupts_disabled = ASC_TRUE;
+       if (boardp->flags & (ASC_HOST_IN_RESET | ASC_HOST_IN_ABORT)) {
+               if (boardp->flags & ASC_HOST_IN_RESET) {
+                       ASC_DBG1(1,
+                               "advansys_queuecommand: scp %x blocked for reset request\n",
+                               (unsigned) scp);
+                       scp->result = HOST_BYTE(DID_RESET);
+               } else {
+                       ASC_DBG1(1,
+                               "advansys_queuecommand: scp %x blocked for abort request\n",
+                               (unsigned) scp);
+                       scp->result = HOST_BYTE(DID_ABORT);
                }
-               asc_enqueue(&boardp->pending, scp, ASC_BACK);
-       }
 
-       if (interrupts_disabled == ASC_TRUE) {
+               /*
+                * Add blocked requests to the board's 'scsi_done_q'. The queued
+                * requests will be completed at the end of the abort or reset
+                * handling.
+                */
+               asc_enqueue(&boardp->scsi_done_q, scp, ASC_BACK);
                restore_flags(flags);
+               return 0;
+       }
+
+       /*
+        * Attempt to execute any waiting commands for the board.
+        */
+       if (!ASC_QUEUE_EMPTY(&boardp->waiting)) {
+               ASC_DBG(1,
+                       "advansys_queuecommand: before asc_execute_queue() waiting\n");
+               asc_execute_queue(&boardp->waiting);
+       }
+
+       /*
+        * Save the function pointer to Linux mid-level 'done' function
+        * and attempt to execute the command.
+        *
+        * If ASC_ERROR is returned the request has been added to the
+        * board's 'active' queue and will be completed by the interrupt
+        * handler.
+        *
+        * If ASC_BUSY is returned add the request to the board's per
+        * target waiting list.
+        * 
+        * If an error occurred, the request will have been placed on the
+        * board's 'scsi_done_q' and must be completed before returning.
+        */
+       scp->scsi_done = done;
+       switch (asc_execute_scsi_cmnd(scp)) {
+       case ASC_NOERROR:
+               break;
+       case ASC_BUSY:
+               asc_enqueue(&boardp->waiting, scp, ASC_BACK);
+               break;
+       case ASC_ERROR:
+       default:
+               done_scp = asc_dequeue_list(&boardp->scsi_done_q, NULL, ASC_TID_ALL);
+               /* Interrupts could be enabled here. */
+               asc_scsi_done_list(done_scp);
+               break;
        }
 
+       restore_flags(flags);
        return 0;
 }
 
@@ -3473,49 +3630,70 @@ advansys_queuecommand(Scsi_Cmnd *scp, void (*done)(Scsi_Cmnd *))
 int
 advansys_abort(Scsi_Cmnd *scp)
 {
-       struct asc_board        *boardp;
+       struct Scsi_Host        *shp;
+       asc_board_t                     *boardp;
        ASC_DVC_VAR                     *asc_dvc_varp;
        int                                     flags;
-       int                                     abort;
-       int                                     ret;
+       int                                     status = ASC_FALSE;
+       int                                     abort_do_done = ASC_FALSE;
+       Scsi_Cmnd                       *done_scp;
+       int                                     ret = ASC_ERROR;
 
        ASC_DBG1(1, "advansys_abort: scp %x\n", (unsigned) scp);
-       ASC_STATS(scp->host, abort);
 
        /* Save current flags and disable interrupts. */
        save_flags(flags);
        cli();
 
+#ifdef ADVANSYS_STATS
+       if (scp->host != NULL) {
+               ASC_STATS(scp->host, abort);
+       }       
+#endif /* ADVANSYS_STATS */
+
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
        if (scp->serial_number != scp->serial_number_at_timeout) {
                ret = SCSI_ABORT_NOT_RUNNING;
        } else
 #endif /* version >= v1.3.89 */
-       if (scp->host == NULL) {
+       if ((shp = scp->host) == NULL) {
+               scp->result = HOST_BYTE(DID_ERROR);
+               ret = SCSI_ABORT_ERROR;
+       } else if ((boardp = ASC_BOARDP(shp))->flags & 
+                               (ASC_HOST_IN_RESET | ASC_HOST_IN_ABORT)) {
+               ASC_PRINT2(
+"advansys_abort: board %d: Nested host reset or abort, flags 0x%x\n",
+                       boardp->id, boardp->flags);
                scp->result = HOST_BYTE(DID_ERROR);
                ret = SCSI_ABORT_ERROR;
        } else {
-               boardp = ASC_BOARDP(scp->host);
-               if (asc_rmqueue(&boardp->pending, scp) == ASC_TRUE) {
+               /* Set abort flag to avoid nested reset or abort requests. */
+               boardp->flags |= ASC_HOST_IN_ABORT;
+
+               if (asc_rmqueue(&boardp->waiting, scp) == ASC_TRUE) {
                        /*
-                        * If asc_rmqueue() found the command on the pending
-                        * queue, it had not been sent to the Asc Library.
-                        * After the queue is removed, no other handling is required.
+                        * If asc_rmqueue() found the command on the waiting
+                        * queue, it had not been sent to the device. After
+                        * the queue is removed, no other handling is required.
                         */
+                       ASC_DBG1(1, "advansys_abort: scp %x found on waiting queue\n",
+                               (unsigned) scp);
                        scp->result = HOST_BYTE(DID_ABORT);
                        ret = SCSI_ABORT_SUCCESS;
                } else if (asc_isqueued(&boardp->active, scp) == ASC_TRUE) {
                        /*
                         * If asc_isqueued() found the command on the active
-                        * queue, it has been sent to the Asc Library. The
-                        * command should be returned through the interrupt
-                        * handler after calling AscAbortSRB().
+                        * queue, it has been sent to the device. The command
+                        * should be returned through the interrupt handler after
+                        * calling AscAbortSRB().
                         */
                        asc_dvc_varp = &boardp->asc_dvc_var;
                        scp->result = HOST_BYTE(DID_ABORT);
-                       /* Must enable interrupts for AscAbortSRB() */
-                       sti();
-                       switch (abort = AscAbortSRB(asc_dvc_varp, (ulong) scp)) {
+
+                       sti(); /* Enable interrupts for AscAbortSRB(). */
+                       ASC_DBG1(1, "advansys_abort: before AscAbortSRB(), scp %x\n",
+                               (unsigned) scp);
+                       switch (status = AscAbortSRB(asc_dvc_varp, (ulong) scp)) {
                        case ASC_TRUE:
                                /* asc_isr_callback() will be called */
                                ASC_DBG(1, "advansys_abort: AscAbortSRB() TRUE\n");
@@ -3533,25 +3711,69 @@ advansys_abort(Scsi_Cmnd *scp)
                                break;
                        }
                        cli();
+
                        /*
                         * If the abort failed, remove the request from the
                         * active list and complete it.
                         */
-                       if (abort != ASC_TRUE) {
+                       if (status != ASC_TRUE) {
                                if (asc_rmqueue(&boardp->active, scp) == ASC_TRUE) {
                                        scp->result = HOST_BYTE(DID_ABORT);
-                                       scp->scsi_done(scp);
+                                       abort_do_done = ASC_TRUE;
                                }
                        }
+
                } else {
                        /*
-                        * The command was not found on the active or pending queues.
+                        * The command was not found on the active or waiting queues.
                         */
                        ret = SCSI_ABORT_NOT_RUNNING;
                }
+
+               /* Clear abort flag. */
+               boardp->flags &= ~ASC_HOST_IN_ABORT;
+
+               /*
+                * Because the ASC_HOST_IN_ABORT flag causes both
+                * 'advansys_interrupt' and 'asc_isr_callback' to
+                * queue requests to the board's 'scsi_done_q' and
+                * prevents waiting commands from being executed,
+                * these queued requests must be handled here.
+                */
+               done_scp = asc_dequeue_list(&boardp->scsi_done_q, NULL, ASC_TID_ALL);
+
+               /*
+                * Start any waiting commands for the board.
+                */
+               if (!ASC_QUEUE_EMPTY(&boardp->waiting)) {
+                       ASC_DBG(1, "advansys_interrupt: before asc_execute_queue()\n");
+                       asc_execute_queue(&boardp->waiting);
+               }
+
+               /* Interrupts could be enabled here. */
+
+               /*
+                * If needed, complete the aborted request.
+                */
+               if (abort_do_done == ASC_TRUE) {
+                       ASC_STATS(scp->host, done);
+                       scp->scsi_done(scp);
+               }
+
+               /*
+                * It is possible for the request done function to re-enable
+                * interrupts without confusing the driver. But here interrupts
+                * aren't enabled until all requests have been completed.
+                */
+               asc_scsi_done_list(done_scp);
        }
-       restore_flags(flags);
+
        ASC_DBG1(1, "advansys_abort: ret %d\n", ret);
+
+       /* Re-enable interrupts, if they were enabled on entry. */
+       restore_flags(flags);
+
+       ASC_ASSERT(ret != ASC_ERROR);
        return ret;
 }
 
@@ -3567,44 +3789,74 @@ advansys_reset(Scsi_Cmnd *scp)
 advansys_reset(Scsi_Cmnd *scp, unsigned int reset_flags)
 #endif /* version >= v1.3.89 */
 {
-       struct asc_board        *boardp;
+       struct Scsi_Host        *shp;
+       asc_board_t                     *boardp;
        ASC_DVC_VAR                     *asc_dvc_varp;
        int                                     flags;
-       Scsi_Cmnd                       *tscp;
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
+       Scsi_Cmnd                       *done_scp = NULL, *last_scp = NULL;
+       Scsi_Cmnd                       *tscp, *new_last_scp;
        int                                     scp_found = ASC_FALSE;
-#endif /* version >= v1.3.89 */
-       int                                     i;
-       int                                     ret;
+       int                             device_reset = ASC_FALSE;
+       int                                     status;
+       int                                     target;
+       int                                     ret = ASC_ERROR;
 
        ASC_DBG1(1, "advansys_reset: %x\n", (unsigned) scp);
-       ASC_STATS(scp->host, reset);
 
        /* Save current flags and disable interrupts. */
        save_flags(flags);
        cli();
 
+#ifdef ADVANSYS_STATS
+       if (scp->host != NULL) {
+               ASC_STATS(scp->host, reset);
+       }       
+#endif /* ADVANSYS_STATS */
+
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
        if (scp->serial_number != scp->serial_number_at_timeout) {
                ret = SCSI_RESET_NOT_RUNNING;
        } else
 #endif /* version >= v1.3.89 */
-       if (scp->host == NULL) {
+       if ((shp = scp->host) == NULL) {
+               scp->result = HOST_BYTE(DID_ERROR);
+               ret = SCSI_RESET_ERROR;
+       } else if ((boardp = ASC_BOARDP(shp))->flags & 
+                               (ASC_HOST_IN_RESET | ASC_HOST_IN_ABORT)) {
+               ASC_PRINT2(
+"advansys_reset: board %d: Nested host reset or abort, flags 0x%x\n",
+                       boardp->id, boardp->flags);
+               scp->result = HOST_BYTE(DID_ERROR);
+               ret = SCSI_RESET_ERROR;
+       } else if (jiffies >= boardp->reset_jiffies &&
+                          jiffies < (boardp->reset_jiffies + (10 * HZ))) {
+               /*
+                * Don't allow a reset to be attempted within 10 seconds
+                * of the last reset.
+                *
+                * If 'jiffies' wrapping occurs, the reset request will go
+                * through, because a wrapped 'jiffies' would not pass the
+                * test above.
+                */
+               ASC_DBG(1,
+                       "advansys_reset: reset within 10 sec of last reset ignored\n");
                scp->result = HOST_BYTE(DID_ERROR);
                ret = SCSI_RESET_ERROR;
        } else {
-               boardp = ASC_BOARDP(scp->host);
+               /* Set reset flag to avoid nested reset or abort requests. */
+               boardp->flags |= ASC_HOST_IN_RESET;
 
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
                /*
-                * If the request is on the target pending or active queue,
-                * note that it was found.
+                * If the request is on the target waiting or active queue,
+                * note that it was found and remove it from its queue.
                 */
-               if ((asc_isqueued(&boardp->pending, scp) == ASC_TRUE) ||
-                   (asc_isqueued(&boardp->active, scp) == ASC_TRUE)) {
+               if (asc_rmqueue(&boardp->active, scp) == ASC_TRUE) {
+                       ASC_DBG(1, "advansys_reset: active scp_found = TRUE\n");
+                       scp_found = ASC_TRUE;
+               } else if (asc_rmqueue(&boardp->waiting, scp) == ASC_TRUE) {
+                       ASC_DBG(1, "advansys_reset: waiting scp_found = TRUE\n");
                        scp_found = ASC_TRUE;
                }
-#endif /* version >= v1.3.89 */
 
                /*
                 * If the suggest reset bus flags are set, reset the bus.
@@ -3616,86 +3868,193 @@ advansys_reset(Scsi_Cmnd *scp, unsigned int reset_flags)
                        (SCSI_RESET_SUGGEST_BUS_RESET | SCSI_RESET_SUGGEST_HOST_RESET)) {
 #endif /* version >= v1.3.89 */
 
-                       /*
-                        * Done all pending requests for all targets with DID_RESET.
-                        */
-                       for (i = 0; i <= ASC_MAX_TID; i++) {
-                               while ((tscp = asc_dequeue(&boardp->pending, i)) != NULL) {
-                                       tscp->result = HOST_BYTE(DID_RESET);
-                                       tscp->scsi_done(tscp);
-                               }
-                       }
-
                        /*
                         * Reset the target's SCSI bus.
                         */
+                       ASC_DBG(1, "advansys_reset: before AscResetSB()\n");
                        sti();  /* Enable interrupts for AscResetSB(). */
-                       switch (AscResetSB(asc_dvc_varp)) {
+                       status = AscResetSB(asc_dvc_varp);
+                       cli();
+                       switch (status) {
                        case ASC_TRUE:
-                               ASC_DBG(1, "advansys_reset: AscResetSB() TRUE\n");
+                               ASC_DBG(1, "advansys_reset: AscResetSB() success\n");
                                ret = SCSI_RESET_SUCCESS;
                                break;
                        case ASC_ERROR:
                        default:
-                               ASC_DBG(1, "advansys_reset: AscResetSB() ERROR\n");
+                               ASC_DBG(1, "advansys_reset: AscResetSB() failed\n");
                                ret = SCSI_RESET_ERROR;
                                break;
                        }
-                       cli();
 
-                       /*
-                        * Done all active requests for all targets with DID_RESET.
-                        */
-                       for (i = 0; i <= ASC_MAX_TID; i++) {
-                               while ((tscp = asc_dequeue(&boardp->active, i)) != NULL) {
-                                       tscp->result = HOST_BYTE(DID_RESET);
-                                       tscp->scsi_done(tscp);
-                               }
-                       }
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
                } else {
                        /*
-                        * Done all pending requests for the target with DID_RESET.
+                        * Reset the specified device. If the device reset fails,
+                        * then reset the SCSI bus.
                         */
-                       while ((tscp = asc_dequeue(&boardp->pending, scp->target))
-                                       != NULL) {
-                               tscp->result = HOST_BYTE(DID_RESET);
-                               tscp->scsi_done(tscp);
-                       }
 
-                       sti();  /* Enabled interrupts for AscResetDevice(). */
-                       ASC_DBG(1, "advansys_reset: AscResetDevice()\n");
-                       (void) AscResetDevice(asc_dvc_varp, scp->target);
+                       ASC_DBG1(1, "advansys_reset: before AscResetDevice(), target %d\n",
+                               scp->target);
+                       sti();  /* Enable interrupts for AscResetDevice(). */
+                       status = AscResetDevice(asc_dvc_varp, scp->target);
                        cli();
 
                        /*
-                        * Done all active requests for the target with DID_RESET.
+                        * If the device has been reset, try to initialize it.
                         */
-                       while ((tscp = asc_dequeue(&boardp->active, scp->target))
-                                       != NULL) {
-                               tscp->result = HOST_BYTE(DID_RESET);
-                               tscp->scsi_done(tscp);
+                       if (status == ASC_TRUE) {
+                               status = asc_init_dev(asc_dvc_varp, scp);
+                       }
+
+                       switch (status) {
+                       case ASC_TRUE:
+                               ASC_DBG(1, "advansys_reset: AscResetDevice() success\n");
+                               device_reset = ASC_TRUE;
+                               ret = SCSI_RESET_SUCCESS;
+                               break;
+                       case ASC_ERROR:
+                       default:
+                               ASC_DBG(1,
+"advansys_reset: AscResetDevice() failed; Calling AscResetSB()\n");
+                               sti();  /* Enable interrupts for AscResetSB(). */
+                               status = AscResetSB(asc_dvc_varp);
+                               cli();
+                               switch (status) {
+                               case ASC_TRUE:
+                                       ASC_DBG(1, "advansys_reset: AscResetSB() TRUE\n");
+                                       ret = SCSI_RESET_SUCCESS;
+                                       break;
+                               case ASC_ERROR:
+                               default:
+                                       ASC_DBG(1, "advansys_reset: AscResetSB() ERROR\n");
+                                       ret = SCSI_RESET_ERROR;
+                                       break;
+                               }
+                               break;
                        }
                }
 #endif /* version >= v1.3.89 */
 
+               /*
+                * Because the ASC_HOST_IN_RESET flag causes both
+                * 'advansys_interrupt' and 'asc_isr_callback' to
+                * queue requests to the board's 'scsi_done_q' and
+                * prevents waiting commands from being executed,
+                * these queued requests must be handled here.
+                */
+               done_scp = asc_dequeue_list(&boardp->scsi_done_q, &last_scp,
+                                                                       ASC_TID_ALL);
+
+               /*
+                * If a device reset was performed dequeue all waiting
+                * and active requests for the device and set the request
+                * status to DID_RESET.
+                *
+                * If a SCSI bus reset was performed dequeue all waiting
+                * and active requests for all devices and set the request
+                * status to DID_RESET.
+                */
+               if (device_reset == ASC_TRUE) {
+                       target = scp->target;
+               } else {
+                       target = ASC_TID_ALL;
+               }
+
+               /*
+                * Add active requests to 'done_scp' and set the request status
+                * to DID_RESET.
+                */
+               if (done_scp == NULL) {
+                       done_scp = asc_dequeue_list(&boardp->active, &last_scp, target);
+                       for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) {
+                               tscp->result = HOST_BYTE(DID_RESET);
+                       }
+               } else {
+                       ASC_ASSERT(last_scp != NULL);
+                       REQPNEXT(last_scp) = asc_dequeue_list(&boardp->active,
+                               &new_last_scp, target);
+                       if (new_last_scp != NULL) {
+                               ASC_ASSERT(REQPNEXT(last_scp) != NULL);
+                               for (tscp = REQPNEXT(last_scp); tscp; tscp = REQPNEXT(tscp)) {
+                                       tscp->result = HOST_BYTE(DID_RESET);
+                               }
+                               last_scp = new_last_scp;
+                       }
+               }
+
+               /*
+                * Add waiting requests to 'done_scp' and set the request status
+                * to DID_RESET.
+                */
+               if (done_scp == NULL) {
+                       done_scp = asc_dequeue_list(&boardp->waiting, &last_scp, target);
+                       for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) {
+                               tscp->result = HOST_BYTE(DID_RESET);
+                       }
+               } else {
+                       ASC_ASSERT(last_scp != NULL);
+                       REQPNEXT(last_scp) = asc_dequeue_list(&boardp->waiting,
+                               &new_last_scp, target);
+                       if (new_last_scp != NULL) {
+                               ASC_ASSERT(REQPNEXT(last_scp) != NULL);
+                               for (tscp = REQPNEXT(last_scp); tscp; tscp = REQPNEXT(tscp)) {
+                                       tscp->result = HOST_BYTE(DID_RESET);
+                               }
+                               last_scp = new_last_scp;
+                       }
+               }
+
+               /* Save the time of the most recently completed reset. */
+               boardp->reset_jiffies = jiffies;
+
+               /* Clear reset flag. */
+               boardp->flags &= ~ASC_HOST_IN_RESET;
+
+               /*
+                * Start any waiting commands for the board.
+                */
+               if (!ASC_QUEUE_EMPTY(&boardp->waiting)) {
+                       ASC_DBG(1, "advansys_interrupt: before asc_execute_queue()\n");
+                       asc_execute_queue(&boardp->waiting);
+               }
+
+               /* Interrupts could be enabled here. */
+
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
                /*
-                * If the command was not on the active or pending request
-                * queues and the SCSI_RESET_SYNCHRONOUS flag is set, then
-                * done the command now. If the command had been on the
-                * active or pending request queues it would have already
-                * been completed.
+                * If the command was found on the active or waiting request
+                * queues or if the the SCSI_RESET_SYNCHRONOUS flag is set,
+                * then done the command now.
                 */
-               if (scp_found == ASC_FALSE && (reset_flags & SCSI_RESET_SYNCHRONOUS)) {
+               if (scp_found == ASC_TRUE || (reset_flags & SCSI_RESET_SYNCHRONOUS)) {
                        scp->result = HOST_BYTE(DID_RESET);
-                       scp->scsi_done(tscp);
+                       ASC_STATS(scp->host, done);
+                       scp->scsi_done(scp);
+               }
+#else /* version >= v1.3.89 */
+               if (scp_found == ASC_TRUE) {
+                       scp->result = HOST_BYTE(DID_RESET);
+                       ASC_STATS(scp->host, done);
+                       scp->scsi_done(scp);
                }
 #endif /* version >= v1.3.89 */
                ret = SCSI_RESET_SUCCESS;
+
+               /*
+                * It is possible for the request done function to re-enable
+                * interrupts without confusing the driver. But here interrupts
+                * aren't enabled until requests have been completed.
+                */
+               asc_scsi_done_list(done_scp);
        }
-       restore_flags(flags);
+
        ASC_DBG1(1, "advansys_reset: ret %d", ret);
+
+       /* Re-enable interrupts, if they were enabled on entry. */
+       restore_flags(flags);
+
+       ASC_ASSERT(ret != ASC_ERROR);
        return ret;
 }
 
@@ -3826,10 +4185,10 @@ Scsi_Host_Template driver_template = ADVANSYS;
  * First-level interrupt handler.
  *
  * For versions > v1.3.70, 'dev_id' is a pointer to the interrupting
- * adapter's struct asc_board. Because all boards are currently checked
+ * adapter's asc_board_t. Because all boards are currently checked
  * for interrupts on each interrupt, 'dev_id' is not referenced. 'dev_id'
- * could be used to identify an interrupt passed to the AdvanSys driver
- * but actually for a device sharing an interrupt with an AdvanSys adapter.
+ * could be used to identify an interrupt passed to the AdvanSys driver,
+ * which is for a device sharing an interrupt with an AdvanSys adapter.
  */
 STATIC void
 #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,70)
@@ -3838,12 +4197,13 @@ advansys_interrupt(int irq, struct pt_regs *regs)
 advansys_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 #endif /* version >= v1.3.70 */
 {
-       int                     i;
-       int                     flags;
-       Scsi_Cmnd       *scp;
-       Scsi_Cmnd       *tscp;
+       int                             flags;
+       int                             i;
+       asc_board_t             *boardp;
+       Scsi_Cmnd               *done_scp = NULL, *last_scp = NULL;
+       Scsi_Cmnd               *new_last_scp;
 
-       /* Disable interrupts, if the aren't already disabled. */
+       /* Disable interrupts, if they aren't already disabled. */
        save_flags(flags);
        cli();
 
@@ -3854,31 +4214,57 @@ advansys_interrupt(int irq, void *dev_id, struct pt_regs *regs)
         */
        for (i = 0; i < asc_board_count; i++) {
                ASC_STATS(asc_host[i], check_interrupt);
+               boardp = ASC_BOARDP(asc_host[i]);
                while (AscIsIntPending(asc_host[i]->io_port)) {
                        ASC_STATS(asc_host[i], interrupt);
                        ASC_DBG(1, "advansys_interrupt: before AscISR()\n");
-                       AscISR(&ASC_BOARDP(asc_host[i])->asc_dvc_var);
+                       AscISR(&boardp->asc_dvc_var);
+               }
+
+               /*
+                * Start waiting requests and create a list of completed requests.
+                * 
+                * If a reset or abort request is being performed for the board,
+                * the reset or abort handler will complete pending requests after
+                * it has completed.
+                */
+       if ((boardp->flags & (ASC_HOST_IN_RESET | ASC_HOST_IN_ABORT)) == 0) {
+                       /* Start any waiting commands for the board. */
+                       if (!ASC_QUEUE_EMPTY(&boardp->waiting)) {
+                               ASC_DBG(1, "advansys_interrupt: before asc_execute_queue()\n");
+                               asc_execute_queue(&boardp->waiting);
+                       }
+
+                       /*
+                        * Add to the list of requests that must be completed.
+                        */
+                       if (done_scp == NULL) {
+                               done_scp = asc_dequeue_list(&boardp->scsi_done_q, &last_scp,
+                                       ASC_TID_ALL);
+                       } else {
+                               ASC_ASSERT(last_scp != NULL);
+                               REQPNEXT(last_scp) = asc_dequeue_list(&boardp->scsi_done_q,
+                                       &new_last_scp, ASC_TID_ALL);
+                               if (new_last_scp != NULL) {
+                                       ASC_ASSERT(REQPNEXT(last_scp) != NULL);
+                                       last_scp = new_last_scp;
+                               }
+                       }
                }
        }
 
+       /* Interrupts could be enabled here. */
+
        /*
-        * While interrupts are still disabled save the list of requests that
-        * need their done function called. After re-enabling interrupts call
-        * the done function which may re-enable interrupts anyway.
+        * It is possible for the request done function to re-enable
+        * interrupts without confusing the driver. But here interrupts
+        * aren't enabled until all requests have been completed.
         */
-       if ((scp = asc_scsi_done) != NULL) {
-               asc_scsi_done = NULL;
-       }
+       asc_scsi_done_list(done_scp);
 
        /* Re-enable interrupts, if they were enabled on entry. */
        restore_flags(flags);
 
-       while (scp) {
-               tscp = (Scsi_Cmnd *) scp->host_scribble;
-               scp->scsi_done(scp);
-               scp = tscp;
-       }
-
        ASC_DBG(1, "advansys_interrupt: end\n");
        return;
 }
@@ -3891,8 +4277,8 @@ advansys_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 STATIC void
 advansys_select_queue_depths(struct Scsi_Host *shp, Scsi_Device *devicelist)
 {
-       Scsi_Device                     *device;
-       struct asc_board        *boardp;
+       Scsi_Device             *device;
+       asc_board_t             *boardp;
 
        boardp = ASC_BOARDP(shp);
        for (device = devicelist; device != NULL; device = device->next) {
@@ -3917,6 +4303,27 @@ advansys_command_done(Scsi_Cmnd *scp)
        scp->SCp.Status = 1;
 }
 
+/*
+ * Complete all requests on the singly linked list pointed
+ * to by 'scp'.
+ *
+ * Interrupts can be enabled on entry.
+ */
+STATIC void
+asc_scsi_done_list(Scsi_Cmnd *scp)
+{
+       Scsi_Cmnd       *tscp;
+
+       while (scp != NULL) {
+               tscp = REQPNEXT(scp);
+               REQPNEXT(scp) = NULL;
+               ASC_STATS(scp->host, done);
+               scp->scsi_done(scp);
+               scp = tscp;
+       }
+       return;
+}
+
 /*
  * Execute a single 'Scsi_Cmnd'.
  *
@@ -3952,20 +4359,21 @@ advansys_command_done(Scsi_Cmnd *scp)
  *  scsi_done - used to save caller's done function
  *     host_scribble - used for pointer to another Scsi_Cmnd
  *
- * If this function returns ASC_NOERROR or ASC_ERROR the done
- * function has been called. If ASC_BUSY is returned the request
- * must be enqueued by the caller and re-tried later.
+ * If this function returns ASC_NOERROR or ASC_ERROR the request
+ * has been enqueued on the board's 'scsi_done_q' and must be
+ * completed by the caller.
+ *
+ * If ASC_BUSY is returned the request must be enqueued by the
+ * caller and re-tried later.
  */
 STATIC int
 asc_execute_scsi_cmnd(Scsi_Cmnd *scp)
 {
-       struct asc_board        *boardp;
-       ASC_DVC_VAR                     *asc_dvc_varp;
-       ASC_SCSI_Q                      scsiq;
-       ASC_SG_HEAD                     sghead;
-       int                                     flags;
-       int                                     ret;
+       asc_board_t             *boardp;
+       ASC_DVC_VAR             *asc_dvc_varp;
+       int                             ret;
 
+       ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
        ASC_DBG2(1, "asc_execute_scsi_cmnd: scp %x, done %x\n",
                (unsigned) scp, (unsigned) scp->scsi_done);
 
@@ -3979,30 +4387,34 @@ asc_execute_scsi_cmnd(Scsi_Cmnd *scp)
        if ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(scp->target)) == 0) {
                if (asc_init_dev(asc_dvc_varp, scp) == ASC_FALSE) {
                        scp->result = HOST_BYTE(DID_BAD_TARGET);
-                       scp->scsi_done(scp);
+                       asc_enqueue(&boardp->scsi_done_q, scp, ASC_BACK);
                        return ASC_ERROR;
                }
                boardp->init_tidmask |= ASC_TIX_TO_TARGET_ID(scp->target);
        }
 
-       memset(&scsiq, 0, sizeof(ASC_SCSI_Q));
+       /*
+        * Mutually exclusive access is required to 'asc_scsi_q' and
+        * 'asc_sg_head' until after the request is started.
+        */
+       memset(&asc_scsi_q, 0, sizeof(ASC_SCSI_Q));
 
        /*
         * Point the ASC_SCSI_Q to the 'Scsi_Cmnd'.
         */
-       scsiq.q2.srb_ptr = (ulong) scp;
+       asc_scsi_q.q2.srb_ptr = (ulong) scp;
 
        /*
         * Build the ASC_SCSI_Q request.
         */
-       scsiq.cdbptr = &scp->cmnd[0];
-       scsiq.q2.cdb_len = scp->cmd_len;
-       scsiq.q1.target_id = ASC_TID_TO_TARGET_ID(scp->target);
-       scsiq.q1.target_lun = scp->lun;
-       scsiq.q2.target_ix = ASC_TIDLUN_TO_IX(scp->target, scp->lun);
-       scsiq.q1.sense_addr = (ulong) &scp->sense_buffer[0];
-       scsiq.q1.sense_len = sizeof(scp->sense_buffer);
-       scsiq.q2.tag_code = M2_QTAG_MSG_SIMPLE;
+       asc_scsi_q.cdbptr = &scp->cmnd[0];
+       asc_scsi_q.q2.cdb_len = scp->cmd_len;
+       asc_scsi_q.q1.target_id = ASC_TID_TO_TARGET_ID(scp->target);
+       asc_scsi_q.q1.target_lun = scp->lun;
+       asc_scsi_q.q2.target_ix = ASC_TIDLUN_TO_IX(scp->target, scp->lun);
+       asc_scsi_q.q1.sense_addr = (ulong) &scp->sense_buffer[0];
+       asc_scsi_q.q1.sense_len = sizeof(scp->sense_buffer);
+       asc_scsi_q.q2.tag_code = M2_QTAG_MSG_SIMPLE;
 
        /*
         * Build ASC_SCSI_Q for a contiguous buffer or a scatter-gather
@@ -4014,12 +4426,12 @@ asc_execute_scsi_cmnd(Scsi_Cmnd *scp)
                 */
                ASC_STATS(scp->host, cont_cnt);
                /* request_buffer is already a real address. */
-               scsiq.q1.data_addr = (ulong) scp->request_buffer;
-               scsiq.q1.data_cnt = scp->request_bufflen;
+               asc_scsi_q.q1.data_addr = (ulong) scp->request_buffer;
+               asc_scsi_q.q1.data_cnt = scp->request_bufflen;
                ASC_STATS_ADD(scp->host, cont_xfer,
                                          ASC_CEILING(scp->request_bufflen, 512));
-               scsiq.q1.sg_queue_cnt = 0;
-               scsiq.sg_head = NULL;
+               asc_scsi_q.q1.sg_queue_cnt = 0;
+               asc_scsi_q.sg_head = NULL;
        } else {
                /*
                 * CDB scatter-gather request list.
@@ -4027,11 +4439,12 @@ asc_execute_scsi_cmnd(Scsi_Cmnd *scp)
                int                                     sgcnt;
                struct scatterlist      *slp;
 
-               if (scp->use_sg > ASC_MAX_SG_LIST) {
-                       ASC_PRINT3("asc_execute_scsi_cmnd: Board %d: use_sg %d > %d\n",
-                               boardp->id, scp->use_sg, ASC_MAX_SG_LIST);
+               if (scp->use_sg > scp->host->sg_tablesize) {
+                       ASC_PRINT3(
+"asc_execute_scsi_cmnd: board %d: use_sg %d > sg_tablesize %d\n",
+                               boardp->id, scp->use_sg, scp->host->sg_tablesize);
                        scp->result = HOST_BYTE(DID_ERROR);
-                       scp->scsi_done(scp);
+                       asc_enqueue(&boardp->scsi_done_q, scp, ASC_BACK);
                        return ASC_ERROR;
                }
 
@@ -4041,40 +4454,37 @@ asc_execute_scsi_cmnd(Scsi_Cmnd *scp)
                 * Allocate a ASC_SG_HEAD structure and set the ASC_SCSI_Q
                 * to point to it.
                 */
-               memset(&sghead, 0, sizeof(ASC_SG_HEAD));
+               memset(&asc_sg_head, 0, sizeof(ASC_SG_HEAD));
 
-               scsiq.q1.cntl |= QC_SG_HEAD;
-               scsiq.sg_head = &sghead;
-               scsiq.q1.data_cnt = 0;
-               scsiq.q1.data_addr = 0;
-               sghead.entry_cnt = scsiq.q1.sg_queue_cnt = scp->use_sg;
-               ASC_STATS_ADD(scp->host, sg_elem, sghead.entry_cnt);
+               asc_scsi_q.q1.cntl |= QC_SG_HEAD;
+               asc_scsi_q.sg_head = &asc_sg_head;
+               asc_scsi_q.q1.data_cnt = 0;
+               asc_scsi_q.q1.data_addr = 0;
+               asc_sg_head.entry_cnt = asc_scsi_q.q1.sg_queue_cnt = scp->use_sg;
+               ASC_STATS_ADD(scp->host, sg_elem, asc_sg_head.entry_cnt);
 
                /*
                 * Convert scatter-gather list into ASC_SG_HEAD list.
                 */
                slp = (struct scatterlist *) scp->request_buffer;
                for (sgcnt = 0; sgcnt < scp->use_sg; sgcnt++, slp++) {
-                       sghead.sg_list[sgcnt].addr = (ulong) slp->address;
-                       sghead.sg_list[sgcnt].bytes = slp->length;
+                       asc_sg_head.sg_list[sgcnt].addr = (ulong) slp->address;
+                       asc_sg_head.sg_list[sgcnt].bytes = slp->length;
                        ASC_STATS_ADD(scp->host, sg_xfer, ASC_CEILING(slp->length, 512));
                }
        }
 
-       ASC_DBG_PRT_SCSI_Q(2, &scsiq);
+       ASC_DBG_PRT_SCSI_Q(2, &asc_scsi_q);
        ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len);
 
        /*
-        * Disable interrupts to issue the command and add the
-        * command to the active queue if it is started.
+        * Execute the command. If there is no error, add the command
+        * to the active queue.
         */
-       save_flags(flags);
-       cli();
-
-       switch (ret = AscExeScsiQueue(asc_dvc_varp, &scsiq)) {
+       switch (ret = AscExeScsiQueue(asc_dvc_varp, &asc_scsi_q)) {
        case ASC_NOERROR:
-               asc_enqueue(&boardp->active, scp, ASC_BACK);
                ASC_STATS(scp->host, asc_noerror);
+               asc_enqueue(&boardp->active, scp, ASC_BACK);
                ASC_DBG(1, "asc_execute_scsi_cmnd: AscExeScsiQueue(), ASC_NOERROR\n");
                break;
        case ASC_BUSY:
@@ -4083,24 +4493,24 @@ asc_execute_scsi_cmnd(Scsi_Cmnd *scp)
                break;
        case ASC_ERROR:
                ASC_PRINT2(
-"asc_execute_scsi_cmnd: Board %d: AscExeScsiQueue() ASC_ERROR, err_code %x\n",
+"asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() ASC_ERROR, err_code %x\n",
                        boardp->id, asc_dvc_varp->err_code);
                ASC_STATS(scp->host, asc_error);
                scp->result = HOST_BYTE(DID_ERROR);
-               scp->scsi_done(scp);
+               asc_enqueue(&boardp->scsi_done_q, scp, ASC_BACK);
                break;
        default:
                ASC_PRINT2(
-"asc_execute_scsi_cmnd: Board %d: AscExeScsiQueue() unknown, err_code %x\n",
+"asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() unknown, err_code %x\n",
                        boardp->id, asc_dvc_varp->err_code);
                ASC_STATS(scp->host, asc_unknown);
                scp->result = HOST_BYTE(DID_ERROR);
-               scp->scsi_done(scp);
+               asc_enqueue(&boardp->scsi_done_q, scp, ASC_BACK);
                break;
        }
-       restore_flags(flags);
 
        ASC_DBG(1, "asc_execute_scsi_cmnd: end\n");
+       ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
        return ret;
 }
 
@@ -4110,10 +4520,10 @@ asc_execute_scsi_cmnd(Scsi_Cmnd *scp)
 void
 asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep)
 {
-       struct asc_board        *boardp;
+       asc_board_t                     *boardp;
        Scsi_Cmnd                       *scp;
        struct Scsi_Host        *shp;
-       Scsi_Cmnd                       **scpp;
+       int                                     i;
 
        ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
        ASC_DBG2(1, "asc_isr_callback: asc_dvc_varp %x, qdonep %x\n",
@@ -4128,16 +4538,40 @@ asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep)
        ASC_DBG1(1, "asc_isr_callback: scp %x\n", (unsigned) scp);
        ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len);
 
+       if (scp == NULL) {
+               ASC_PRINT("asc_isr_callback: scp is NULL\n");
+               return;
+       }
+
+       /*
+        * If the request's host pointer is not valid, display a
+        * message and return.
+        */
        shp = scp->host;
-       ASC_ASSERT(shp);
+       for (i = 0; i < asc_board_count; i++) {
+               if (asc_host[i] == shp) {
+                       break;
+               }
+       }
+       if (i == asc_board_count) {
+               ASC_PRINT2("asc_isr_callback: scp %x has bad host pointer, host %x\n",
+                       (unsigned) scp, (unsigned) shp);
+               return;
+       }
+
        ASC_STATS(shp, callback);
        ASC_DBG1(1, "asc_isr_callback: shp %x\n", (unsigned) shp);
 
+       /*
+        * If the request isn't found on the active queue, it may
+        * have been removed to handle a reset or abort request.
+        * Display a message and return.
+        */
        boardp = ASC_BOARDP(shp);
        if (asc_rmqueue(&boardp->active, scp) == ASC_FALSE) {
-               ASC_PRINT2(
-"asc_isr_callback: Board %d: scp %x not on active queue\n",
+               ASC_PRINT2("asc_isr_callback: board %d: scp %x not on active queue\n",
                        boardp->id, (unsigned) scp);
+               return;
        }
 
        /*
@@ -4205,33 +4639,14 @@ asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep)
                break;
        }
 
-       /*
-        * Before calling 'scsi_done' for the current 'Scsi_Cmnd' and possibly
-        * triggering more commands to be issued, try to start any pending
-        * commands.
-        */
-       if (boardp->pending.tidmask != 0) {
-               /*
-                * If there are any pending commands for this board before trying
-                * to execute them, disable interrupts to preserve request ordering.
-                */
-               ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
-               ASC_DBG1(1, "asc_isr_callback: asc_execute_queue() %x\n",
-                       boardp->pending.tidmask);
-               asc_execute_queue(&boardp->pending);
-       }
-
        /* 
-        * Because interrupts may be enabled by the 'Scsi_Cmnd' done function,
-        * add the command to the end of the global done list. The done function
-        * for the command will be called in advansys_interrupt().
+        * Because interrupts may be enabled by the 'Scsi_Cmnd' done
+        * function, add the command to the end of the board's done queue.
+        * The done function for the command will be called from
+        * advansys_interrupt().
         */
-       for (scpp = &asc_scsi_done; *scpp;
-            scpp = (Scsi_Cmnd **) &(*scpp)->host_scribble) {
-               ;
-       }
-       *scpp = scp;
-       scp->host_scribble = NULL;
+       asc_enqueue(&boardp->scsi_done_q, scp, ASC_BACK);
+
        return;
 }
 
@@ -4243,10 +4658,7 @@ asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep)
 STATIC int
 asc_init_dev(ASC_DVC_VAR *asc_dvc_varp, Scsi_Cmnd *scp)
 {
-       struct asc_board                *boardp;
-       ASC_SCSI_REQ_Q                  *scsireqq;
-       ASC_CAP_INFO                    *cap_info;
-       ASC_SCSI_INQUIRY                *inquiry;
+       asc_board_t                             *boardp;
        int                                             found;
        ASC_SCSI_BIT_ID_TYPE    save_use_tagged_qng;
        ASC_SCSI_BIT_ID_TYPE    save_can_tagged_qng;
@@ -4257,26 +4669,15 @@ asc_init_dev(ASC_DVC_VAR *asc_dvc_varp, Scsi_Cmnd *scp)
 
        ASC_DBG1(1, "asc_init_dev: target %d\n", (unsigned) scp->target);
 
-       /* The hosts's target id is set in init_tidmask during initialization. */
+       /* The host's target id is set in init_tidmask during initialization. */
        ASC_ASSERT(asc_dvc_varp->cfg->chip_scsi_id != scp->target);
 
        boardp = ASC_BOARDP(scp->host);
 
-       /*
-        * XXX - Host drivers should not modify the timeout field.
-        * But on the first command only add some extra time to
-        * allow the driver to complete its initialization for the
-        * device.
-        */
-       scp->timeout += 2000;   /* Add 5 seconds to the request timeout. */
-
        /* Set-up AscInitPollTarget() arguments. */
-       scsireqq = &boardp->scsireqq;
-       memset(scsireqq, 0, sizeof(ASC_SCSI_REQ_Q));
-       cap_info = &boardp->cap_info;
-       memset(cap_info, 0, sizeof(ASC_CAP_INFO));
-       inquiry = &boardp->inquiry;
-       memset(inquiry, 0, sizeof(ASC_SCSI_INQUIRY));
+       memset(&asc_scsireqq, 0, sizeof(ASC_SCSI_REQ_Q));
+       memset(&asc_cap_info, 0, sizeof(ASC_CAP_INFO));
+       memset(&asc_inquiry, 0, sizeof(ASC_SCSI_INQUIRY));
 
        /*
         * XXX - AscInitPollBegin() re-initializes these fields to
@@ -4289,28 +4690,29 @@ asc_init_dev(ASC_DVC_VAR *asc_dvc_varp, Scsi_Cmnd *scp)
 
        ASC_DBG(2, "asc_init_dev: AscInitPollBegin()\n");
        if (AscInitPollBegin(asc_dvc_varp)) {
-               ASC_PRINT1("asc_init_dev: Board %d: AscInitPollBegin() failed\n",
+               ASC_PRINT1("asc_init_dev: board %d: AscInitPollBegin() failed\n",
                        boardp->id);
                return ASC_FALSE;
        }
 
-       scsireqq->sense_ptr = &scsireqq->sense[0];
-       scsireqq->r1.sense_len = ASC_MIN_SENSE_LEN;
-       scsireqq->r1.target_id = ASC_TID_TO_TARGET_ID(scp->target);
-       scsireqq->r1.target_lun = 0;
-       scsireqq->r2.target_ix = ASC_TIDLUN_TO_IX(scp->target, 0);
+       asc_scsireqq.sense_ptr = &asc_scsireqq.sense[0];
+       asc_scsireqq.r1.sense_len = ASC_MIN_SENSE_LEN;
+       asc_scsireqq.r1.target_id = ASC_TID_TO_TARGET_ID(scp->target);
+       asc_scsireqq.r1.target_lun = 0;
+       asc_scsireqq.r2.target_ix = ASC_TIDLUN_TO_IX(scp->target, 0);
 
        found = ASC_FALSE;
        ASC_DBG(2, "asc_init_dev: AscInitPollTarget()\n");
-       switch (ret = AscInitPollTarget(asc_dvc_varp, scsireqq, inquiry, cap_info)) {
+       switch (ret = AscInitPollTarget(asc_dvc_varp, &asc_scsireqq,
+               &asc_inquiry, &asc_cap_info)) {
        case ASC_TRUE:
                found = ASC_TRUE;
 #ifdef ADVANSYS_DEBUG
                tidmask = ASC_TIX_TO_TARGET_ID(scp->target);
                ASC_DBG2(1, "asc_init_dev: lba %lu, blk_size %lu\n",
-                       cap_info->lba, cap_info->blk_size);
+                       asc_cap_info.lba, asc_cap_info.blk_size);
                ASC_DBG1(1, "asc_init_dev: peri_dvc_type %x\n",
-                       inquiry->byte0.peri_dvc_type);
+                       asc_inquiry.byte0.peri_dvc_type);
                if (asc_dvc_varp->use_tagged_qng & tidmask) {
                        ASC_DBG1(1, "asc_init_dev: command queuing enabled: %d\n",
                                asc_dvc_varp->max_dvc_qng[scp->target]);
@@ -4334,12 +4736,12 @@ asc_init_dev(ASC_DVC_VAR *asc_dvc_varp, Scsi_Cmnd *scp)
                ASC_DBG(1, "asc_init_dev: no device found\n");
                break;
        case ASC_ERROR:
-               ASC_PRINT1("asc_init_dev: Board %d: AscInitPollTarget() ASC_ERROR\n",
+               ASC_PRINT1("asc_init_dev: board %d: AscInitPollTarget() ASC_ERROR\n",
                                boardp->id);
                break;
        default:
                ASC_PRINT2(
-"asc_init_dev: Board %d: AscInitPollTarget() unknown ret %d\n",
+"asc_init_dev: board %d: AscInitPollTarget() unknown ret %d\n",
                                boardp->id, ret);
                break;
        }
@@ -4351,6 +4753,8 @@ asc_init_dev(ASC_DVC_VAR *asc_dvc_varp, Scsi_Cmnd *scp)
        ASC_DBG(2, "asc_init_dev: AscInitPollEnd()\n");
        AscInitPollEnd(asc_dvc_varp);
 
+       ASC_DBG1(1, "asc_init_dev: found %d\n", found); 
+
        return found;
 }
 
@@ -4753,36 +5157,42 @@ asc_put_cfg_byte(PCI_DATA *pciData, uchar byte_data)
 void
 asc_enqueue(asc_queue_t *ascq, REQP reqp, int flag)
 {
-       REQP    *reqpp;
        int             tid;
 
-       ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
        ASC_DBG3(2, "asc_enqueue: ascq %x, reqp %x, flag %d\n",
                (unsigned) ascq, (unsigned) reqp, flag);
-       tid = REQPTID(reqp);
+       ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
+       ASC_ASSERT(reqp != NULL);
        ASC_ASSERT(flag == ASC_FRONT || flag == ASC_BACK);
+       tid = REQPTID(reqp);
+       ASC_ASSERT(tid >= 0 && tid <= ASC_MAX_TID);
        if (flag == ASC_FRONT) {
-               REQPNEXT(reqp) = ascq->queue[tid];
-               ascq->queue[tid] = reqp;
+               REQPNEXT(reqp) = ascq->q_first[tid];
+               ascq->q_first[tid] = reqp;
+               /* If the queue was empty, set the last pointer. */
+               if (ascq->q_last[tid] == NULL) {
+                       ascq->q_last[tid] = reqp;
+               }
        } else { /* ASC_BACK */
-               for (reqpp = &ascq->queue[tid]; *reqpp; reqpp = REQPNEXTP(*reqpp)) {
-                       ASC_ASSERT(ascq->tidmask & ASC_TIX_TO_TARGET_ID(tid));
-                       ;
+               if (ascq->q_last[tid] != NULL) {
+                       REQPNEXT(ascq->q_last[tid]) = reqp;
                }
-               *reqpp = reqp;
+               ascq->q_last[tid] = reqp;
                REQPNEXT(reqp) = NULL;
+               /* If the queue was empty, set the first pointer. */
+               if (ascq->q_first[tid] == NULL) {
+                       ascq->q_first[tid] = reqp;
+               }
        }
        /* The queue has at least one entry, set its bit. */
-       ascq->tidmask |= ASC_TIX_TO_TARGET_ID(tid);
+       ascq->q_tidmask |= ASC_TIX_TO_TARGET_ID(tid);
 #ifdef ADVANSYS_STATS
-       /*
-        * Maintain request queue statistics.
-        */
-       ascq->cur_count[tid]++;
-       if (ascq->cur_count[tid] > ascq->max_count[tid]) {
-               ascq->max_count[tid] = ascq->cur_count[tid];
-               ASC_DBG2(1, "asc_enqueue: new max_count[%d] %d\n",
-                       tid, ascq->max_count[tid]);
+       /* Maintain request queue statistics. */
+       ascq->q_cur_cnt[tid]++;
+       if (ascq->q_cur_cnt[tid] > ascq->q_max_cnt[tid]) {
+               ascq->q_max_cnt[tid] = ascq->q_cur_cnt[tid];
+               ASC_DBG2(1, "asc_enqueue: new q_max_cnt[%d] %d\n",
+                       tid, ascq->q_max_cnt[tid]);
        }
 #endif /* ADVANSYS_STATS */
        ASC_DBG1(1, "asc_enqueue: reqp %x\n", (unsigned) reqp);
@@ -4801,29 +5211,102 @@ asc_dequeue(asc_queue_t *ascq, int tid)
 {
        REQP    reqp;
 
-       ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
        ASC_DBG2(1, "asc_dequeue: ascq %x, tid %d\n", (unsigned) ascq, tid);
-       if ((reqp = ascq->queue[tid]) != NULL) {
-               ASC_ASSERT(ascq->tidmask & ASC_TIX_TO_TARGET_ID(tid));
-               ascq->queue[tid] = REQPNEXT(reqp);
-               /* If the queue is empty, clear its bit. */
-               if (ascq->queue[tid] == NULL) {
-                       ascq->tidmask &= ~ASC_TIX_TO_TARGET_ID(tid);
+       ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
+       ASC_ASSERT(tid >= 0 && tid <= ASC_MAX_TID);
+       if ((reqp = ascq->q_first[tid]) != NULL) {
+               ASC_ASSERT(ascq->q_tidmask & ASC_TIX_TO_TARGET_ID(tid));
+               ascq->q_first[tid] = REQPNEXT(reqp);
+               /* If the queue is empty, clear its bit and the last pointer. */
+               if (ascq->q_first[tid] == NULL) {
+                       ascq->q_tidmask &= ~ASC_TIX_TO_TARGET_ID(tid);
+                       ASC_ASSERT(ascq->q_last[tid] == reqp);
+                       ascq->q_last[tid] = NULL;
                }
-       }
 #ifdef ADVANSYS_STATS
-       /*
-        * Maintain request queue statistics.
-        */
-       if (reqp != NULL) {
-               ascq->cur_count[tid]--;
-       }
-       ASC_ASSERT(ascq->cur_count[tid] >= 0);
+               /* Maintain request queue statistics. */
+               ascq->q_cur_cnt[tid]--;
+               ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0);
 #endif /* ADVANSYS_STATS */
+       }
        ASC_DBG1(1, "asc_dequeue: reqp %x\n", (unsigned) reqp);
        return reqp;
 }
 
+/*
+ * Return a pointer to a singly linked list of all the requests queued
+ * for 'tid' on the 'asc_queue_t' pointed to by 'ascq'.
+ *
+ * If 'lastpp' is not NULL, '*lastpp' will be set to point to the 
+ * the last request returned in the singly linked list.
+ *
+ * 'tid' should either be a valid target id or if it is ASC_TID_ALL,
+ * then all queued requests are concatenated into one list and
+ * returned.
+ *
+ * Note: If 'lastpp' is used to append a new list to the end of
+ * an old list, only change the old list last pointer if '*lastpp'
+ * (or the function return value) is not NULL, i.e. use a temporary
+ * variable for 'lastpp' and check its value after the function return
+ * before assigning it to the list last pointer.
+ */
+REQP
+asc_dequeue_list(asc_queue_t *ascq, REQP *lastpp, int tid)
+{
+       REQP    firstp, lastp;
+       int             i;
+
+       ASC_DBG2(1, "asc_dequeue_list: ascq %x, tid %d\n", (unsigned) ascq, tid);
+       ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
+       ASC_ASSERT((tid == ASC_TID_ALL) || (tid >= 0 && tid <= ASC_MAX_TID));
+
+       /*
+        * If 'tid' is not ASC_TID_ALL, return requests only for
+        * the specified 'tid'. If 'tid' is ASC_TID_ALL, return all
+        * requests for all tids.
+        */
+       if (tid != ASC_TID_ALL) {
+               /* Return all requests for the specified 'tid'. */
+               if ((ascq->q_tidmask & ASC_TIX_TO_TARGET_ID(tid)) == 0) {
+                       /* List is empty set first and last return pointers to NULL. */
+                       firstp = lastp = NULL;
+               } else {
+                       firstp = ascq->q_first[tid];
+                       lastp = ascq->q_last[tid];
+                       ascq->q_first[tid] = ascq->q_last[tid] = NULL;
+                       ascq->q_tidmask &= ~ASC_TIX_TO_TARGET_ID(tid);
+#ifdef ADVANSYS_STATS
+                       ascq->q_cur_cnt[tid] = 0;
+#endif /* ADVANSYS_STATS */
+               }
+       } else {
+               /* Return all requests for all tids. */
+               firstp = lastp = NULL;
+               for (i = 0; i <= ASC_MAX_TID; i++) {
+                       if (ascq->q_tidmask & ASC_TIX_TO_TARGET_ID(i)) {
+                               if (firstp == NULL) {
+                                       firstp = ascq->q_first[i];
+                                       lastp = ascq->q_last[i];
+                               } else {
+                                       ASC_ASSERT(lastp != NULL);
+                                       REQPNEXT(lastp) = ascq->q_first[i];
+                                       lastp = ascq->q_last[i];
+                               }
+                               ascq->q_first[i] = ascq->q_last[i] = NULL;
+                               ascq->q_tidmask &= ~ASC_TIX_TO_TARGET_ID(i);
+#ifdef ADVANSYS_STATS
+                               ascq->q_cur_cnt[i] = 0;
+#endif /* ADVANSYS_STATS */
+                       }
+               }
+       }
+       if (lastpp) {
+               *lastpp = lastp;
+       }
+       ASC_DBG1(1, "asc_dequeue_list: firstp %x\n", (unsigned) firstp);
+       return firstp;
+}
+
 /*
  * Remove the specified 'REQP' from the specified queue for
  * the specified target device. Clear the 'tidmask' bit for the
@@ -4837,34 +5320,61 @@ asc_dequeue(asc_queue_t *ascq, int tid)
 int
 asc_rmqueue(asc_queue_t *ascq, REQP reqp)
 {
-       REQP            *reqpp;
+       REQP            currp, prevp;
        int                     tid;
-       int                     ret;
+       int                     ret = ASC_FALSE;
 
+       ASC_DBG2(1, "asc_rmqueue: ascq %x, reqp %d\n",
+               (unsigned) ascq, (unsigned) reqp);
        ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
-       ret = ASC_FALSE;
+       ASC_ASSERT(reqp != NULL);
+
        tid = REQPTID(reqp);
-       for (reqpp = &ascq->queue[tid]; *reqpp; reqpp = REQPNEXTP(*reqpp)) {
-               ASC_ASSERT(ascq->tidmask & ASC_TIX_TO_TARGET_ID(tid));
-               if (*reqpp == reqp) {
-                       ret = ASC_TRUE;
-                       *reqpp = REQPNEXT(reqp);
-                       REQPNEXT(reqp) = NULL;
-                       /* If the queue is now empty, clear its bit. */
-                       if (ascq->queue[tid] == NULL) {
-                               ascq->tidmask &= ~ASC_TIX_TO_TARGET_ID(tid);
+       ASC_ASSERT(tid >= 0 && tid <= ASC_MAX_TID);
+
+       /*
+        * Handle the common case of 'reqp' being the first
+        * entry on the queue.
+        */
+       if (reqp == ascq->q_first[tid]) {
+               ret = ASC_TRUE;
+               ascq->q_first[tid] = REQPNEXT(reqp);
+               /* If the queue is now empty, clear its bit and the last pointer. */
+               if (ascq->q_first[tid] == NULL) {
+                       ascq->q_tidmask &= ~ASC_TIX_TO_TARGET_ID(tid);
+                       ASC_ASSERT(ascq->q_last[tid] == reqp);
+                       ascq->q_last[tid] = NULL;
+               }
+       } else if (ascq->q_first[tid] != NULL) {
+               ASC_ASSERT(ascq->q_last[tid] != NULL);
+               /*
+                * Because the case of 'reqp' being the first entry has been
+                * handled above and it is known the queue is not empty, if
+                * 'reqp' is found on the queue it is guaranteed the queue will
+                * not become empty and that 'q_first[tid]' will not be changed.
+                *
+                * Set 'prevp' to the first entry, 'currp' to the second entry,
+                * and search for 'reqp'.
+                */
+               for (prevp = ascq->q_first[tid], currp = REQPNEXT(prevp);
+                        currp; prevp = currp, currp = REQPNEXT(currp)) {
+                       if (currp == reqp) {
+                               ret = ASC_TRUE;
+                               REQPNEXT(prevp) = REQPNEXT(currp);
+                               REQPNEXT(reqp) = NULL;
+                               if (ascq->q_last[tid] == reqp) {
+                                       ascq->q_last[tid] = prevp;
+                               }
+                               break;
                        }
-                       break; /* Note: *reqpp may now be NULL, don't iterate. */
                }
        }
 #ifdef ADVANSYS_STATS
-       /*
-        * Maintain request queue statistics.
-        */
+       /* Maintain request queue statistics. */
        if (ret == ASC_TRUE) {
-               ascq->cur_count[tid]--;
+               ascq->q_cur_cnt[tid]--;
        }
-       ASC_ASSERT(ascq->cur_count[tid] >= 0);
+       ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0);
 #endif /* ADVANSYS_STATS */
        ASC_DBG2(1, "asc_rmqueue: reqp %x, ret %d\n", (unsigned) reqp, ret);
        return ret;
@@ -4877,16 +5387,21 @@ asc_rmqueue(asc_queue_t *ascq, REQP reqp)
 int
 asc_isqueued(asc_queue_t *ascq, REQP reqp)
 {
-       REQP            *reqpp;
+       REQP            treqp;
        int                     tid;
-       int                     ret;
+       int                     ret = ASC_FALSE;
 
+       ASC_DBG2(1, "asc_isqueued: ascq %x, reqp %x\n",
+               (unsigned) ascq, (unsigned) reqp);
        ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
-       ret = ASC_FALSE;
+       ASC_ASSERT(reqp != NULL);
+
        tid = REQPTID(reqp);
-       for (reqpp = &ascq->queue[tid]; *reqpp; reqpp = REQPNEXTP(*reqpp)) {
-               ASC_ASSERT(ascq->tidmask & ASC_TIX_TO_TARGET_ID(tid));
-               if (*reqpp == reqp) {
+       ASC_ASSERT(tid >= 0 && tid <= ASC_MAX_TID);
+
+       for (treqp = ascq->q_first[tid]; treqp; treqp = REQPNEXT(treqp)) {
+               ASC_ASSERT(ascq->q_tidmask & ASC_TIX_TO_TARGET_ID(tid));
+               if (treqp == reqp) {
                        ret = ASC_TRUE;
                        break;
                }
@@ -4906,13 +5421,13 @@ asc_execute_queue(asc_queue_t *ascq)
        REQP                                    reqp;
        int                                             i;
 
-       ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
        ASC_DBG1(1, "asc_execute_queue: ascq %x\n", (unsigned) ascq);
+       ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
        /*
         * Execute queued commands for devices attached to
         * the current board in round-robin fashion.
         */
-       scan_tidmask = ascq->tidmask;
+       scan_tidmask = ascq->q_tidmask;
        do {
                for (i = 0; i <= ASC_MAX_TID; i++) {
                        if (scan_tidmask & ASC_TIX_TO_TARGET_ID(i)) {
@@ -4944,11 +5459,11 @@ asc_execute_queue(asc_queue_t *ascq)
 STATIC int
 asc_prt_board_devices(struct Scsi_Host *shp, char *cp, int cplen)
 {
-       struct asc_board        *boardp;
-       int                                     leftlen;
-       int                                     totlen;
-       int                                     len;
-       int                                     i;
+       asc_board_t             *boardp;
+       int                             leftlen;
+       int                             totlen;
+       int                             len;
+       int                             i;
 
        boardp = ASC_BOARDP(shp);
        leftlen = cplen;
@@ -4989,14 +5504,14 @@ asc_prt_board_devices(struct Scsi_Host *shp, char *cp, int cplen)
 STATIC int
 asc_prt_board_eeprom(struct Scsi_Host *shp, char *cp, int cplen)
 {
-       struct asc_board        *boardp;
-       ASC_DVC_VAR                     *asc_dvc_varp;
-       int                                     leftlen;
-       int                                     totlen;
-       int                                     len;
-       ASCEEP_CONFIG       *ep;
-       int                                     i;
-       int                                     isa_dma_speed[] = { 10, 8, 7, 6, 5, 4, 3, 2 };
+       asc_board_t             *boardp;
+       ASC_DVC_VAR             *asc_dvc_varp;
+       int                             leftlen;
+       int                             totlen;
+       int                             len;
+       ASCEEP_CONFIG   *ep;
+       int                             i;
+       int                             isa_dma_speed[] = { 10, 8, 7, 6, 5, 4, 3, 2 };
 
        boardp = ASC_BOARDP(shp);
        asc_dvc_varp = &boardp->asc_dvc_var;
@@ -5068,6 +5583,70 @@ asc_prt_board_eeprom(struct Scsi_Host *shp, char *cp, int cplen)
        return totlen;
 }
 
+/*
+ * asc_prt_driver_conf()
+ *
+ * Note: no single line should be greater than ASC_PRTLINE_SIZE,
+ * cf. asc_prt_line().
+ *
+ * Return the number of characters copied into 'cp'. No more than
+ * 'cplen' characters will be copied to 'cp'.
+ */
+STATIC int
+asc_prt_driver_conf(struct Scsi_Host *shp, char *cp, int cplen)
+{
+       int                                     leftlen;
+       int                                     totlen;
+       int                                     len;
+
+       leftlen = cplen;
+       totlen = len = 0;
+
+       len = asc_prt_line(cp, leftlen,
+"\nLinux Driver Configuration and Information for AdvanSys SCSI Host %d:\n",
+               shp->host_no);
+       ASC_PRT_NEXT();
+
+       len = asc_prt_line(cp, leftlen,
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
+" host_busy %u, last_reset %u, max_id %u, max_lun %u, max_channel %u\n",
+               shp->host_busy, shp->last_reset, shp->max_id, shp->max_lun,
+               shp->max_channel);
+#else /* version >= v1.3.89 */
+" host_busy %u, last_reset %u, max_id %u, max_lun %u\n",
+               shp->host_busy, shp->last_reset, shp->max_id, shp->max_lun);
+#endif /* version >= v1.3.89 */
+       ASC_PRT_NEXT();
+       
+       len = asc_prt_line(cp, leftlen,
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,57)
+" unique_id %d, can_queue %d, this_id %d, sg_tablesize %u, cmd_per_lun %u\n",
+               shp->unique_id, shp->can_queue, shp->this_id, shp->sg_tablesize,
+               shp->cmd_per_lun);
+#else /* version >= v1.3.57 */
+" can_queue %d, this_id %d, sg_tablesize %u, cmd_per_lun %u\n",
+               shp->can_queue, shp->this_id, shp->sg_tablesize, shp->cmd_per_lun);
+#endif /* version >= v1.3.57 */
+       ASC_PRT_NEXT();
+
+       len = asc_prt_line(cp, leftlen,
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,57)
+" unchecked_isa_dma %d, use_clustering %d, loaded_as_module %d\n",
+               shp->unchecked_isa_dma, shp->use_clustering, shp->loaded_as_module);
+#else /* version >= v1.3.57 */
+" unchecked_isa_dma %d, loaded_as_module %d\n",
+               shp->unchecked_isa_dma, shp->loaded_as_module);
+#endif /* version >= v1.3.57 */
+       ASC_PRT_NEXT();
+
+       len = asc_prt_line(cp, leftlen,
+" flags %x, reset_jiffies %x, jiffies %x\n",
+               ASC_BOARDP(shp)->flags, ASC_BOARDP(shp)->reset_jiffies, jiffies);
+       ASC_PRT_NEXT();
+
+       return totlen;
+}
+
 /*
  * asc_prt_board_info()
  *
@@ -5082,7 +5661,7 @@ asc_prt_board_eeprom(struct Scsi_Host *shp, char *cp, int cplen)
 STATIC int
 asc_prt_board_info(struct Scsi_Host *shp, char *cp, int cplen)
 {
-       struct asc_board        *boardp;
+       asc_board_t                     *boardp;
        int                                     leftlen;
        int                                     totlen;
        int                                     len;
@@ -5106,7 +5685,7 @@ asc_prt_board_info(struct Scsi_Host *shp, char *cp, int cplen)
        ASC_PRT_NEXT();
 
        len = asc_prt_line(cp, leftlen,
-" chip_version %u, lib_version %u, lib_serial_no %u mcode_date %u\n",
+" chip_version %u, lib_version %u, lib_serial_no %u, mcode_date %u\n",
                c->chip_version, c->lib_version, c->lib_serial_no, c->mcode_date);
        ASC_PRT_NEXT();
 
@@ -5115,7 +5694,7 @@ asc_prt_board_info(struct Scsi_Host *shp, char *cp, int cplen)
                 c->mcode_version, v->err_code);
        ASC_PRT_NEXT();
 
-       /* Current number of commands pending for the host. */
+       /* Current number of commands waiting for the host. */
        len = asc_prt_line(cp, leftlen,
 " Total Command Pending:    %d\n", v->cur_total_qng);
        ASC_PRT_NEXT();
@@ -5150,7 +5729,7 @@ asc_prt_board_info(struct Scsi_Host *shp, char *cp, int cplen)
        len = asc_prt_line(cp, leftlen, "\n");
        ASC_PRT_NEXT();
 
-       /* Current number of commands pending for a device. */
+       /* Current number of commands waiting for a device. */
        len = asc_prt_line(cp, leftlen,
 " Command Queue Pending:   ");
        ASC_PRT_NEXT();
@@ -5495,7 +6074,7 @@ DvcWritePCIConfigByte(
 }
 
 /*
- * Return the BIOS address of the adatper at the specified
+ * Return the BIOS address of the adapter at the specified
  * I/O port and with the specified bus type.
  *
  * This function was formerly supplied by the library.
@@ -5565,7 +6144,7 @@ asc_prt_board_stats(struct Scsi_Host *shp, char *cp, int cplen)
        struct asc_stats        *s;
        int                                     i;
        asc_queue_t                     *active;
-       asc_queue_t                     *pending;
+       asc_queue_t                     *waiting;
 
        leftlen = cplen;
        totlen = len = 0;
@@ -5581,8 +6160,8 @@ asc_prt_board_stats(struct Scsi_Host *shp, char *cp, int cplen)
        ASC_PRT_NEXT();
 
        len = asc_prt_line(cp, leftlen,
-" check_interrupt %lu, interrupt %lu, callback %lu\n",
-               s->check_interrupt, s->interrupt, s->callback);
+" check_interrupt %lu, interrupt %lu, callback %lu, done %lu\n",
+               s->check_interrupt, s->interrupt, s->callback, s->done);
        ASC_PRT_NEXT();
 
        len = asc_prt_line(cp, leftlen,
@@ -5598,13 +6177,13 @@ asc_prt_board_stats(struct Scsi_Host *shp, char *cp, int cplen)
        ASC_PRT_NEXT();
 
        active = &ASC_BOARDP(shp)->active;
-       pending = &ASC_BOARDP(shp)->pending;
+       waiting = &ASC_BOARDP(shp)->waiting;
        for (i = 0; i < ASC_MAX_TID + 1; i++) {
-               if (active->max_count[i] > 0 || pending->max_count[i] > 0) {
+               if (active->q_max_cnt[i] > 0 || waiting->q_max_cnt[i] > 0) {
                        len = asc_prt_line(cp, leftlen,
-"  target %d: active [cur %d, max %d], pending [cur %d, max %d]\n",
-                               i, active->cur_count[i], active->max_count[i],
-                               pending->cur_count[i], pending->max_count[i]);
+"  target %d: active [cur %d, max %d], waiting [cur %d, max %d]\n",
+                               i, active->q_cur_cnt[i], active->q_max_cnt[i],
+                               waiting->q_cur_cnt[i], waiting->q_max_cnt[i]);
                        ASC_PRT_NEXT();
                }
        }
@@ -6287,10 +6866,11 @@ AscIsrChipHalted(
                                        sdtr_xmsg.req_ack_offset = ASC_SYN_MAX_OFFSET;
                                }
                                if (
-                                          (sdtr_xmsg.xfer_period < asc_dvc->sdtr_period_tbl[0])
+                                          (sdtr_xmsg.xfer_period < asc_dvc->sdtr_period_tbl[asc_dvc->host_init_sdtr_index])
                                           || (sdtr_xmsg.xfer_period > asc_dvc->sdtr_period_tbl[asc_dvc->max_sdtr_index])
                                  ) {
                                        sdtr_accept = FALSE;
+                                       sdtr_xmsg.xfer_period = asc_dvc->sdtr_period_tbl[ asc_dvc->host_init_sdtr_index ] ;
                                }
                                if (sdtr_accept) {
                                        sdtr_data = AscCalSDTRData(asc_dvc, sdtr_xmsg.xfer_period,
@@ -6344,7 +6924,7 @@ AscIsrChipHalted(
                        sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
                        q_cntl |= QC_MSG_OUT;
                        AscMsgOutSDTR(asc_dvc,
-                                                 asc_dvc->sdtr_period_tbl[(sdtr_data >> 4) & (uchar) (ASC_SYN_XFER_NO - 1)],
+                                                 asc_dvc->sdtr_period_tbl[(sdtr_data >> 4) & (uchar) (asc_dvc->max_sdtr_index - 1)],
                                                  (uchar) (sdtr_data & (uchar) ASC_SYN_MAX_OFFSET));
                }
 #endif
@@ -6418,8 +6998,8 @@ AscIsrChipHalted(
                                }
 #ifdef ADVANSYS_STATS
                                {
-                                       struct asc_board   *boardp;
-                                       int                 i;
+                                       asc_board_t             *boardp;
+                                       int                             i;
                                        for (i = 0; i < ASC_NUM_BOARD_SUPPORTED; i++) {
                                                if (asc_host[i] == NULL) {
                                                        continue;
@@ -6768,156 +7348,156 @@ AscScsiSetupCmdQ(
        return (0);
 }
 
-uchar               _mcode_buf[] =
-{
-       0x01, 0x03, 0x01, 0x19, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0xC4, 0x0C, 0x08, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0xFF, 0x80, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x23, 0x00, 0x20, 0x00, 0x00, 0x00, 0x07, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
-       0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE4, 0x88, 0x00, 0x00, 0x00, 0x00,
-       0x80, 0x73, 0x48, 0x04, 0x36, 0x00, 0x00, 0xA2, 0xC6, 0x00, 0x80, 0x73, 0x03, 0x23, 0x36, 0x40,
-       0xB6, 0x00, 0x36, 0x00, 0x05, 0xD6, 0x0C, 0xD2, 0x12, 0xDA, 0x00, 0xA2, 0xC6, 0x00, 0x92, 0x80,
-       0x20, 0x98, 0x50, 0x00, 0xF5, 0x00, 0x4A, 0x98, 0xDF, 0x23, 0x36, 0x60, 0xB6, 0x00, 0x92, 0x80,
-       0x4F, 0x00, 0xF5, 0x00, 0x4A, 0x98, 0xEF, 0x23, 0x36, 0x60, 0xB6, 0x00, 0x92, 0x80, 0x80, 0x62,
-       0x92, 0x80, 0x00, 0x62, 0x92, 0x80, 0x00, 0x46, 0x17, 0xEE, 0x13, 0xEA, 0x02, 0x01, 0x09, 0xD8,
-       0xCD, 0x04, 0x4D, 0x00, 0x00, 0xA3, 0xDA, 0x00, 0xA8, 0x97, 0x7F, 0x23, 0x04, 0x61, 0x84, 0x01,
-       0xD2, 0x84, 0xD0, 0xC1, 0x80, 0x73, 0xCD, 0x04, 0x4D, 0x00, 0x00, 0xA3, 0xE6, 0x01, 0xA8, 0x97,
-       0xD2, 0x81, 0x00, 0x33, 0x02, 0x00, 0xC2, 0x88, 0x80, 0x73, 0x80, 0x77, 0x00, 0x01, 0x01, 0xA1,
-       0x06, 0x01, 0x4F, 0x00, 0x86, 0x97, 0x07, 0xA6, 0x10, 0x01, 0x00, 0x33, 0x03, 0x00, 0xC2, 0x88,
-       0x03, 0x03, 0x03, 0xDE, 0x00, 0x33, 0x05, 0x00, 0xC2, 0x88, 0xCE, 0x00, 0x69, 0x60, 0xCE, 0x00,
-       0x02, 0x03, 0x4A, 0x60, 0x00, 0xA2, 0x84, 0x01, 0x80, 0x63, 0x07, 0xA6, 0x30, 0x01, 0x84, 0x81,
-       0x03, 0x03, 0x80, 0x63, 0xE2, 0x00, 0x07, 0xA6, 0x40, 0x01, 0x00, 0x33, 0x04, 0x00, 0xC2, 0x88,
-       0x03, 0x07, 0x02, 0x01, 0x04, 0xCA, 0x0D, 0x23, 0x6A, 0x98, 0x4D, 0x04, 0xF0, 0x84, 0x05, 0xD8,
-       0x0D, 0x23, 0x6A, 0x98, 0xCD, 0x04, 0x15, 0x23, 0xF8, 0x88, 0xFB, 0x23, 0x02, 0x61, 0x82, 0x01,
-       0x80, 0x63, 0x02, 0x03, 0x06, 0xA3, 0x6E, 0x01, 0x00, 0x33, 0x0A, 0x00, 0xC2, 0x88, 0x4E, 0x00,
-       0x07, 0xA3, 0x7A, 0x01, 0x00, 0x33, 0x0B, 0x00, 0xC2, 0x88, 0xCD, 0x04, 0x36, 0x2D, 0x00, 0x33,
-       0x1A, 0x00, 0xC2, 0x88, 0x50, 0x04, 0x94, 0x81, 0x06, 0xAB, 0x8E, 0x01, 0x94, 0x81, 0x4E, 0x00,
-       0x07, 0xA3, 0x9E, 0x01, 0x50, 0x00, 0x00, 0xA3, 0x48, 0x01, 0x00, 0x05, 0x88, 0x81, 0x48, 0x97,
-       0x02, 0x01, 0x05, 0xC6, 0x04, 0x23, 0xA0, 0x01, 0x15, 0x23, 0xA1, 0x01, 0xCA, 0x81, 0xFD, 0x23,
-       0x02, 0x61, 0x82, 0x01, 0x0A, 0xDA, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA0, 0xC0, 0x01, 0x80, 0x63,
-       0xCD, 0x04, 0x36, 0x2D, 0x00, 0x33, 0x1B, 0x00, 0xC2, 0x88, 0x06, 0x23, 0x6A, 0x98, 0xCD, 0x04,
-       0xD2, 0x84, 0x06, 0x01, 0x00, 0xA2, 0xE0, 0x01, 0x57, 0x60, 0x00, 0xA0, 0xE6, 0x01, 0xD2, 0x84,
-       0x80, 0x23, 0xA0, 0x01, 0xD2, 0x84, 0x80, 0x73, 0x4B, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x0E, 0x02,
-       0x04, 0x01, 0x0D, 0xDE, 0x02, 0x01, 0x03, 0xCC, 0x4F, 0x00, 0x86, 0x97, 0x08, 0x82, 0x08, 0x23,
-       0x02, 0x41, 0x82, 0x01, 0x4F, 0x00, 0x64, 0x97, 0x48, 0x04, 0xFF, 0x23, 0x84, 0x80, 0xF2, 0x97,
-       0x00, 0x46, 0x56, 0x00, 0x03, 0xC0, 0x01, 0x23, 0xE8, 0x00, 0x81, 0x73, 0x06, 0x29, 0x03, 0x42,
-       0x06, 0xE2, 0x03, 0xEE, 0x66, 0xEB, 0x11, 0x23, 0xF8, 0x88, 0x06, 0x98, 0xF8, 0x80, 0x80, 0x73,
-       0x80, 0x77, 0x06, 0xA6, 0x3C, 0x02, 0x00, 0x33, 0x31, 0x00, 0xC2, 0x88, 0x04, 0x01, 0x03, 0xD8,
-       0xB4, 0x98, 0x3E, 0x96, 0x4E, 0x82, 0xCE, 0x95, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0xB6, 0x2D,
-       0x02, 0xA6, 0x78, 0x02, 0x07, 0xA6, 0x66, 0x02, 0x06, 0xA6, 0x6A, 0x02, 0x03, 0xA6, 0x6E, 0x02,
-       0x00, 0x33, 0x10, 0x00, 0xC2, 0x88, 0x6A, 0x95, 0x50, 0x82, 0x34, 0x96, 0x50, 0x82, 0x04, 0x23,
-       0xA0, 0x01, 0x14, 0x23, 0xA1, 0x01, 0x28, 0x84, 0x04, 0x01, 0x0C, 0xDC, 0xE0, 0x23, 0x25, 0x61,
-       0xEF, 0x00, 0x14, 0x01, 0x4F, 0x04, 0xA8, 0x01, 0x6F, 0x00, 0xA5, 0x01, 0x03, 0x23, 0xA4, 0x01,
-       0x06, 0x23, 0x9C, 0x01, 0x24, 0x2B, 0x1C, 0x01, 0x02, 0xA6, 0xAA, 0x02, 0x07, 0xA6, 0x66, 0x02,
-       0x06, 0xA6, 0x6A, 0x02, 0x00, 0x33, 0x12, 0x00, 0xC2, 0x88, 0x00, 0x0E, 0x80, 0x63, 0x00, 0x43,
-       0x00, 0xA0, 0x98, 0x02, 0x4D, 0x04, 0x04, 0x01, 0x0B, 0xDC, 0xE7, 0x23, 0x04, 0x61, 0x84, 0x01,
-       0x10, 0x31, 0x12, 0x35, 0x14, 0x01, 0xEC, 0x00, 0x6C, 0x38, 0x00, 0x3F, 0x00, 0x00, 0xEA, 0x82,
-       0x18, 0x23, 0x04, 0x61, 0x18, 0xA0, 0xE2, 0x02, 0x04, 0x01, 0x98, 0xC8, 0x00, 0x33, 0x1F, 0x00,
-       0xC2, 0x88, 0x08, 0x31, 0x0A, 0x35, 0x0C, 0x39, 0x0E, 0x3D, 0x80, 0x98, 0xB6, 0x2D, 0x01, 0xA6,
-       0x14, 0x03, 0x00, 0xA6, 0x14, 0x03, 0x07, 0xA6, 0x0C, 0x03, 0x06, 0xA6, 0x10, 0x03, 0x03, 0xA6,
-       0x0C, 0x04, 0x02, 0xA6, 0x78, 0x02, 0x00, 0x33, 0x33, 0x00, 0xC2, 0x88, 0x6A, 0x95, 0xEE, 0x82,
-       0x34, 0x96, 0xEE, 0x82, 0x84, 0x98, 0x80, 0x42, 0x80, 0x98, 0x60, 0xE4, 0x04, 0x01, 0x29, 0xC8,
-       0x31, 0x05, 0x07, 0x01, 0x00, 0xA2, 0x54, 0x03, 0x00, 0x43, 0x87, 0x01, 0x05, 0x05, 0x88, 0x98,
-       0x80, 0x98, 0x00, 0xA6, 0x16, 0x03, 0x07, 0xA6, 0x4C, 0x03, 0x03, 0xA6, 0x28, 0x04, 0x06, 0xA6,
-       0x50, 0x03, 0x01, 0xA6, 0x16, 0x03, 0x00, 0x33, 0x25, 0x00, 0xC2, 0x88, 0x6A, 0x95, 0x32, 0x83,
-       0x34, 0x96, 0x32, 0x83, 0x04, 0x01, 0x0C, 0xCE, 0x03, 0xC8, 0x00, 0x33, 0x42, 0x00, 0xC2, 0x88,
-       0x00, 0x01, 0x05, 0x05, 0xFF, 0xA2, 0x72, 0x03, 0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, 0x2E, 0x83,
-       0x05, 0x05, 0x15, 0x01, 0x00, 0xA2, 0x92, 0x03, 0xEC, 0x00, 0x6E, 0x00, 0x95, 0x01, 0x6C, 0x38,
-       0x00, 0x3F, 0x00, 0x00, 0x01, 0xA6, 0x8E, 0x03, 0x00, 0xA6, 0x8E, 0x03, 0x02, 0x84, 0x80, 0x42,
-       0x80, 0x98, 0x01, 0xA6, 0x9C, 0x03, 0x00, 0xA6, 0xB4, 0x03, 0x02, 0x84, 0xA8, 0x98, 0x80, 0x42,
-       0x01, 0xA6, 0x9C, 0x03, 0x07, 0xA6, 0xAA, 0x03, 0xCC, 0x83, 0x6A, 0x95, 0xA0, 0x83, 0x00, 0x33,
-       0x2F, 0x00, 0xC2, 0x88, 0xA8, 0x98, 0x80, 0x42, 0x00, 0xA6, 0xB4, 0x03, 0x07, 0xA6, 0xC2, 0x03,
-       0xCC, 0x83, 0x6A, 0x95, 0xB8, 0x83, 0x00, 0x33, 0x26, 0x00, 0xC2, 0x88, 0x38, 0x2B, 0x80, 0x32,
-       0x80, 0x36, 0x04, 0x23, 0xA0, 0x01, 0x12, 0x23, 0xA1, 0x01, 0x02, 0x84, 0x04, 0xF0, 0x80, 0x6B,
-       0x00, 0x33, 0x20, 0x00, 0xC2, 0x88, 0x03, 0xA6, 0x00, 0x04, 0x07, 0xA6, 0xF8, 0x03, 0x06, 0xA6,
-       0xFC, 0x03, 0x00, 0x33, 0x17, 0x00, 0xC2, 0x88, 0x6A, 0x95, 0xE6, 0x83, 0x34, 0x96, 0xE6, 0x83,
-       0x0C, 0x84, 0x04, 0xF0, 0x80, 0x6B, 0x00, 0x33, 0x20, 0x00, 0xC2, 0x88, 0xB6, 0x2D, 0x03, 0xA6,
-       0x28, 0x04, 0x07, 0xA6, 0x20, 0x04, 0x06, 0xA6, 0x24, 0x04, 0x00, 0x33, 0x30, 0x00, 0xC2, 0x88,
-       0x6A, 0x95, 0x0C, 0x84, 0x34, 0x96, 0x0C, 0x84, 0x1D, 0x01, 0x06, 0xCC, 0x00, 0x33, 0x00, 0x84,
-       0xC0, 0x20, 0x00, 0x23, 0xEA, 0x00, 0x81, 0x62, 0xA2, 0x0D, 0x80, 0x63, 0x07, 0xA6, 0x46, 0x04,
-       0x00, 0x33, 0x18, 0x00, 0xC2, 0x88, 0x03, 0x03, 0x80, 0x63, 0xA3, 0x01, 0x07, 0xA4, 0x50, 0x04,
-       0x23, 0x01, 0x00, 0xA2, 0x72, 0x04, 0x0A, 0xA0, 0x62, 0x04, 0xE0, 0x00, 0x00, 0x33, 0x1D, 0x00,
-       0xC2, 0x88, 0x0B, 0xA0, 0x6E, 0x04, 0xE0, 0x00, 0x00, 0x33, 0x1E, 0x00, 0xC2, 0x88, 0x42, 0x23,
-       0xF8, 0x88, 0x00, 0x23, 0x22, 0xA3, 0xD2, 0x04, 0x08, 0x23, 0x22, 0xA3, 0x8E, 0x04, 0x28, 0x23,
-       0x22, 0xA3, 0x9A, 0x04, 0x02, 0x23, 0x22, 0xA3, 0xB0, 0x04, 0x42, 0x23, 0xF8, 0x88, 0x4A, 0x00,
-       0x06, 0x61, 0x00, 0xA0, 0x9A, 0x04, 0x45, 0x23, 0xF8, 0x88, 0x06, 0x98, 0x00, 0xA2, 0xAC, 0x04,
-       0xB4, 0x98, 0x00, 0x33, 0x00, 0x82, 0xC0, 0x20, 0x81, 0x62, 0xF4, 0x81, 0x47, 0x23, 0xF8, 0x88,
-       0x04, 0x01, 0x0B, 0xDE, 0x06, 0x98, 0xB4, 0x98, 0x00, 0x33, 0x00, 0x81, 0xC0, 0x20, 0x81, 0x62,
-       0x14, 0x01, 0x00, 0xA0, 0x0E, 0x02, 0x43, 0x23, 0xF8, 0x88, 0x04, 0x23, 0xA0, 0x01, 0x44, 0x23,
-       0xA1, 0x01, 0x80, 0x73, 0x4D, 0x00, 0x03, 0xA3, 0xE0, 0x04, 0x00, 0x33, 0x27, 0x00, 0xC2, 0x88,
-       0x04, 0x01, 0x04, 0xDC, 0x02, 0x23, 0xA2, 0x01, 0x04, 0x23, 0xA0, 0x01, 0x06, 0x98, 0x14, 0x95,
-       0x4B, 0x00, 0xF6, 0x00, 0x4F, 0x04, 0x4F, 0x00, 0x00, 0xA3, 0x0E, 0x05, 0x00, 0x05, 0x76, 0x00,
-       0x06, 0x61, 0x00, 0xA2, 0x08, 0x05, 0xF6, 0x84, 0x48, 0x97, 0xCD, 0x04, 0x12, 0x85, 0x48, 0x04,
-       0xFF, 0x23, 0x84, 0x80, 0x02, 0x01, 0x03, 0xDA, 0x80, 0x23, 0x82, 0x01, 0x22, 0x85, 0x02, 0x23,
-       0xA0, 0x01, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x2E, 0x05, 0x1D, 0x01, 0x04, 0xD6, 0xFF, 0x23,
-       0x86, 0x41, 0x4B, 0x60, 0xCB, 0x00, 0xFF, 0x23, 0x80, 0x01, 0x49, 0x00, 0x81, 0x01, 0x04, 0x01,
-       0x02, 0xC8, 0x30, 0x01, 0x80, 0x01, 0xF7, 0x04, 0x03, 0x01, 0x49, 0x04, 0x80, 0x01, 0xC9, 0x00,
-       0x00, 0x05, 0x00, 0x01, 0xFF, 0xA0, 0x4E, 0x05, 0x77, 0x04, 0x01, 0x23, 0xEA, 0x00, 0x5D, 0x00,
-       0xFE, 0xC7, 0x00, 0x62, 0x00, 0x23, 0xEA, 0x00, 0x00, 0x63, 0x07, 0xA4, 0xCC, 0x05, 0x03, 0x03,
-       0x02, 0xA0, 0x7C, 0x05, 0xC8, 0x85, 0x00, 0x33, 0x2D, 0x00, 0xC2, 0x88, 0x04, 0xA0, 0xA2, 0x05,
-       0x80, 0x63, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x8E, 0x05, 0x1D, 0x01, 0x06, 0xD6, 0x02, 0x23,
-       0x02, 0x41, 0x82, 0x01, 0x50, 0x00, 0x64, 0x97, 0xF0, 0x84, 0x04, 0x23, 0x02, 0x41, 0x82, 0x01,
-       0xF0, 0x84, 0x08, 0xA0, 0xA8, 0x05, 0xC8, 0x85, 0x03, 0xA0, 0xAE, 0x05, 0xC8, 0x85, 0x01, 0xA0,
-       0xBA, 0x05, 0x88, 0x00, 0x80, 0x63, 0xB8, 0x96, 0x6A, 0x85, 0x07, 0xA0, 0xC6, 0x05, 0x06, 0x23,
-       0x6A, 0x98, 0x48, 0x23, 0xF8, 0x88, 0xC8, 0x86, 0x80, 0x63, 0x6A, 0x85, 0x00, 0x63, 0x4A, 0x00,
-       0x06, 0x61, 0x00, 0xA2, 0x0A, 0x06, 0x1D, 0x01, 0x18, 0xD4, 0xC0, 0x23, 0x07, 0x41, 0x83, 0x03,
-       0x80, 0x63, 0x06, 0xA6, 0xEC, 0x05, 0x00, 0x33, 0x37, 0x00, 0xC2, 0x88, 0x1D, 0x01, 0x02, 0xD6,
-       0x46, 0x23, 0xF8, 0x88, 0x63, 0x60, 0x83, 0x03, 0x80, 0x63, 0x06, 0xA6, 0x04, 0x06, 0x00, 0x33,
-       0x38, 0x00, 0xC2, 0x88, 0xEF, 0x04, 0x6F, 0x00, 0x00, 0x63, 0x4B, 0x00, 0x06, 0x41, 0xCB, 0x00,
-       0x52, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x22, 0x06, 0x1D, 0x01, 0x03, 0xCA, 0xC0, 0x23, 0x07, 0x41,
-       0x00, 0x63, 0x1D, 0x01, 0x04, 0xCC, 0x00, 0x33, 0x00, 0x83, 0xC0, 0x20, 0x81, 0x62, 0x80, 0x23,
-       0x07, 0x41, 0x00, 0x63, 0x80, 0x67, 0x08, 0x23, 0x83, 0x03, 0x80, 0x63, 0x00, 0x63, 0x06, 0xA6,
-       0x50, 0x06, 0x07, 0xA6, 0xA4, 0x06, 0x02, 0xA6, 0xFC, 0x06, 0x00, 0x33, 0x39, 0x00, 0xC2, 0x88,
-       0x00, 0x00, 0x01, 0xA0, 0x16, 0x07, 0xCE, 0x95, 0x83, 0x03, 0x80, 0x63, 0x06, 0xA6, 0x64, 0x06,
-       0x07, 0xA6, 0xA4, 0x06, 0x00, 0x00, 0x01, 0xA0, 0x16, 0x07, 0x00, 0x2B, 0x40, 0x0E, 0x80, 0x63,
-       0x01, 0x00, 0x06, 0xA6, 0x80, 0x06, 0x07, 0xA6, 0xA4, 0x06, 0x00, 0x33, 0x3A, 0x00, 0xC2, 0x88,
-       0x40, 0x0E, 0x80, 0x63, 0x00, 0x43, 0x00, 0xA0, 0x72, 0x06, 0x06, 0xA6, 0x98, 0x06, 0x07, 0xA6,
-       0xA4, 0x06, 0x00, 0x33, 0x3B, 0x00, 0xC2, 0x88, 0x80, 0x67, 0x40, 0x0E, 0x80, 0x63, 0x07, 0xA6,
-       0xA4, 0x06, 0x00, 0x63, 0x03, 0x03, 0x80, 0x63, 0x88, 0x00, 0x01, 0xA2, 0xB8, 0x06, 0x07, 0xA2,
-       0xFC, 0x06, 0x00, 0x33, 0x35, 0x00, 0xC2, 0x88, 0x07, 0xA6, 0xC2, 0x06, 0x00, 0x33, 0x2A, 0x00,
-       0xC2, 0x88, 0x03, 0x03, 0x03, 0xA2, 0xCE, 0x06, 0x07, 0x23, 0x80, 0x00, 0x08, 0x87, 0x80, 0x63,
-       0x89, 0x00, 0x0A, 0x2B, 0x07, 0xA6, 0xDE, 0x06, 0x00, 0x33, 0x29, 0x00, 0xC2, 0x88, 0x00, 0x43,
-       0x00, 0xA2, 0xEA, 0x06, 0xC0, 0x0E, 0x80, 0x63, 0xD4, 0x86, 0xC0, 0x0E, 0x00, 0x33, 0x00, 0x80,
-       0xC0, 0x20, 0x81, 0x62, 0x04, 0x01, 0x08, 0xDA, 0x80, 0x63, 0x00, 0x63, 0x80, 0x67, 0x00, 0x33,
-       0x00, 0x40, 0xC0, 0x20, 0x81, 0x62, 0x00, 0x63, 0x80, 0x7B, 0x80, 0x63, 0x06, 0xA6, 0x5C, 0x06,
-       0x00, 0x33, 0x2C, 0x00, 0xC2, 0x88, 0x0C, 0xA2, 0x30, 0x07, 0xCE, 0x95, 0x83, 0x03, 0x80, 0x63,
-       0x06, 0xA6, 0x2E, 0x07, 0x07, 0xA6, 0xA4, 0x06, 0x00, 0x33, 0x3D, 0x00, 0xC2, 0x88, 0x00, 0x00,
-       0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0x0C, 0xA0, 0x46, 0x07, 0x07, 0xA6, 0xA4, 0x06, 0xBF, 0x23,
-       0x04, 0x61, 0x84, 0x01, 0xD2, 0x84, 0x00, 0x63, 0xF0, 0x04, 0x01, 0x01, 0xF1, 0x00, 0x00, 0x01,
-       0xF2, 0x00, 0x01, 0x05, 0x80, 0x01, 0x72, 0x04, 0x71, 0x00, 0x81, 0x01, 0x70, 0x04, 0x80, 0x05,
-       0x81, 0x05, 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04, 0x01, 0x01, 0xF1, 0x00, 0x70, 0x00,
-       0x81, 0x01, 0x70, 0x04, 0x71, 0x00, 0x81, 0x01, 0x72, 0x00, 0x80, 0x01, 0x71, 0x04, 0x70, 0x00,
-       0x80, 0x01, 0x70, 0x04, 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04, 0x00, 0x01, 0xF1, 0x00,
-       0x70, 0x00, 0x80, 0x01, 0x70, 0x04, 0x71, 0x00, 0x80, 0x01, 0x72, 0x00, 0x81, 0x01, 0x71, 0x04,
-       0x70, 0x00, 0x81, 0x01, 0x70, 0x04, 0x00, 0x63, 0x00, 0x23, 0xB3, 0x01, 0x83, 0x05, 0xA3, 0x01,
-       0xA2, 0x01, 0xA1, 0x01, 0x01, 0x23, 0xA0, 0x01, 0x00, 0x01, 0xC8, 0x00, 0x03, 0xA1, 0xC6, 0x07,
-       0x00, 0x33, 0x07, 0x00, 0xC2, 0x88, 0x80, 0x05, 0x81, 0x05, 0x04, 0x01, 0x11, 0xC8, 0x48, 0x00,
-       0xB0, 0x01, 0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, 0x05, 0x01, 0x48, 0x04, 0x00, 0x43, 0x00, 0xA2,
-       0xE6, 0x07, 0x00, 0x05, 0xDC, 0x87, 0x00, 0x01, 0xC8, 0x00, 0xFF, 0x23, 0x80, 0x01, 0x05, 0x05,
-       0x00, 0x63, 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04, 0x00, 0x02, 0x80, 0x43, 0x76, 0x08,
-       0x80, 0x02, 0x77, 0x04, 0x00, 0x63, 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04, 0x00, 0x02,
-       0x00, 0xA0, 0x16, 0x08, 0x18, 0x88, 0x00, 0x43, 0x76, 0x08, 0x80, 0x02, 0x77, 0x04, 0x00, 0x63,
-       0xF3, 0x04, 0x00, 0x23, 0xF4, 0x00, 0x74, 0x00, 0x80, 0x43, 0xF4, 0x00, 0xCF, 0x40, 0x00, 0xA2,
-       0x46, 0x08, 0x74, 0x04, 0x02, 0x01, 0xF7, 0xC9, 0xF6, 0xD9, 0x00, 0x01, 0x01, 0xA1, 0x26, 0x08,
-       0x06, 0x98, 0x14, 0x95, 0x26, 0x88, 0x73, 0x04, 0x00, 0x63, 0xF3, 0x04, 0x75, 0x04, 0x5C, 0x88,
-       0x02, 0x01, 0x04, 0xD8, 0x48, 0x97, 0x06, 0x98, 0x14, 0x95, 0x4C, 0x88, 0x75, 0x00, 0x00, 0xA3,
-       0x66, 0x08, 0x00, 0x05, 0x50, 0x88, 0x73, 0x04, 0x00, 0x63, 0x80, 0x7B, 0x80, 0x63, 0x06, 0xA6,
-       0x78, 0x08, 0x00, 0x33, 0x3E, 0x00, 0xC2, 0x88, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0x00, 0x63,
-       0x38, 0x2B, 0x9E, 0x88, 0x38, 0x2B, 0x94, 0x88, 0x32, 0x09, 0x31, 0x05, 0x94, 0x98, 0x05, 0x05,
-       0xB2, 0x09, 0x00, 0x63, 0x00, 0x32, 0x00, 0x36, 0x00, 0x3A, 0x00, 0x3E, 0x00, 0x63, 0x80, 0x32,
-       0x80, 0x36, 0x80, 0x3A, 0x80, 0x3E, 0x00, 0x63, 0x38, 0x2B, 0x40, 0x32, 0x40, 0x36, 0x40, 0x3A,
-       0x40, 0x3E, 0x00, 0x63, 0x5A, 0x20, 0xC9, 0x40, 0x00, 0xA0, 0xB4, 0x08, 0x5D, 0x00, 0xFE, 0xC3,
-       0x00, 0x63, 0x80, 0x73, 0xE6, 0x20, 0x02, 0x23, 0xE8, 0x00, 0x82, 0x73, 0xFF, 0xFD, 0x80, 0x73,
-       0x13, 0x23, 0xF8, 0x88, 0x66, 0x20, 0xC0, 0x20, 0x04, 0x23, 0xA0, 0x01, 0xA1, 0x23, 0xA1, 0x01,
-       0x81, 0x62, 0xE2, 0x88, 0x80, 0x73, 0x80, 0x77, 0x68, 0x00, 0x00, 0xA2, 0x80, 0x00, 0x03, 0xC2,
-       0xF1, 0xC7, 0x41, 0x23, 0xF8, 0x88, 0x11, 0x23, 0xA1, 0x01, 0x04, 0x23, 0xA0, 0x01, 0xD2, 0x84,
-};
+uchar _mcode_buf[ ] = {
+  0x01,  0x03,  0x01,  0x19,  0x0F,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+  0x0F,  0x0F,  0x0F,  0x0F,  0x0F,  0x0F,  0x0F,  0x0F,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+  0x00,  0x00,  0x00,  0x00,  0x10,  0x0D,  0x09,  0x05,  0x01,  0x00,  0x00,  0x00,  0x00,  0xFF,  0x00,  0x00,
+  0x00,  0x00,  0x00,  0x00,  0xFF,  0x80,  0xFF,  0xFF,  0x01,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+  0x00,  0x00,  0x00,  0x23,  0x00,  0x21,  0x00,  0x00,  0x00,  0x07,  0x00,  0xFF,  0x00,  0x00,  0x00,  0x00,
+  0xFF,  0xFF,  0xFF,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0xDC,  0x88,  0x00,  0x00,  0x00,  0x00,
+  0x80,  0x73,  0x48,  0x04,  0x36,  0x00,  0x00,  0xA2,  0xC2,  0x00,  0x80,  0x73,  0x03,  0x23,  0x36,  0x40,
+  0xB6,  0x00,  0x36,  0x00,  0x05,  0xD6,  0x0C,  0xD2,  0x12,  0xDA,  0x00,  0xA2,  0xC2,  0x00,  0x92,  0x80,
+  0x18,  0x98,  0x50,  0x00,  0xF5,  0x00,  0x42,  0x98,  0xDF,  0x23,  0x36,  0x60,  0xB6,  0x00,  0x92,  0x80,
+  0x4F,  0x00,  0xF5,  0x00,  0x42,  0x98,  0xEF,  0x23,  0x36,  0x60,  0xB6,  0x00,  0x92,  0x80,  0x80,  0x62,
+  0x92,  0x80,  0x00,  0x46,  0x17,  0xEE,  0x13,  0xEA,  0x02,  0x01,  0x09,  0xD8,  0xCD,  0x04,  0x4D,  0x00,
+  0x00,  0xA3,  0xD6,  0x00,  0xA0,  0x97,  0x7F,  0x23,  0x04,  0x61,  0x84,  0x01,  0xCC,  0x84,  0xD2,  0xC1,
+  0x80,  0x73,  0xCD,  0x04,  0x4D,  0x00,  0x00,  0xA3,  0xE2,  0x01,  0xA0,  0x97,  0xCE,  0x81,  0x00,  0x33,
+  0x02,  0x00,  0xBA,  0x88,  0x80,  0x73,  0x80,  0x77,  0x00,  0x01,  0x01,  0xA1,  0x02,  0x01,  0x4F,  0x00,
+  0x7E,  0x97,  0x07,  0xA6,  0x0C,  0x01,  0x00,  0x33,  0x03,  0x00,  0xBA,  0x88,  0x03,  0x03,  0x03,  0xDE,
+  0x00,  0x33,  0x05,  0x00,  0xBA,  0x88,  0xCE,  0x00,  0x69,  0x60,  0xCE,  0x00,  0x02,  0x03,  0x4A,  0x60,
+  0x00,  0xA2,  0x80,  0x01,  0x80,  0x63,  0x07,  0xA6,  0x2C,  0x01,  0x80,  0x81,  0x03,  0x03,  0x80,  0x63,
+  0xE2,  0x00,  0x07,  0xA6,  0x3C,  0x01,  0x00,  0x33,  0x04,  0x00,  0xBA,  0x88,  0x03,  0x07,  0x02,  0x01,
+  0x04,  0xCA,  0x0D,  0x23,  0x62,  0x98,  0x4D,  0x04,  0xEA,  0x84,  0x05,  0xD8,  0x0D,  0x23,  0x62,  0x98,
+  0xCD,  0x04,  0x15,  0x23,  0xF0,  0x88,  0xFB,  0x23,  0x02,  0x61,  0x82,  0x01,  0x80,  0x63,  0x02,  0x03,
+  0x06,  0xA3,  0x6A,  0x01,  0x00,  0x33,  0x0A,  0x00,  0xBA,  0x88,  0x4E,  0x00,  0x07,  0xA3,  0x76,  0x01,
+  0x00,  0x33,  0x0B,  0x00,  0xBA,  0x88,  0xCD,  0x04,  0x36,  0x2D,  0x00,  0x33,  0x1A,  0x00,  0xBA,  0x88,
+  0x50,  0x04,  0x90,  0x81,  0x06,  0xAB,  0x8A,  0x01,  0x90,  0x81,  0x4E,  0x00,  0x07,  0xA3,  0x9A,  0x01,
+  0x50,  0x00,  0x00,  0xA3,  0x44,  0x01,  0x00,  0x05,  0x84,  0x81,  0x40,  0x97,  0x02,  0x01,  0x05,  0xC6,
+  0x04,  0x23,  0xA0,  0x01,  0x15,  0x23,  0xA1,  0x01,  0xC6,  0x81,  0xFD,  0x23,  0x02,  0x61,  0x82,  0x01,
+  0x0A,  0xDA,  0x4A,  0x00,  0x06,  0x61,  0x00,  0xA0,  0xBC,  0x01,  0x80,  0x63,  0xCD,  0x04,  0x36,  0x2D,
+  0x00,  0x33,  0x1B,  0x00,  0xBA,  0x88,  0x06,  0x23,  0x62,  0x98,  0xCD,  0x04,  0xCC,  0x84,  0x06,  0x01,
+  0x00,  0xA2,  0xDC,  0x01,  0x57,  0x60,  0x00,  0xA0,  0xE2,  0x01,  0xCC,  0x84,  0x80,  0x23,  0xA0,  0x01,
+  0xCC,  0x84,  0x80,  0x73,  0x4B,  0x00,  0x06,  0x61,  0x00,  0xA2,  0x08,  0x02,  0x04,  0x01,  0x0C,  0xDE,
+  0x02,  0x01,  0x03,  0xCC,  0x4F,  0x00,  0x7E,  0x97,  0x04,  0x82,  0x08,  0x23,  0x02,  0x41,  0x82,  0x01,
+  0x4F,  0x00,  0x5C,  0x97,  0x48,  0x04,  0x84,  0x80,  0xEA,  0x97,  0x00,  0x46,  0x56,  0x00,  0x03,  0xC0,
+  0x01,  0x23,  0xE8,  0x00,  0x81,  0x73,  0x06,  0x29,  0x03,  0x42,  0x06,  0xE2,  0x03,  0xEE,  0x67,  0xEB,
+  0x11,  0x23,  0xF0,  0x88,  0xFE,  0x97,  0xF4,  0x80,  0x80,  0x73,  0x80,  0x77,  0x06,  0xA6,  0x36,  0x02,
+  0x00,  0x33,  0x31,  0x00,  0xBA,  0x88,  0x04,  0x01,  0x03,  0xD8,  0xAC,  0x98,  0x36,  0x96,  0x48,  0x82,
+  0xC6,  0x95,  0x80,  0x67,  0x83,  0x03,  0x80,  0x63,  0xB6,  0x2D,  0x02,  0xA6,  0x72,  0x02,  0x07,  0xA6,
+  0x60,  0x02,  0x06,  0xA6,  0x64,  0x02,  0x03,  0xA6,  0x68,  0x02,  0x00,  0x33,  0x10,  0x00,  0xBA,  0x88,
+  0x62,  0x95,  0x4A,  0x82,  0x2C,  0x96,  0x4A,  0x82,  0x04,  0x23,  0xA0,  0x01,  0x14,  0x23,  0xA1,  0x01,
+  0x22,  0x84,  0x04,  0x01,  0x0C,  0xDC,  0xE0,  0x23,  0x25,  0x61,  0xEF,  0x00,  0x14,  0x01,  0x4F,  0x04,
+  0xA8,  0x01,  0x6F,  0x00,  0xA5,  0x01,  0x03,  0x23,  0xA4,  0x01,  0x06,  0x23,  0x9C,  0x01,  0x24,  0x2B,
+  0x1C,  0x01,  0x02,  0xA6,  0xA4,  0x02,  0x07,  0xA6,  0x60,  0x02,  0x06,  0xA6,  0x64,  0x02,  0x00,  0x33,
+  0x12,  0x00,  0xBA,  0x88,  0x00,  0x0E,  0x80,  0x63,  0x00,  0x43,  0x00,  0xA0,  0x92,  0x02,  0x4D,  0x04,
+  0x04,  0x01,  0x0B,  0xDC,  0xE7,  0x23,  0x04,  0x61,  0x84,  0x01,  0x10,  0x31,  0x12,  0x35,  0x14,  0x01,
+  0xEC,  0x00,  0x6C,  0x38,  0x00,  0x3F,  0x00,  0x00,  0xE4,  0x82,  0x18,  0x23,  0x04,  0x61,  0x18,  0xA0,
+  0xDC,  0x02,  0x04,  0x01,  0x98,  0xC8,  0x00,  0x33,  0x1F,  0x00,  0xBA,  0x88,  0x08,  0x31,  0x0A,  0x35,
+  0x0C,  0x39,  0x0E,  0x3D,  0x78,  0x98,  0xB6,  0x2D,  0x01,  0xA6,  0x0E,  0x03,  0x00,  0xA6,  0x0E,  0x03,
+  0x07,  0xA6,  0x06,  0x03,  0x06,  0xA6,  0x0A,  0x03,  0x03,  0xA6,  0x06,  0x04,  0x02,  0xA6,  0x72,  0x02,
+  0x00,  0x33,  0x33,  0x00,  0xBA,  0x88,  0x62,  0x95,  0xE8,  0x82,  0x2C,  0x96,  0xE8,  0x82,  0x7C,  0x98,
+  0x80,  0x42,  0x78,  0x98,  0x60,  0xE4,  0x04,  0x01,  0x29,  0xC8,  0x31,  0x05,  0x07,  0x01,  0x00,  0xA2,
+  0x4E,  0x03,  0x00,  0x43,  0x87,  0x01,  0x05,  0x05,  0x80,  0x98,  0x78,  0x98,  0x00,  0xA6,  0x10,  0x03,
+  0x07,  0xA6,  0x46,  0x03,  0x03,  0xA6,  0x22,  0x04,  0x06,  0xA6,  0x4A,  0x03,  0x01,  0xA6,  0x10,  0x03,
+  0x00,  0x33,  0x25,  0x00,  0xBA,  0x88,  0x62,  0x95,  0x2C,  0x83,  0x2C,  0x96,  0x2C,  0x83,  0x04,  0x01,
+  0x0C,  0xCE,  0x03,  0xC8,  0x00,  0x33,  0x42,  0x00,  0xBA,  0x88,  0x00,  0x01,  0x05,  0x05,  0xFF,  0xA2,
+  0x6C,  0x03,  0xB1,  0x01,  0x08,  0x23,  0xB2,  0x01,  0x28,  0x83,  0x05,  0x05,  0x15,  0x01,  0x00,  0xA2,
+  0x8C,  0x03,  0xEC,  0x00,  0x6E,  0x00,  0x95,  0x01,  0x6C,  0x38,  0x00,  0x3F,  0x00,  0x00,  0x01,  0xA6,
+  0x88,  0x03,  0x00,  0xA6,  0x88,  0x03,  0xFC,  0x83,  0x80,  0x42,  0x78,  0x98,  0x01,  0xA6,  0x96,  0x03,
+  0x00,  0xA6,  0xAE,  0x03,  0xFC,  0x83,  0xA0,  0x98,  0x80,  0x42,  0x01,  0xA6,  0x96,  0x03,  0x07,  0xA6,
+  0xA4,  0x03,  0xC6,  0x83,  0x62,  0x95,  0x9A,  0x83,  0x00,  0x33,  0x2F,  0x00,  0xBA,  0x88,  0xA0,  0x98,
+  0x80,  0x42,  0x00,  0xA6,  0xAE,  0x03,  0x07,  0xA6,  0xBC,  0x03,  0xC6,  0x83,  0x62,  0x95,  0xB2,  0x83,
+  0x00,  0x33,  0x26,  0x00,  0xBA,  0x88,  0x38,  0x2B,  0x80,  0x32,  0x80,  0x36,  0x04,  0x23,  0xA0,  0x01,
+  0x12,  0x23,  0xA1,  0x01,  0xFC,  0x83,  0x04,  0xF0,  0x80,  0x6B,  0x00,  0x33,  0x20,  0x00,  0xBA,  0x88,
+  0x03,  0xA6,  0xFA,  0x03,  0x07,  0xA6,  0xF2,  0x03,  0x06,  0xA6,  0xF6,  0x03,  0x00,  0x33,  0x17,  0x00,
+  0xBA,  0x88,  0x62,  0x95,  0xE0,  0x83,  0x2C,  0x96,  0xE0,  0x83,  0x06,  0x84,  0x04,  0xF0,  0x80,  0x6B,
+  0x00,  0x33,  0x20,  0x00,  0xBA,  0x88,  0xB6,  0x2D,  0x03,  0xA6,  0x22,  0x04,  0x07,  0xA6,  0x1A,  0x04,
+  0x06,  0xA6,  0x1E,  0x04,  0x00,  0x33,  0x30,  0x00,  0xBA,  0x88,  0x62,  0x95,  0x06,  0x84,  0x2C,  0x96,
+  0x06,  0x84,  0x1D,  0x01,  0x06,  0xCC,  0x00,  0x33,  0x00,  0x84,  0xC0,  0x20,  0x00,  0x23,  0xEA,  0x00,
+  0x81,  0x62,  0xA2,  0x0D,  0x80,  0x63,  0x07,  0xA6,  0x40,  0x04,  0x00,  0x33,  0x18,  0x00,  0xBA,  0x88,
+  0x03,  0x03,  0x80,  0x63,  0xA3,  0x01,  0x07,  0xA4,  0x4A,  0x04,  0x23,  0x01,  0x00,  0xA2,  0x6C,  0x04,
+  0x0A,  0xA0,  0x5C,  0x04,  0xE0,  0x00,  0x00,  0x33,  0x1D,  0x00,  0xBA,  0x88,  0x0B,  0xA0,  0x68,  0x04,
+  0xE0,  0x00,  0x00,  0x33,  0x1E,  0x00,  0xBA,  0x88,  0x42,  0x23,  0xF0,  0x88,  0x00,  0x23,  0x22,  0xA3,
+  0xCC,  0x04,  0x08,  0x23,  0x22,  0xA3,  0x88,  0x04,  0x28,  0x23,  0x22,  0xA3,  0x94,  0x04,  0x02,  0x23,
+  0x22,  0xA3,  0xAA,  0x04,  0x42,  0x23,  0xF0,  0x88,  0x4A,  0x00,  0x06,  0x61,  0x00,  0xA0,  0x94,  0x04,
+  0x45,  0x23,  0xF0,  0x88,  0xFE,  0x97,  0x00,  0xA2,  0xA6,  0x04,  0xAC,  0x98,  0x00,  0x33,  0x00,  0x82,
+  0xC0,  0x20,  0x81,  0x62,  0xF0,  0x81,  0x47,  0x23,  0xF0,  0x88,  0x04,  0x01,  0x0B,  0xDE,  0xFE,  0x97,
+  0xAC,  0x98,  0x00,  0x33,  0x00,  0x81,  0xC0,  0x20,  0x81,  0x62,  0x14,  0x01,  0x00,  0xA0,  0x08,  0x02,
+  0x43,  0x23,  0xF0,  0x88,  0x04,  0x23,  0xA0,  0x01,  0x44,  0x23,  0xA1,  0x01,  0x80,  0x73,  0x4D,  0x00,
+  0x03,  0xA3,  0xDA,  0x04,  0x00,  0x33,  0x27,  0x00,  0xBA,  0x88,  0x04,  0x01,  0x04,  0xDC,  0x02,  0x23,
+  0xA2,  0x01,  0x04,  0x23,  0xA0,  0x01,  0xFE,  0x97,  0x0C,  0x95,  0x4B,  0x00,  0xF6,  0x00,  0x4F,  0x04,
+  0x4F,  0x00,  0x00,  0xA3,  0x08,  0x05,  0x00,  0x05,  0x76,  0x00,  0x06,  0x61,  0x00,  0xA2,  0x02,  0x05,
+  0xF0,  0x84,  0x40,  0x97,  0xCD,  0x04,  0x0A,  0x85,  0x48,  0x04,  0x84,  0x80,  0x02,  0x01,  0x03,  0xDA,
+  0x80,  0x23,  0x82,  0x01,  0x1A,  0x85,  0x02,  0x23,  0xA0,  0x01,  0x4A,  0x00,  0x06,  0x61,  0x00,  0xA2,
+  0x26,  0x05,  0x1D,  0x01,  0x04,  0xD6,  0xFF,  0x23,  0x86,  0x41,  0x4B,  0x60,  0xCB,  0x00,  0xFF,  0x23,
+  0x80,  0x01,  0x49,  0x00,  0x81,  0x01,  0x04,  0x01,  0x02,  0xC8,  0x30,  0x01,  0x80,  0x01,  0xF7,  0x04,
+  0x03,  0x01,  0x49,  0x04,  0x80,  0x01,  0xC9,  0x00,  0x00,  0x05,  0x00,  0x01,  0xFF,  0xA0,  0x46,  0x05,
+  0x77,  0x04,  0x01,  0x23,  0xEA,  0x00,  0x5D,  0x00,  0xFE,  0xC7,  0x00,  0x62,  0x00,  0x23,  0xEA,  0x00,
+  0x00,  0x63,  0x07,  0xA4,  0xC4,  0x05,  0x03,  0x03,  0x02,  0xA0,  0x74,  0x05,  0xC0,  0x85,  0x00,  0x33,
+  0x2D,  0x00,  0xBA,  0x88,  0x04,  0xA0,  0x9A,  0x05,  0x80,  0x63,  0x4A,  0x00,  0x06,  0x61,  0x00,  0xA2,
+  0x86,  0x05,  0x1D,  0x01,  0x06,  0xD6,  0x02,  0x23,  0x02,  0x41,  0x82,  0x01,  0x50,  0x00,  0x5C,  0x97,
+  0xEA,  0x84,  0x04,  0x23,  0x02,  0x41,  0x82,  0x01,  0xEA,  0x84,  0x08,  0xA0,  0xA0,  0x05,  0xC0,  0x85,
+  0x03,  0xA0,  0xA6,  0x05,  0xC0,  0x85,  0x01,  0xA0,  0xB2,  0x05,  0x88,  0x00,  0x80,  0x63,  0xB0,  0x96,
+  0x62,  0x85,  0x07,  0xA0,  0xBE,  0x05,  0x06,  0x23,  0x62,  0x98,  0x48,  0x23,  0xF0,  0x88,  0xC0,  0x86,
+  0x80,  0x63,  0x62,  0x85,  0x00,  0x63,  0x4A,  0x00,  0x06,  0x61,  0x00,  0xA2,  0x02,  0x06,  0x1D,  0x01,
+  0x18,  0xD4,  0xC0,  0x23,  0x07,  0x41,  0x83,  0x03,  0x80,  0x63,  0x06,  0xA6,  0xE4,  0x05,  0x00,  0x33,
+  0x37,  0x00,  0xBA,  0x88,  0x1D,  0x01,  0x02,  0xD6,  0x46,  0x23,  0xF0,  0x88,  0x63,  0x60,  0x83,  0x03,
+  0x80,  0x63,  0x06,  0xA6,  0xFC,  0x05,  0x00,  0x33,  0x38,  0x00,  0xBA,  0x88,  0xEF,  0x04,  0x6F,  0x00,
+  0x00,  0x63,  0x4B,  0x00,  0x06,  0x41,  0xCB,  0x00,  0x52,  0x00,  0x06,  0x61,  0x00,  0xA2,  0x1A,  0x06,
+  0x1D,  0x01,  0x03,  0xCA,  0xC0,  0x23,  0x07,  0x41,  0x00,  0x63,  0x1D,  0x01,  0x04,  0xCC,  0x00,  0x33,
+  0x00,  0x83,  0xC0,  0x20,  0x81,  0x62,  0x80,  0x23,  0x07,  0x41,  0x00,  0x63,  0x80,  0x67,  0x08,  0x23,
+  0x83,  0x03,  0x80,  0x63,  0x00,  0x63,  0x06,  0xA6,  0x48,  0x06,  0x07,  0xA6,  0x9C,  0x06,  0x02,  0xA6,
+  0xF4,  0x06,  0x00,  0x33,  0x39,  0x00,  0xBA,  0x88,  0x00,  0x00,  0x01,  0xA0,  0x0E,  0x07,  0xC6,  0x95,
+  0x83,  0x03,  0x80,  0x63,  0x06,  0xA6,  0x5C,  0x06,  0x07,  0xA6,  0x9C,  0x06,  0x00,  0x00,  0x01,  0xA0,
+  0x0E,  0x07,  0x00,  0x2B,  0x40,  0x0E,  0x80,  0x63,  0x01,  0x00,  0x06,  0xA6,  0x78,  0x06,  0x07,  0xA6,
+  0x9C,  0x06,  0x00,  0x33,  0x3A,  0x00,  0xBA,  0x88,  0x40,  0x0E,  0x80,  0x63,  0x00,  0x43,  0x00,  0xA0,
+  0x6A,  0x06,  0x06,  0xA6,  0x90,  0x06,  0x07,  0xA6,  0x9C,  0x06,  0x00,  0x33,  0x3B,  0x00,  0xBA,  0x88,
+  0x80,  0x67,  0x40,  0x0E,  0x80,  0x63,  0x07,  0xA6,  0x9C,  0x06,  0x00,  0x63,  0x03,  0x03,  0x80,  0x63,
+  0x88,  0x00,  0x01,  0xA2,  0xB0,  0x06,  0x07,  0xA2,  0xF4,  0x06,  0x00,  0x33,  0x35,  0x00,  0xBA,  0x88,
+  0x07,  0xA6,  0xBA,  0x06,  0x00,  0x33,  0x2A,  0x00,  0xBA,  0x88,  0x03,  0x03,  0x03,  0xA2,  0xC6,  0x06,
+  0x07,  0x23,  0x80,  0x00,  0x00,  0x87,  0x80,  0x63,  0x89,  0x00,  0x0A,  0x2B,  0x07,  0xA6,  0xD6,  0x06,
+  0x00,  0x33,  0x29,  0x00,  0xBA,  0x88,  0x00,  0x43,  0x00,  0xA2,  0xE2,  0x06,  0xC0,  0x0E,  0x80,  0x63,
+  0xCC,  0x86,  0xC0,  0x0E,  0x00,  0x33,  0x00,  0x80,  0xC0,  0x20,  0x81,  0x62,  0x04,  0x01,  0x08,  0xDA,
+  0x80,  0x63,  0x00,  0x63,  0x80,  0x67,  0x00,  0x33,  0x00,  0x40,  0xC0,  0x20,  0x81,  0x62,  0x00,  0x63,
+  0x80,  0x7B,  0x80,  0x63,  0x06,  0xA6,  0x54,  0x06,  0x00,  0x33,  0x2C,  0x00,  0xBA,  0x88,  0x0C,  0xA2,
+  0x28,  0x07,  0xC6,  0x95,  0x83,  0x03,  0x80,  0x63,  0x06,  0xA6,  0x26,  0x07,  0x07,  0xA6,  0x9C,  0x06,
+  0x00,  0x33,  0x3D,  0x00,  0xBA,  0x88,  0x00,  0x00,  0x80,  0x67,  0x83,  0x03,  0x80,  0x63,  0x0C,  0xA0,
+  0x3E,  0x07,  0x07,  0xA6,  0x9C,  0x06,  0xBF,  0x23,  0x04,  0x61,  0x84,  0x01,  0xCC,  0x84,  0x00,  0x63,
+  0xF0,  0x04,  0x01,  0x01,  0xF1,  0x00,  0x00,  0x01,  0xF2,  0x00,  0x01,  0x05,  0x80,  0x01,  0x72,  0x04,
+  0x71,  0x00,  0x81,  0x01,  0x70,  0x04,  0x80,  0x05,  0x81,  0x05,  0x00,  0x63,  0xF0,  0x04,  0xF2,  0x00,
+  0x72,  0x04,  0x01,  0x01,  0xF1,  0x00,  0x70,  0x00,  0x81,  0x01,  0x70,  0x04,  0x71,  0x00,  0x81,  0x01,
+  0x72,  0x00,  0x80,  0x01,  0x71,  0x04,  0x70,  0x00,  0x80,  0x01,  0x70,  0x04,  0x00,  0x63,  0xF0,  0x04,
+  0xF2,  0x00,  0x72,  0x04,  0x00,  0x01,  0xF1,  0x00,  0x70,  0x00,  0x80,  0x01,  0x70,  0x04,  0x71,  0x00,
+  0x80,  0x01,  0x72,  0x00,  0x81,  0x01,  0x71,  0x04,  0x70,  0x00,  0x81,  0x01,  0x70,  0x04,  0x00,  0x63,
+  0x00,  0x23,  0xB3,  0x01,  0x83,  0x05,  0xA3,  0x01,  0xA2,  0x01,  0xA1,  0x01,  0x01,  0x23,  0xA0,  0x01,
+  0x00,  0x01,  0xC8,  0x00,  0x03,  0xA1,  0xBE,  0x07,  0x00,  0x33,  0x07,  0x00,  0xBA,  0x88,  0x80,  0x05,
+  0x81,  0x05,  0x04,  0x01,  0x11,  0xC8,  0x48,  0x00,  0xB0,  0x01,  0xB1,  0x01,  0x08,  0x23,  0xB2,  0x01,
+  0x05,  0x01,  0x48,  0x04,  0x00,  0x43,  0x00,  0xA2,  0xDE,  0x07,  0x00,  0x05,  0xD4,  0x87,  0x00,  0x01,
+  0xC8,  0x00,  0xFF,  0x23,  0x80,  0x01,  0x05,  0x05,  0x00,  0x63,  0xF7,  0x04,  0x1A,  0x09,  0xF6,  0x08,
+  0x6E,  0x04,  0x00,  0x02,  0x80,  0x43,  0x76,  0x08,  0x80,  0x02,  0x77,  0x04,  0x00,  0x63,  0xF7,  0x04,
+  0x1A,  0x09,  0xF6,  0x08,  0x6E,  0x04,  0x00,  0x02,  0x00,  0xA0,  0x0E,  0x08,  0x10,  0x88,  0x00,  0x43,
+  0x76,  0x08,  0x80,  0x02,  0x77,  0x04,  0x00,  0x63,  0xF3,  0x04,  0x00,  0x23,  0xF4,  0x00,  0x74,  0x00,
+  0x80,  0x43,  0xF4,  0x00,  0xCF,  0x40,  0x00,  0xA2,  0x3E,  0x08,  0x74,  0x04,  0x02,  0x01,  0xF7,  0xC9,
+  0xF6,  0xD9,  0x00,  0x01,  0x01,  0xA1,  0x1E,  0x08,  0xFE,  0x97,  0x0C,  0x95,  0x1E,  0x88,  0x73,  0x04,
+  0x00,  0x63,  0xF3,  0x04,  0x75,  0x04,  0x54,  0x88,  0x02,  0x01,  0x04,  0xD8,  0x40,  0x97,  0xFE,  0x97,
+  0x0C,  0x95,  0x44,  0x88,  0x75,  0x00,  0x00,  0xA3,  0x5E,  0x08,  0x00,  0x05,  0x48,  0x88,  0x73,  0x04,
+  0x00,  0x63,  0x80,  0x7B,  0x80,  0x63,  0x06,  0xA6,  0x70,  0x08,  0x00,  0x33,  0x3E,  0x00,  0xBA,  0x88,
+  0x80,  0x67,  0x83,  0x03,  0x80,  0x63,  0x00,  0x63,  0x38,  0x2B,  0x96,  0x88,  0x38,  0x2B,  0x8C,  0x88,
+  0x32,  0x09,  0x31,  0x05,  0x8C,  0x98,  0x05,  0x05,  0xB2,  0x09,  0x00,  0x63,  0x00,  0x32,  0x00,  0x36,
+  0x00,  0x3A,  0x00,  0x3E,  0x00,  0x63,  0x80,  0x32,  0x80,  0x36,  0x80,  0x3A,  0x80,  0x3E,  0x00,  0x63,
+  0x38,  0x2B,  0x40,  0x32,  0x40,  0x36,  0x40,  0x3A,  0x40,  0x3E,  0x00,  0x63,  0x5A,  0x20,  0xC9,  0x40,
+  0x00,  0xA0,  0xAC,  0x08,  0x5D,  0x00,  0xFE,  0xC3,  0x00,  0x63,  0x80,  0x73,  0xE6,  0x20,  0x02,  0x23,
+  0xE8,  0x00,  0x82,  0x73,  0xFF,  0xFD,  0x80,  0x73,  0x13,  0x23,  0xF0,  0x88,  0x66,  0x20,  0xC0,  0x20,
+  0x04,  0x23,  0xA0,  0x01,  0xA1,  0x23,  0xA1,  0x01,  0x81,  0x62,  0xDA,  0x88,  0x80,  0x73,  0x80,  0x77,
+  0x68,  0x00,  0x00,  0xA2,  0x80,  0x00,  0x03,  0xC2,  0xF1,  0xC7,  0x41,  0x23,  0xF0,  0x88,  0x11,  0x23,
+  0xA1,  0x01,  0x04,  0x23,  0xA0,  0x01,  0xCC,  0x84,
+} ;
+
+ushort _mcode_size = sizeof(_mcode_buf);
+ulong  _mcode_chksum = 0x012BA2FAUL ;
 
-ushort              _mcode_size = sizeof (_mcode_buf);
-ulong               _mcode_chksum = 0x012CD3FFUL;
 #define ASC_SYN_OFFSET_ONE_DISABLE_LIST  16
 uchar               _syn_offset_one_disable_cmd[ASC_SYN_OFFSET_ONE_DISABLE_LIST] =
 {
@@ -6978,7 +7558,9 @@ AscExeScsiQueue(
                return (ERR);
        }
        scsiq->q1.q_no = 0;
-       scsiq->q1.extra_bytes = 0;
+       if ((scsiq->q2.tag_code & ASC_TAG_FLAG_EXTRA_BYTES) == 0) {
+               scsiq->q1.extra_bytes = 0;
+       }
        sta = 0;
        target_ix = scsiq->q2.target_ix;
        tid_no = ASC_TIX_TO_TID(target_ix);
@@ -6988,7 +7570,7 @@ AscExeScsiQueue(
                        ((asc_dvc->sdtr_done & scsiq->q1.target_id) != 0)) {
                        sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
                        AscMsgOutSDTR(asc_dvc,
-                                                 asc_dvc->sdtr_period_tbl[(sdtr_data >> 4) & (uchar) (ASC_SYN_XFER_NO - 1)],
+                                                 asc_dvc->sdtr_period_tbl[(sdtr_data >> 4) & (uchar) (asc_dvc->max_sdtr_index - 1)],
                                                  (uchar) (sdtr_data & (uchar) ASC_SYN_MAX_OFFSET));
                        scsiq->q1.cntl |= (QC_MSG_OUT | QC_URGENT);
                }
@@ -7082,7 +7664,7 @@ AscExeScsiQueue(
                                        addr = sg_head->sg_list[sg_entry_cnt_minus_one].addr +
                                          sg_head->sg_list[sg_entry_cnt_minus_one].bytes;
                                        extra_bytes = (uchar) ((ushort) addr & 0x0003);
-                                       if (extra_bytes != 0) {
+                                       if ((extra_bytes != 0) && ((scsiq->q2.tag_code & ASC_TAG_FLAG_EXTRA_BYTES) == 0)) {
                                                scsiq->q2.tag_code |= ASC_TAG_FLAG_EXTRA_BYTES;
                                                scsiq->q1.extra_bytes = extra_bytes;
                                                sg_head->sg_list[sg_entry_cnt_minus_one].bytes -= (ulong) extra_bytes;
@@ -7122,7 +7704,7 @@ AscExeScsiQueue(
                                  ) {
                                        addr = scsiq->q1.data_addr + scsiq->q1.data_cnt;
                                        extra_bytes = (uchar) ((ushort) addr & 0x0003);
-                                       if (extra_bytes != 0) {
+                                       if ((extra_bytes != 0) && ((scsiq->q2.tag_code & ASC_TAG_FLAG_EXTRA_BYTES) == 0)) {
                                                if (((ushort) scsiq->q1.data_cnt & 0x01FF) == 0) {
                                                        scsiq->q2.tag_code |= ASC_TAG_FLAG_EXTRA_BYTES;
                                                        scsiq->q1.data_cnt -= (ulong) extra_bytes;
@@ -7307,7 +7889,7 @@ AscGetNumOfFreeQueue(
                return (cur_free_qs);
        }
        if (n_qs > 1) {
-               if (n_qs > asc_dvc->last_q_shortage) {
+               if ((n_qs > asc_dvc->last_q_shortage) && ( n_qs <= ( asc_dvc->max_total_qng - ASC_MIN_FREE_Q ))) {
                        asc_dvc->last_q_shortage = n_qs;
                }
        }
@@ -7332,7 +7914,7 @@ AscPutReadyQueue(
                ((asc_dvc->sdtr_done & scsiq->q1.target_id) == 0)) {
                tid_no = ASC_TIX_TO_TID(scsiq->q2.target_ix);
                sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
-               syn_period_ix = (sdtr_data >> 4) & (ASC_SYN_XFER_NO - 1);
+               syn_period_ix = (sdtr_data >> 4) & (asc_dvc->max_sdtr_index - 1);
                syn_offset = sdtr_data & ASC_SYN_MAX_OFFSET;
                AscMsgOutSDTR(asc_dvc,
                                          asc_dvc->sdtr_period_tbl[syn_period_ix],
@@ -8686,8 +9268,7 @@ AscInitAscDvcVar(
        asc_dvc->max_dma_count = AscGetMaxDmaCount(asc_dvc->bus_type);
        asc_dvc->redo_scam = 0;
        asc_dvc->res2 = 0;
-       asc_dvc->res4 = 0;
-       asc_dvc->res6 = 0;
+       asc_dvc->host_init_sdtr_index = 0;
        asc_dvc->res7 = 0;
        asc_dvc->res8 = 0;
        asc_dvc->cfg->disc_enable = ASC_SCSI_WIDTH_BIT_SET;
@@ -8746,7 +9327,6 @@ AscInitAscDvcVar(
                asc_dvc->scsiq_busy_head[i] = (ASC_SCSI_Q dosfar *) 0L;
                asc_dvc->scsiq_busy_tail[i] = (ASC_SCSI_Q dosfar *) 0L;
                asc_dvc->cfg->max_tag_qng[i] = ASC_MAX_INRAM_TAG_QNG;
-               asc_dvc->cfg->sdtr_period_offset[i] = (uchar) (ASC_DEF_SDTR_OFFSET | (ASC_DEF_SDTR_INDEX << 4));
        }
        return (warn_code);
 }
@@ -8855,12 +9435,20 @@ AscInitFromEEP(
        }
        eep_config->chip_scsi_id &= ASC_MAX_TID;
        asc_dvc->cfg->chip_scsi_id = eep_config->chip_scsi_id;
+       if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA ) == ASC_IS_PCI_ULTRA ) &&
+           !(asc_dvc->dvc_cntl & ASC_CNTL_SDTR_ENABLE_ULTRA)) {
+               asc_dvc->host_init_sdtr_index = ASC_SDTR_ULTRA_PCI_10MB_INDEX;
+       }
+
        for (i = 0; i <= ASC_MAX_TID; i++) {
 #if CC_TMP_USE_EEP_SDTR
                asc_dvc->cfg->sdtr_period_offset[i] = eep_config->dos_int13_table[i];
 #endif
                asc_dvc->dos_int13_table[i] = eep_config->dos_int13_table[i];
                asc_dvc->cfg->max_tag_qng[i] = eep_config->max_tag_qng;
+               asc_dvc->cfg->sdtr_period_offset[i] =
+                       (uchar) (ASC_DEF_SDTR_OFFSET |
+                                        (asc_dvc->host_init_sdtr_index << 4));
        }
        eep_config->cfg_msw = AscGetChipCfgMsw(iop_base);
 #if CC_CHK_FIX_EEP_CONTENT
@@ -8880,6 +9468,7 @@ AscInitWithoutEEP(
        PortAddr            iop_base;
        ushort              warn_code;
        ushort              cfg_msw;
+       int                                     i;
        iop_base = asc_dvc->iop_base;
        warn_code = 0;
        cfg_msw = AscGetChipCfgMsw(iop_base);
@@ -8889,12 +9478,19 @@ AscInitWithoutEEP(
                AscSetChipCfgMsw(iop_base, cfg_msw);
        }
        if (!AscTestExternalLram(asc_dvc)) {
-               if (asc_dvc->bus_type & ASC_IS_PCI) {
+               if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA)) {
+                       asc_dvc->max_total_qng = ASC_MAX_PCI_ULTRA_INRAM_TOTAL_QNG ;
+                       for( i = 0 ; i <= ASC_MAX_TID ; i++ ) {
+                               asc_dvc->cfg->max_tag_qng[ i ] = ASC_MAX_PCI_ULTRA_INRAM_TAG_QNG ;
+                       }
+               } else {
                        cfg_msw |= 0x0800;
                        AscSetChipCfgMsw(iop_base, cfg_msw);
                        asc_dvc->max_total_qng = ASC_MAX_PCI_INRAM_TOTAL_QNG;
+                       for (i = 0 ; i <= ASC_MAX_TID ; i++) {
+                               asc_dvc->cfg->max_tag_qng[ i ] = ASC_MAX_INRAM_TAG_QNG;
+                       }
                }
-       } else {
        }
        if (asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL | ASC_IS_EISA)) {
                asc_dvc->irq_no = AscGetChipIRQ(iop_base, asc_dvc->bus_type);
@@ -8959,6 +9555,7 @@ AscInitPollIsrCallBack(
        ASC_ISR_CALLBACK    asc_isr_callback;
        uchar               cp_sen_len;
        uchar               i;
+       ASC_DBG(1, "AscInitPollIsrCallBack: begin\n");
        if ((scsi_done_q->d2.flag & ASC_FLAG_SCSIQ_REQ) != 0) {
                scsiq_req = (ASC_SCSI_REQ_Q dosfar *) scsi_done_q->d2.srb_ptr;
                scsiq_req->r3.done_stat = scsi_done_q->d3.done_stat;
@@ -8981,6 +9578,7 @@ AscInitPollIsrCallBack(
                        (*asc_isr_callback) (asc_dvc, scsi_done_q);
                }
        }
+       ASC_DBG(1, "AscInitPollIsrCallBack: end\n");
        return;
 }
 
@@ -9316,6 +9914,7 @@ AscInitPollTarget(
                asc_dvc->init_sdtr &= ~tid_bits;
                tmp_disable_init_sdtr = TRUE;
        }
+       ASC_DBG(1, "AscInitPollTarget: before PollScsiInquiry\n");
        if (
                   PollScsiInquiry(asc_dvc, scsiq, (uchar dosfar *) inq,
                                                   sizeof (ASC_SCSI_INQUIRY)) == 1
@@ -9353,19 +9952,8 @@ AscInitPollTarget(
                                        if (inq->byte7.CmdQue) {
                                                asc_dvc->cfg->can_tagged_qng |= tid_bits;
                                                if (asc_dvc->cfg->cmd_qng_enabled & tid_bits) {
-#if CC_FIX_QUANTUM_XP34301_1071
-                                                       if (
-                                                                  (inq->add_len >= 32)
-                                                                  && (AscCompareString(inq->vendor_id, (uchar *) "QUANTUM XP34301", 15) == 0)
-                                                                  && (AscCompareString(inq->product_rev_level, (uchar *) "1071", 4) == 0)
-                                                         ) {
-                                                       } else {
-#endif
                                                                asc_dvc->use_tagged_qng |= tid_bits;
                                                                asc_dvc->max_dvc_qng[tid_no] = asc_dvc->cfg->max_tag_qng[tid_no];
-#if CC_FIX_QUANTUM_XP34301_1071
-                                                       }
-#endif
                                                }
                                        }
                                        if (!inq->byte7.Sync) {
@@ -9404,12 +9992,12 @@ AscInitPollTarget(
                                }
                        }
                        sta = 1;
-#if CC_INIT_TARGET_TEST_UNIT_READY
+                       ASC_DBG(1, "AscInitPollTarget: before InitTestUnitReady\n");
                        sta = InitTestUnitReady(asc_dvc, scsiq);
-#endif
-#if CC_INIT_TARGET_READ_CAPACITY
                        if (sta == 1) {
                                if ((cap_info != 0L) && support_read_cap) {
+                                       ASC_DBG(1,
+                                               "AscInitPollTarget: before PollScsiReadCapacity\n");
                                        if (PollScsiReadCapacity(asc_dvc, scsiq,
                                                                                         cap_info) != 1) {
                                                cap_info->lba = 0L;
@@ -9418,12 +10006,11 @@ AscInitPollTarget(
                                        }
                                }
                        }
-#endif
                } else {
                        asc_dvc->start_motor &= ~tid_bits;
                }
-       } else {
        }
+       ASC_DBG1(1, "AscInitPollTarget: dvc_found %d\n", dvc_found);
        return (dvc_found);
 }
 
@@ -9435,13 +10022,14 @@ PollQueueDone(
 )
 {
        int                 status;
-       int                 retry;
-       retry = 0;
+       int                 retry = 0;
+
+       ASC_DBG1(1, "PollQueueDone: timeout_sec %d", timeout_sec);
        do {
-               if (
-                          (status = AscExeScsiQueue(asc_dvc,
-                                                                                (ASC_SCSI_Q dosfar *) scsiq)) == 1
-                 ) {
+               ASC_DBG(1, "PollQueueDone: before AscExeScsiQueue\n");
+               if ((status = AscExeScsiQueue(asc_dvc,
+                               (ASC_SCSI_Q dosfar *) scsiq)) == 1) {
+                       ASC_DBG(1, "PollQueueDone: before AscPollQDone\n");
                        if ((status = AscPollQDone(asc_dvc, scsiq,
                                                                           timeout_sec)) != 1) {
                                if (status == 0x80) {
@@ -9461,9 +10049,13 @@ PollQueueDone(
                                scsiq->r3.scsi_msg = 0;
                                AscAbortSRB(asc_dvc, (ulong) scsiq);
                        }
+                       ASC_DBG1(1, "PollQueueDone: done_stat %x\n", scsiq->r3.done_stat);
                        return (scsiq->r3.done_stat);
                }
-       } while ((status == 0) || (status == 0x80));
+               DvcSleepMilliSecond(5);
+       } while (((status == 0) || (status == 0x80)) &&
+                         retry++ < ASC_MAX_INIT_BUSY_RETRY);
+       ASC_DBG(1, "PollQueueDone: done_stat QD_WITH_ERROR\n");
        return (scsiq->r3.done_stat = QD_WITH_ERROR);
 }
 
@@ -9481,7 +10073,6 @@ PollScsiInquiry(
        return (PollQueueDone(asc_dvc, (ASC_SCSI_REQ_Q dosfar *) scsiq, 4));
 }
 
-#if CC_INIT_TARGET_START_UNIT
 int
 PollScsiStartUnit(
                                         REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
@@ -9493,9 +10084,7 @@ PollScsiStartUnit(
        }
        return (PollQueueDone(asc_dvc, (ASC_SCSI_REQ_Q dosfar *) scsiq, 40));
 }
-#endif
 
-#if CC_INIT_TARGET_READ_CAPACITY
 int
 PollScsiReadCapacity(
                                                REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
@@ -9522,7 +10111,6 @@ PollScsiReadCapacity(
        }
        return (scsiq->r3.done_stat = QD_WITH_ERROR);
 }
-#endif
 
 ulong dosfar       *
 swapfarbuf4(
@@ -9542,7 +10130,6 @@ swapfarbuf4(
        return ((ulong dosfar *) buf);
 }
 
-#if CC_INIT_TARGET_TEST_UNIT_READY
 int
 PollScsiTestUnitReady(
                                                 REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
@@ -9603,7 +10190,6 @@ InitTestUnitReady(
        }
        return (0);
 }
-#endif
 
 int
 AscPollQDone(
@@ -9866,7 +10452,6 @@ AscScsiInquiry(
        return (0);
 }
 
-#if CC_INIT_TARGET_READ_CAPACITY
 int
 AscScsiReadCapacity(
                                           REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
@@ -9890,9 +10475,7 @@ AscScsiReadCapacity(
        scsiq->r2.cdb_len = 10;
        return (0);
 }
-#endif
 
-#if CC_INIT_TARGET_TEST_UNIT_READY
 int
 AscScsiTestUnitReady(
                                                REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
@@ -9913,9 +10496,7 @@ AscScsiTestUnitReady(
        scsiq->r2.cdb_len = 6;
        return (0);
 }
-#endif
 
-#if CC_INIT_TARGET_START_UNIT
 int
 AscScsiStartStopUnit(
                                                REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
@@ -9936,4 +10517,3 @@ AscScsiStartStopUnit(
        scsiq->r2.cdb_len = 6;
        return (0);
 }
-#endif
index 29fea2c522e1251009c03cb74906370ac7168ff1..4683ea293adc36d8b5a1cf4d249f46fff2033704 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: advansys.h,v 1.11 1996/08/12 17:20:44 bobf Exp bobf $ */
+/* $Id: advansys.h,v 1.12 1996/09/23 18:12:02 bobf Exp bobf $ */
 /*
  * advansys.h - Linux Host Driver for AdvanSys SCSI Adapters
  *
@@ -85,10 +85,12 @@ void advansys_setup(char *, int *);
        1,                                              /* unsigned unchecked_isa_dma:1 */ \
        /* \
         * All adapters controlled by this driver are capable of large \
-        * scatter-gather lists. This apparently obviates any performance
-        * gain provided by setting 'use_clustering'. \
+        * scatter-gather lists. According to the mid-level SCSI documentation \
+        * this obviates any performance gain provided by setting \
+        * 'use_clustering'. But empirically while CPU utilization is increased \
+        * by enabling clustering, I/O throughput increases as well. \
         */ \
-       DISABLE_CLUSTERING,             /* unsigned use_clustering:1 */ \
+       ENABLE_CLUSTERING,              /* unsigned use_clustering:1 */ \
 }
 #else /* version >= v1.3.0 */
 #define ADVANSYS { \
@@ -126,10 +128,12 @@ void advansys_setup(char *, int *);
        1,                                              /* unsigned unchecked_isa_dma:1 */ \
        /* \
         * All adapters controlled by this driver are capable of large \
-        * scatter-gather lists. This apparently obviates any performance
-        * gain provided by setting 'use_clustering'. \
+        * scatter-gather lists. According to the mid-level SCSI documentation \
+        * this obviates any performance gain provided by setting \
+        * 'use_clustering'. But empirically while CPU utilization is increased \
+        * by enabling clustering, I/O throughput increases as well. \
         */ \
-       DISABLE_CLUSTERING,             /* unsigned use_clustering:1 */ \
+       ENABLE_CLUSTERING,              /* unsigned use_clustering:1 */ \
 }
 #endif /* version >= v1.3.0 */
 #endif /* _ADVANSYS_H */
index a125f089a2c3d8fd3c87de05d4049618165a3a33..68ab0dd1fe192ac93b87c83780dad00e0f62db70 100644 (file)
@@ -547,7 +547,7 @@ static void ncr53c8xx_timeout(unsigned long np);
 #define INB_OFF(o)         IOM_INB_OFF(o)
 #define INW(r)             IOM_INW(r)
 #define INL(r)             IOM_INL(r)
-#define INL_OFF(r)         IOM_INL_OFF(o)
+#define INL_OFF(o)         IOM_INL_OFF(o)
 
 #define OUTB(r, val)       IOM_OUTB(r, val)
 #define OUTW(r, val)       IOM_OUTW(r, val)
@@ -3587,7 +3587,7 @@ printf("%s: cache misconfigured, retrying with IO mapped at 0x%lx\n",
 #   ifdef SCSI_NCR_SHARE_IRQ
        printf("%s: requesting shared irq %d (dev_id=0x%lx)\n",
                ncr_name(np), irq, (u_long) np);
-       if (request_irq(irq, ncr53c8xx_intr, SA_SHIRQ, "53c8xx", np)) {
+       if (request_irq(irq, ncr53c8xx_intr, SA_INTERRUPT|SA_SHIRQ, "53c8xx", np)) {
 #   else
        if (request_irq(irq, ncr53c8xx_intr, SA_INTERRUPT, "53c8xx", NULL)) {
 #   endif
@@ -4789,6 +4789,11 @@ void ncr_init (ncb_p np, char * msg, u_long code)
        */
        ncr_wakeup (np, code);
 
+       /*
+       **      Remove Reset, abort ...
+       */
+       OUTB (nc_istat,  0      );
+
        /*
        **      Init chip.
        */
@@ -4838,8 +4843,6 @@ void ncr_init (ncb_p np, char * msg, u_long code)
        burstlen = 0xc0;
 #endif
 
-       OUTB (nc_istat,  0      );      /*  Remove Reset, abort ...          */
-
 #ifdef SCSI_NCR_DISABLE_PARITY_CHECK
        OUTB (nc_scntl0, 0xc0   );      /*  full arb., (no parity)           */
 #else
@@ -7636,7 +7639,6 @@ printk("ncr53c8xx : interrupt received\n");
 #if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,70)
 #   ifdef SCSI_NCR_SHARE_IRQ
                if (dev_id == &host_data->ncb_data)
-                   ncr_intr(&host_data->ncb_data);
 #   endif
 #endif
               ncr_intr(&host_data->ncb_data);
index fc70b86888dadcb179c6a3c0d076ea358d2b18c7..affc819bebe8e259a1bb5f4874de2151fa20baea 100644 (file)
@@ -282,6 +282,7 @@ static struct dev_info device_list[] =
 {"PIONEER","CD-ROM DRM-604X","*", BLIST_FORCELUN | BLIST_SINGLELUN},
 {"EMULEX","MD21/S2     ESDI","*", BLIST_SINGLELUN},
 {"CANON","IPUBJD","*", BLIST_SPARSELUN},
+{"MATSHITA","PD","*", BLIST_FORCELUN | BLIST_SINGLELUN},
 /*
  * Must be at end of list...
  */
index dcd5ffffcf6900804ba14dc3373a41c7a80d063f..66476fc007c84e42453c5257ff13b16e6cd72b6e 100644 (file)
@@ -11,7 +11,7 @@
   Copyright 1992 - 1996 Kai Makisara
                 email Kai.Makisara@metla.fi
 
-  Last modified: Sun Jul  7 10:08:46 1996 by root@kai.makisara.fi
+  Last modified: Tue Oct  1 22:53:51 1996 by makisara@kai.makisara.fi
   Some small formal changes - aeb, 950809
 */
 
@@ -2192,7 +2192,8 @@ get_location(struct inode * inode, unsigned int *block, int *partition,
       return (-EBUSY);
 
     if ((STp->buffer)->last_result_fatal != 0 ||
-       ((STp->buffer)->b_data[0] & 4)) {
+       (STp->device->scsi_level >= SCSI_2 &&
+        ((STp->buffer)->b_data[0] & 4) != 0)) {
       *block = *partition = 0;
 #if DEBUG
       if (debugging)
index d6ce3262d89dc9e7d0b5940acd6d41b2c03cac20..62027a4ca65962670b6cd3a122326efc78aebb42 100644 (file)
@@ -403,7 +403,7 @@ audio_ioctl (int dev, struct fileinfo *file,
 
       case SNDCTL_DSP_GETOSPACE:
        if (!(audio_devs[dev]->open_mode & OPEN_WRITE))
-         return 0;
+         return -EPERM;
        if ((audio_mode[dev] & AM_READ) && !(audio_devs[dev]->flags & DMA_DUPLEX))
          return -(EBUSY);
 
@@ -418,7 +418,7 @@ audio_ioctl (int dev, struct fileinfo *file,
            return err;
 
          if (DMAbuf_get_curr_buffer (dev, &buf_no, &dma_buf, &buf_ptr, &buf_size) >= 0)
-           info.bytes += buf_size - buf_ptr;
+           info.bytes -= buf_ptr;
 
          memcpy_tofs (&((char *) arg)[0], (char *) &info, sizeof (info));
          return 0;
index af7378c27294f2059b4aa9ae27565c3dfac2469e..2a64fd8d2b24fbd6f1ae58c8a529b3cf14f6d2ab 100644 (file)
@@ -735,11 +735,13 @@ ask_parameters (void)
    * IRQ and DMA settings
    */
 
+#if 0  /* Disable this broken question. */
   ask_int_choice (B (OPT_AEDSP16), "AEDSP16_BASE",
                  "I/O base for Audio Excel DSP 16",
                  FMT_HEX,
                  0x220,
                  "220 or 240");
+#endif
 
   ask_int_choice (B (OPT_SB), "SBC_BASE",
                  "I/O base for SB",
index b83513410b26ca03adf306157e1fb91a382de165..611c41da86002a60a3ce807365d0d877e07a118d 100644 (file)
 #define ICMP_HOST_ANO          10
 #define ICMP_NET_UNR_TOS       11
 #define ICMP_HOST_UNR_TOS      12
+#define ICMP_PKT_FILTERED      13      /* Packet filtered */
+#define ICMP_PREC_VIOLATION    14      /* Precedence violation */
+#define ICMP_PREC_CUTOFF       15      /* Precedence cut off */
+#define NR_ICMP_UNREACH        15        /* instead of hardcoding immediate value */
 
 /* Codes for REDIRECT. */
 #define ICMP_REDIR_NET         0       /* Redirect Net                 */
index 5e5459164386a00bf74f8d15753645da4ae36d70..8922277d623b13a0fdf7d66fb5545c9251e43852 100644 (file)
@@ -98,6 +98,7 @@ extern void wd7000_setup(char *str, int *ints);
 extern void ppa_setup(char *str, int *ints);
 extern void scsi_luns_setup(char *str, int *ints);
 extern void sound_setup(char *str, int *ints);
+extern void reboot_setup(char *str, int *ints);
 #ifdef CONFIG_CDU31A
 extern void cdu31a_setup(char *str, int *ints);
 #endif CONFIG_CDU31A
@@ -268,6 +269,7 @@ struct {
 #ifdef CONFIG_BUGi386
        { "no-hlt", no_halt },
        { "no387", no_387 },
+       { "reboot=", reboot_setup },
 #endif
 #ifdef CONFIG_INET
        { "ether=", eth_setup },
index 52e434285f5785d0ee06f636384648aa7d0af97d..540162e3c88135843f31259b6e5ba19046fc86f7 100644 (file)
@@ -100,12 +100,12 @@ static inline int dup_mmap(struct mm_struct * mm)
                        mpnt->vm_next_share = tmp;
                        tmp->vm_prev_share = mpnt;
                }
-               if (tmp->vm_ops && tmp->vm_ops->open)
-                       tmp->vm_ops->open(tmp);
                if (copy_page_range(mm, current->mm, tmp)) {
                        exit_mmap(mm);
                        return -ENOMEM;
                }
+               if (tmp->vm_ops && tmp->vm_ops->open)
+                       tmp->vm_ops->open(tmp);
                *p = tmp;
                p = &tmp->vm_next;
        }
index 47150376aa59797dcd864cfe71050d82effb179c..60ef256b3b2975b2e971ad982b815d2884989ce3 100644 (file)
@@ -1137,7 +1137,6 @@ int br_receive_frame(struct sk_buff *skb) /* 3.5 */
                                                /* happen in net_bh() in dev.c) */
                        }
                        /* ok, forward this frame... */
-                       skb_device_lock(skb);
                        return(br_forward(skb, port));
                default:
                        printk(KERN_DEBUG "br_receive_frame: port [%i] unknown state [%i]\n",
index 1737b366173ee6061960fded70361f00bcc61ba4..b21d84b4e34a183d16765c332ea742d4befd3a93 100644 (file)
@@ -1984,13 +1984,14 @@ static int arp_req_set(struct arpreq *r, struct device * dev)
        {
                if (!mask && ip)
                        return -EINVAL;
-               if (!dev)
+               if (!dev) {
                        dev = dev_getbytype(r->arp_ha.sa_family);
+                       if (!dev)
+                               return -ENODEV;
+               }
        }
        else
        {
-               if (ip_chk_addr(ip) && dev->type != ARPHRD_METRICOM)
-                       return -EINVAL;
                if (!dev)
                {
                        struct rtable * rt;
@@ -1999,9 +2000,13 @@ static int arp_req_set(struct arpreq *r, struct device * dev)
                                return -ENETUNREACH;
                        dev = rt->rt_dev;
                        ip_rt_put(rt);
+                       if (!dev)
+                               return -ENODEV;
                }
+               if (dev->type != ARPHRD_METRICOM && ip_chk_addr(ip))
+                       return -EINVAL;
        }
-       if (!dev || (dev->flags&(IFF_LOOPBACK|IFF_NOARP)))
+       if (dev->flags & (IFF_LOOPBACK | IFF_NOARP))
                return -ENODEV;
 
        if (r->arp_ha.sa_family != dev->type)   
index e6cd8fad3b7929e086869926c22d0e9270940a5e..e5c3a7fb0ddffc1c07f750346ec0d37679cc9e0f 100644 (file)
@@ -36,6 +36,8 @@
  *     Willy Konynenberg       :       Transparent proxying support.
  *             Keith Owens     :       RFC1191 correction for 4.2BSD based 
  *                                     path MTU bug.
+ *             Thomas Quinot   :       ICMP Dest Unreach codes up to 15 are
+ *                                     valid (RFC 1812).
  *
  *
  * RFC1122 (Host Requirements -- Comm. Layer) Status:
@@ -281,7 +283,10 @@ struct icmp_err icmp_err_convert[] = {
   { ENETUNREACH,       1 },    /*      ICMP_NET_ANO            */
   { EHOSTUNREACH,      1 },    /*      ICMP_HOST_ANO           */
   { EOPNOTSUPP,                0 },    /*      ICMP_NET_UNR_TOS        */
-  { EOPNOTSUPP,                0 }     /*      ICMP_HOST_UNR_TOS       */
+  { EOPNOTSUPP,                0 },    /*      ICMP_HOST_UNR_TOS       */
+  { EOPNOTSUPP,                1 },    /*      ICMP_PKT_FILTERED       */
+  { EOPNOTSUPP,                1 },    /*      ICMP_PREC_VIOLATION     */
+  { EOPNOTSUPP,                1 }     /*      ICMP_PREC_CUTOFF        */
 };
 
 /*
@@ -732,7 +737,7 @@ static void icmp_unreach(struct icmphdr *icmph, struct sk_buff *skb, struct devi
                        default:
                                break;
                }
-               if(icmph->code>12)      /* Invalid type */
+               if(icmph->code>NR_ICMP_UNREACH) /* Invalid type */
                        return;
        }
        
index f76a72a760dddaa91bbeb1c1f9aaf5af7b3dea0f..402237f7f9a2ac852a83926a327caf0bfd3c2afc 100644 (file)
@@ -100,7 +100,7 @@ void raw_err (int type, int code, unsigned char *header, __u32 daddr,
                sk->error_report(sk);
        }
 
-       if(code<13)
+       if(code<=NR_ICMP_UNREACH)
        {
                sk->err = icmp_err_convert[code & 0xff].errno;
                sk->error_report(sk);
index ee26b4bd62df732155595a4b5495d5ba7bcb1964..393d0241c8fa7780cf936c5c14ab5c3dd49b0c8f 100644 (file)
@@ -573,7 +573,7 @@ void tcp_err(int type, int code, unsigned char *header, __u32 daddr,
         * until we time out, or the user gives up.
         */
 
-       if (code < 13)
+       if(code<=NR_ICMP_UNREACH)
        {
                if(icmp_err_convert[code].fatal || sk->state == TCP_SYN_SENT || sk->state == TCP_SYN_RECV)
                {
index 478baa87333170ddf8e0d806fc5484b857a3553c..07e2a4a77222f09235ab132c183196ed36f84cc9 100644 (file)
@@ -193,7 +193,7 @@ void udp_err(int type, int code, unsigned char *header, __u32 daddr,
        /* 4.1.3.3. */
        /* After the comment above, that should be no surprise. */
 
-       if (code < 13 && icmp_err_convert[code].fatal)
+       if(code<=NR_ICMP_UNREACH && icmp_err_convert[code].fatal)
        {
                /*
                 *      4.x BSD compatibility item. Break RFC1122 to
index ea0bda9c82ca31a660d2ca7916aab63ee72fcaa9..37cf7acb575c7624deb5f6adfda0bb183969c9d3 100644 (file)
@@ -931,9 +931,9 @@ static int unix_sendmsg(struct socket *sock, struct msghdr *msg, int len, int no
                 *      have suggested. Big mallocs stress the vm too
                 *      much.
                 */
-
-               if(size > 4000 && sock->type!=SOCK_DGRAM)
-                       limit = 4000;   /* Fall back to 4K if we can't grab a big buffer this instant */
+#define MAX_ALLOC (PAGE_SIZE*7/8)
+               if(size > MAX_ALLOC && sock->type!=SOCK_DGRAM)
+                       limit = MAX_ALLOC;      /* Fall back to 4K if we can't grab a big buffer this instant */
                else
                        limit = 0;      /* Otherwise just grab and wait */
 
index c8f513b264d4325ba004e0ecb8247757d143ec0f..fc2608113cb1fbc183af069fa62e06f824da3839 100644 (file)
@@ -57,25 +57,29 @@ static void handle_config(void)
 #endif
 
 #ifdef LE_MACHINE
-#define first_byte(x) current = (unsigned char) x; x >>= 8;
+#define next_byte(x) (x >>= 8)
+#define current ((unsigned char) __buf)
 #else
-#define first_byte(x) current = x >> 8*(sizeof(unsigned long)-1); x <<= 8;
+#define next_byte(x) (x <<= 8)
+#define current (__buf >> 8*(sizeof(unsigned long)-1))
 #endif
 
 #define GETNEXT { \
-if (!__buf) { \
+next_byte(__buf); \
+if (!__nrbuf) { \
        __buf = *(unsigned long *) next; \
+       __nrbuf = sizeof(unsigned long); \
        if (!__buf) \
                break; \
-} first_byte(__buf); next++; }
+} next++; __nrbuf--; }
 #define CASE(c,label) if (current == c) goto label
 #define NOTCASE(c,label) if (current != c) goto label
 
-static void state_machine(char *next)
+static void state_machine(register char *next)
 {
        for(;;) {
-       unsigned long __buf = 0;
-       unsigned char current;
+       register unsigned long __buf = 0;
+       register unsigned long __nrbuf = 0;
 
 normal:
        GETNEXT
@@ -181,19 +185,33 @@ if_line:
        if (needsconfig)
                goto skippreproc;
 if_start:
-       if (!memcmp("CONFIG_", next, 7)) {
-               handle_config();
-               goto skippreproc;
-       }
        GETNEXT
+       CASE('C', config);
        CASE('\n', normal);
        CASE('_', if_middle);
        if (current >= 'a' && current <= 'z')
                goto if_middle;
        if (current < 'A' || current > 'Z')
                goto if_start;
+config:
+       GETNEXT
+       NOTCASE('O', __if_middle);
+       GETNEXT
+       NOTCASE('N', __if_middle);
+       GETNEXT
+       NOTCASE('F', __if_middle);
+       GETNEXT
+       NOTCASE('I', __if_middle);
+       GETNEXT
+       NOTCASE('G', __if_middle);
+       GETNEXT
+       NOTCASE('_', __if_middle);
+       handle_config();
+       goto skippreproc;
+
 if_middle:
        GETNEXT
+__if_middle:
        CASE('\n', normal);
        CASE('_', if_middle);
        if (current >= 'a' && current <= 'z')