diff -u --recursive --new-file v2.0.21/linux/CREDITS linux/CREDITS --- v2.0.21/linux/CREDITS Fri Sep 20 17:00:33 1996 +++ linux/CREDITS Mon Oct 7 07:45:08 1996 @@ -1088,13 +1088,12 @@ 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 diff -u --recursive --new-file v2.0.21/linux/Documentation/Configure.help linux/Documentation/Configure.help --- v2.0.21/linux/Documentation/Configure.help Sun Sep 15 10:34:18 1996 +++ linux/Documentation/Configure.help Sat Oct 5 12:13:56 1996 @@ -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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 -u --recursive --new-file v2.0.21/linux/Documentation/IO-mapping.txt linux/Documentation/IO-mapping.txt --- v2.0.21/linux/Documentation/IO-mapping.txt Thu Jan 1 02:00:00 1970 +++ linux/Documentation/IO-mapping.txt Mon Sep 30 17:05:45 1996 @@ -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 + + 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 + diff -u --recursive --new-file v2.0.21/linux/Documentation/cdrom/ide-cd linux/Documentation/cdrom/ide-cd --- v2.0.21/linux/Documentation/cdrom/ide-cd Fri Sep 20 17:00:33 1996 +++ linux/Documentation/cdrom/ide-cd Wed Sep 25 11:12:11 1996 @@ -352,6 +352,14 @@ 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 ----------- diff -u --recursive --new-file v2.0.21/linux/Documentation/ide.txt linux/Documentation/ide.txt --- v2.0.21/linux/Documentation/ide.txt Sat Aug 10 10:03:14 1996 +++ linux/Documentation/ide.txt Wed Sep 25 11:12:11 1996 @@ -255,6 +255,8 @@ 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, diff -u --recursive --new-file v2.0.21/linux/Makefile linux/Makefile --- v2.0.21/linux/Makefile Fri Sep 20 17:00:33 1996 +++ linux/Makefile Mon Sep 30 17:09:31 1996 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 0 -SUBLEVEL = 21 +SUBLEVEL = 22 ARCH = i386 diff -u --recursive --new-file v2.0.21/linux/arch/i386/kernel/process.c linux/arch/i386/kernel/process.c --- v2.0.21/linux/arch/i386/kernel/process.c Wed Sep 11 17:57:13 1996 +++ linux/arch/i386/kernel/process.c Sun Sep 22 10:07:45 1996 @@ -182,6 +182,17 @@ * 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 @@ 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(); diff -u --recursive --new-file v2.0.21/linux/arch/i386/kernel/traps.c linux/arch/i386/kernel/traps.c --- v2.0.21/linux/arch/i386/kernel/traps.c Mon Aug 5 10:13:50 1996 +++ linux/arch/i386/kernel/traps.c Sat Oct 5 14:25:51 1996 @@ -173,12 +173,8 @@ 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) { diff -u --recursive --new-file v2.0.21/linux/arch/i386/math-emu/fpu_emu.h linux/arch/i386/math-emu/fpu_emu.h --- v2.0.21/linux/arch/i386/math-emu/fpu_emu.h Thu May 9 07:59:33 1996 +++ linux/arch/i386/math-emu/fpu_emu.h Sun Sep 22 10:13:54 1996 @@ -97,9 +97,9 @@ 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; diff -u --recursive --new-file v2.0.21/linux/drivers/block/floppy.c linux/drivers/block/floppy.c --- v2.0.21/linux/drivers/block/floppy.c Mon Sep 2 15:18:25 1996 +++ linux/drivers/block/floppy.c Tue Sep 24 14:12:40 1996 @@ -2087,7 +2087,7 @@ /* determine interleave */ il = 1; - if (_floppy->sect > DP->interleave_sect && F_SIZECODE == 2) + if (_floppy->fmt_gap < 0x22) il++; /* initialize field */ diff -u --recursive --new-file v2.0.21/linux/drivers/block/ide-tape.c linux/drivers/block/ide-tape.c --- v2.0.21/linux/drivers/block/ide-tape.c Wed Sep 11 17:57:13 1996 +++ linux/drivers/block/ide-tape.c Fri Sep 27 08:27:37 1996 @@ -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 * @@ -187,6 +187,8 @@ * 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 @@ { 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 @@ * 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 @@ 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; } diff -u --recursive --new-file v2.0.21/linux/drivers/block/ide-tape.h linux/drivers/block/ide-tape.h --- v2.0.21/linux/drivers/block/ide-tape.h Wed Sep 11 17:57:13 1996 +++ linux/drivers/block/ide-tape.h Fri Sep 27 08:27:37 1996 @@ -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 */ @@ -232,6 +232,15 @@ */ #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. diff -u --recursive --new-file v2.0.21/linux/drivers/block/ide.c linux/drivers/block/ide.c --- v2.0.21/linux/drivers/block/ide.c Sat Aug 17 21:19:26 1996 +++ linux/drivers/block/ide.c Fri Sep 27 08:27:37 1996 @@ -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) */ @@ -259,6 +259,8 @@ * 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 @@ } 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 @@ } 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 @@ 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 @@ 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 @@ for (p = 0; p < (1<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 @@ */ 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; @@ -2894,6 +2918,9 @@ goto done; 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; diff -u --recursive --new-file v2.0.21/linux/drivers/block/ide.h linux/drivers/block/ide.h --- v2.0.21/linux/drivers/block/ide.h Sat Aug 10 10:03:14 1996 +++ linux/drivers/block/ide.h Tue Oct 8 19:44:21 1996 @@ -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 @@ 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 */ diff -u --recursive --new-file v2.0.21/linux/drivers/block/triton.c linux/drivers/block/triton.c --- v2.0.21/linux/drivers/block/triton.c Wed Sep 11 17:57:14 1996 +++ linux/drivers/block/triton.c Sun Sep 22 09:54:08 1996 @@ -128,7 +128,8 @@ */ 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 diff -u --recursive --new-file v2.0.21/linux/drivers/char/cyclades.c linux/drivers/char/cyclades.c --- v2.0.21/linux/drivers/char/cyclades.c Mon Aug 5 10:13:51 1996 +++ linux/drivers/char/cyclades.c Tue Oct 8 08:03:17 1996 @@ -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 @@ * 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 ) + * + * 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 + * * Revision 1.36.3.7 1996/04/19 21:06:18 bentson * remove unneeded boot message & fix CLOCAL hardware flow * control (Miquel van Smoorenburg ); @@ -2355,6 +2363,7 @@ /* If the TTY is being hung up, nothing to do */ if (tty_hung_up_p(filp)) { + MOD_DEC_USE_COUNT; restore_flags(flags); return; } diff -u --recursive --new-file v2.0.21/linux/drivers/char/pcxx.c linux/drivers/char/pcxx.c --- v2.0.21/linux/drivers/char/pcxx.c Mon Aug 5 10:13:51 1996 +++ linux/drivers/char/pcxx.c Sat Oct 5 09:46:20 1996 @@ -1120,10 +1120,12 @@ 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); diff -u --recursive --new-file v2.0.21/linux/drivers/char/pty.c linux/drivers/char/pty.c --- v2.0.21/linux/drivers/char/pty.c Wed Jul 17 15:10:03 1996 +++ linux/drivers/char/pty.c Mon Sep 30 16:56:48 1996 @@ -181,66 +181,41 @@ 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; } diff -u --recursive --new-file v2.0.21/linux/drivers/net/eql.c linux/drivers/net/eql.c --- v2.0.21/linux/drivers/net/eql.c Mon May 6 12:26:08 1996 +++ linux/drivers/net/eql.c Sun Sep 22 21:17:08 1996 @@ -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 @@ 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; diff -u --recursive --new-file v2.0.21/linux/drivers/net/ne.c linux/drivers/net/ne.c --- v2.0.21/linux/drivers/net/ne.c Tue May 28 07:39:18 1996 +++ linux/drivers/net/ne.c Mon Oct 7 20:27:46 1996 @@ -299,14 +299,21 @@ 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 { diff -u --recursive --new-file v2.0.21/linux/drivers/scsi/advansys.c linux/drivers/scsi/advansys.c --- v2.0.21/linux/drivers/scsi/advansys.c Sat Aug 17 21:19:27 1996 +++ linux/drivers/scsi/advansys.c Fri Sep 27 07:52:29 1996 @@ -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 */ /* @@ -28,14 +28,15 @@ 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) @@ -56,8 +57,10 @@ 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) @@ -72,17 +76,18 @@ 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. @@ -148,11 +153,13 @@ '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. @@ -212,7 +219,21 @@ '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'. @@ -251,7 +272,7 @@ --- 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 @@ -299,7 +320,7 @@ 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. @@ -315,7 +336,7 @@ 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 @@ -346,7 +367,7 @@ 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 @@ -389,7 +410,7 @@ 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. @@ -403,15 +424,28 @@ 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 provided the directions and basis for the Linux v1.3.X changes which were included in the @@ -420,7 +454,7 @@ Thomas E Zerucha 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 @@ -505,8 +539,8 @@ */ #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 @@ #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 @@ #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 @@ #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 @@ #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 @@ #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 @@ #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 @@ #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 @@ 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 @@ #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 @@ #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 @@ #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 @@ #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 @@ 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 @@ 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 @@ * 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 @@ * 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 @@ 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 @@ 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 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 @@ 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 @@ 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 @@ 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 @@ * 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ #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 @@ 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", 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 @@ 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 @@ 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 @@ 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 @@ } 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 @@ 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 @@ 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 @@ 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, 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. @@ -3617,85 +3869,192 @@ #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 @@ * 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, 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 @@ */ 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 @@ 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) { @@ -3918,6 +4304,27 @@ } /* + * 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'. * * The function 'done' is called when the request has been completed. @@ -3952,20 +4359,21 @@ * 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 @@ 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_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 @@ 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 @@ * 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 @@ 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 @@ 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_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 @@ 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 @@ 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_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_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_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_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 @@ 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,30 +5211,103 @@ { 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 * device if no more commands are left queued for it. @@ -4837,34 +5320,61 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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; @@ -5069,6 +5584,70 @@ } /* + * 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() * * Print dynamic board configuration information. @@ -5082,7 +5661,7 @@ 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_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 @@ 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 @@ 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 @@ } /* - * 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 @@ 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_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_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 @@ 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 @@ 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 @@ } #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 @@ 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 @@ 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 @@ ((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 @@ 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 @@ ) { 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 @@ 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 @@ ((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 @@ 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 @@ 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 @@ } 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 @@ 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 @@ 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 @@ 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 @@ (*asc_isr_callback) (asc_dvc, scsi_done_q); } } + ASC_DBG(1, "AscInitPollIsrCallBack: end\n"); return; } @@ -9316,6 +9914,7 @@ 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 @@ 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 @@ } } 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 @@ } } } -#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 @@ ) { 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 @@ 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 @@ 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 @@ } 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 @@ } return (scsiq->r3.done_stat = QD_WITH_ERROR); } -#endif ulong dosfar * swapfarbuf4( @@ -9542,7 +10130,6 @@ 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 @@ } return (0); } -#endif int AscPollQDone( @@ -9866,7 +10452,6 @@ return (0); } -#if CC_INIT_TARGET_READ_CAPACITY int AscScsiReadCapacity( REG ASC_DVC_VAR asc_ptr_type * asc_dvc, @@ -9890,9 +10475,7 @@ 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 @@ 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 @@ scsiq->r2.cdb_len = 6; return (0); } -#endif diff -u --recursive --new-file v2.0.21/linux/drivers/scsi/advansys.h linux/drivers/scsi/advansys.h --- v2.0.21/linux/drivers/scsi/advansys.h Sat Aug 17 21:19:27 1996 +++ linux/drivers/scsi/advansys.h Fri Sep 27 07:52:29 1996 @@ -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 @@ 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 @@ 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 */ diff -u --recursive --new-file v2.0.21/linux/drivers/scsi/ncr53c8xx.c linux/drivers/scsi/ncr53c8xx.c --- v2.0.21/linux/drivers/scsi/ncr53c8xx.c Sun Sep 8 19:50:21 1996 +++ linux/drivers/scsi/ncr53c8xx.c Mon Sep 30 08:53:59 1996 @@ -547,7 +547,7 @@ #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 @@ # 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 @@ -4790,6 +4790,11 @@ ncr_wakeup (np, code); /* + ** Remove Reset, abort ... + */ + OUTB (nc_istat, 0 ); + + /* ** Init chip. */ /** NCR53C810 **/ @@ -4838,8 +4843,6 @@ 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 @@ #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); diff -u --recursive --new-file v2.0.21/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c --- v2.0.21/linux/drivers/scsi/scsi.c Fri Sep 20 17:00:34 1996 +++ linux/drivers/scsi/scsi.c Sat Oct 5 12:17:45 1996 @@ -282,6 +282,7 @@ {"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... */ diff -u --recursive --new-file v2.0.21/linux/drivers/scsi/st.c linux/drivers/scsi/st.c --- v2.0.21/linux/drivers/scsi/st.c Sat Aug 17 21:19:28 1996 +++ linux/drivers/scsi/st.c Wed Oct 2 14:03:30 1996 @@ -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 @@ 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) diff -u --recursive --new-file v2.0.21/linux/drivers/sound/audio.c linux/drivers/sound/audio.c --- v2.0.21/linux/drivers/sound/audio.c Wed Aug 21 09:18:09 1996 +++ linux/drivers/sound/audio.c Tue Oct 8 19:12:33 1996 @@ -403,7 +403,7 @@ 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 @@ 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; diff -u --recursive --new-file v2.0.21/linux/drivers/sound/configure.c linux/drivers/sound/configure.c --- v2.0.21/linux/drivers/sound/configure.c Sat Jul 20 08:56:20 1996 +++ linux/drivers/sound/configure.c Wed Sep 25 21:35:30 1996 @@ -735,11 +735,13 @@ * 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", diff -u --recursive --new-file v2.0.21/linux/include/linux/icmp.h linux/include/linux/icmp.h --- v2.0.21/linux/include/linux/icmp.h Wed Jul 12 06:41:59 1995 +++ linux/include/linux/icmp.h Sun Oct 6 17:42:09 1996 @@ -46,6 +46,10 @@ #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 */ diff -u --recursive --new-file v2.0.21/linux/init/main.c linux/init/main.c --- v2.0.21/linux/init/main.c Wed Sep 11 17:57:18 1996 +++ linux/init/main.c Sun Sep 22 10:07:09 1996 @@ -98,6 +98,7 @@ 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 @@ #ifdef CONFIG_BUGi386 { "no-hlt", no_halt }, { "no387", no_387 }, + { "reboot=", reboot_setup }, #endif #ifdef CONFIG_INET { "ether=", eth_setup }, diff -u --recursive --new-file v2.0.21/linux/kernel/fork.c linux/kernel/fork.c --- v2.0.21/linux/kernel/fork.c Sun Sep 1 09:15:34 1996 +++ linux/kernel/fork.c Mon Sep 23 10:57:30 1996 @@ -100,12 +100,12 @@ 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; } diff -u --recursive --new-file v2.0.21/linux/net/bridge/br.c linux/net/bridge/br.c --- v2.0.21/linux/net/bridge/br.c Fri Jul 19 08:24:05 1996 +++ linux/net/bridge/br.c Sat Sep 21 11:02:56 1996 @@ -1137,7 +1137,6 @@ /* 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", diff -u --recursive --new-file v2.0.21/linux/net/ipv4/arp.c linux/net/ipv4/arp.c --- v2.0.21/linux/net/ipv4/arp.c Mon Aug 5 10:13:55 1996 +++ linux/net/ipv4/arp.c Wed Oct 2 14:44:00 1996 @@ -1984,13 +1984,14 @@ { 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 @@ 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) diff -u --recursive --new-file v2.0.21/linux/net/ipv4/icmp.c linux/net/ipv4/icmp.c --- v2.0.21/linux/net/ipv4/icmp.c Sun Sep 8 19:50:22 1996 +++ linux/net/ipv4/icmp.c Sun Oct 6 17:42:09 1996 @@ -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 @@ { 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 @@ default: break; } - if(icmph->code>12) /* Invalid type */ + if(icmph->code>NR_ICMP_UNREACH) /* Invalid type */ return; } diff -u --recursive --new-file v2.0.21/linux/net/ipv4/raw.c linux/net/ipv4/raw.c --- v2.0.21/linux/net/ipv4/raw.c Sun Sep 8 19:50:22 1996 +++ linux/net/ipv4/raw.c Sun Oct 6 17:42:09 1996 @@ -100,7 +100,7 @@ sk->error_report(sk); } - if(code<13) + if(code<=NR_ICMP_UNREACH) { sk->err = icmp_err_convert[code & 0xff].errno; sk->error_report(sk); diff -u --recursive --new-file v2.0.21/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c --- v2.0.21/linux/net/ipv4/tcp.c Sun Sep 8 19:50:22 1996 +++ linux/net/ipv4/tcp.c Sun Oct 6 17:42:09 1996 @@ -573,7 +573,7 @@ * 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) { diff -u --recursive --new-file v2.0.21/linux/net/ipv4/udp.c linux/net/ipv4/udp.c --- v2.0.21/linux/net/ipv4/udp.c Tue Jun 4 15:34:43 1996 +++ linux/net/ipv4/udp.c Sun Oct 6 17:42:09 1996 @@ -193,7 +193,7 @@ /* 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 diff -u --recursive --new-file v2.0.21/linux/net/unix/af_unix.c linux/net/unix/af_unix.c --- v2.0.21/linux/net/unix/af_unix.c Sun Sep 8 19:50:22 1996 +++ linux/net/unix/af_unix.c Sat Oct 5 16:50:45 1996 @@ -931,9 +931,9 @@ * 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 */ diff -u --recursive --new-file v2.0.21/linux/scripts/mkdep.c linux/scripts/mkdep.c --- v2.0.21/linux/scripts/mkdep.c Fri Sep 20 17:00:36 1996 +++ linux/scripts/mkdep.c Tue Oct 8 19:33:56 1996 @@ -57,25 +57,29 @@ #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 (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')