diff -u --recursive --new-file v2.1.80/linux/CREDITS linux/CREDITS --- v2.1.80/linux/CREDITS Tue Jan 20 16:44:57 1998 +++ linux/CREDITS Wed Jan 21 14:09:54 1998 @@ -465,11 +465,12 @@ S: Germany N: Jeremy Fitzhardinge -E: jeremy@sw.oz.au +E: jeremy@zip.com.au D: Improved mmap and munmap handling D: General mm minor tidyups -S: 99 Albermarle Street -S: Newtown 2042 +S: 67 Surrey St. +S: Darlinghurst, Sydney +S: NSW 2010 S: Australia N: Ralf Flaxa @@ -705,6 +706,7 @@ N: Ron Holt E: ron@caldera.com W: http://www.holt.org/ +P: 1024/1FD44539 DF 4B EB 9F 5B 68 38 9A 40 E3 FB 71 D1 C8 0B 56 D: Kernel development D: Minor kernel modifications to support Wabi and Wine S: Caldera, Inc. @@ -820,9 +822,11 @@ N: Ian Kluft E: ikluft@thunder.sbay.org -D: Smail binary packages for Slackware and Debian -S: 2200 Monroe Street #1509 -S: Santa Clara, California 95050-3452 +W: http://www.kluft.com/~ikluft/ +D: NET-1 beta testing & minor patches, original Smail binary packages for +D: Slackware and Debian, vote-taker for 2nd comp.os.linux reorganization +S: PO Box 611311 +S: San Jose, CA 95161-1311 S: USA N: Alain L. Knaff @@ -977,6 +981,14 @@ S: Nepean, Ontario S: Canada K2H 6S3 +N: Jamie Lokier +E: jamie@imbolc.ucc.ie +D: Reboot-through-BIOS for broken 486 motherboards +S: 26 Oatlands Road +S: Oxford +S: OX2 0ET +S: United Kingdom + N: Warner Losh E: imp@village.org D: Linux/MIPS Deskstation support, Provided OI/OB for Linux @@ -1146,6 +1158,7 @@ N: Rick Miller E: rdmiller@execpc.com +W: http://www.execpc.com/~rdmiller/ D: Original Linux Device Registrar (Major/minor numbers) D: au-play, bwBASIC S: S78 W16203 Woods Road @@ -1309,8 +1322,12 @@ D: Some PCI kernel support N: Stefan Probst -E: snprobst@immd4.informatik.uni-erlangen.de -D: The Linux Support Team Erlangen +E: sp@caldera.de +D: The Linux Support Team Erlangen, 1993-97 +S: Caldera (Deutschland) GmbH +S: Lazarettstrasse 8 +S: 91054 Erlangen +S: Germany N: Daniel Quinlan E: quinlan@pathname.com @@ -1651,6 +1668,14 @@ S: Obere Heerbergstrasse 17 S: 97078 Wuerzburg S: Germany + +N: Greg Ungerer +E: gerg@stallion.com +D: Author of Stallion multiport serial drivers +S: Stallion Technologies +S: 33 Woodstock Rd +S: Toowong, QLD. 4066 +S: Australia N: Jeffrey A. Uphoff E: juphoff@nrao.edu diff -u --recursive --new-file v2.1.80/linux/Documentation/00-INDEX linux/Documentation/00-INDEX --- v2.1.80/linux/Documentation/00-INDEX Sun Dec 28 12:05:44 1997 +++ linux/Documentation/00-INDEX Wed Jan 21 17:51:11 1998 @@ -80,6 +80,8 @@ - notes on how to use the Real Time Clock (aka CMOS clock) driver. scsi.txt - short blurb on using SCSI support as a module. +smart-config.txt + - description of the Smart Config makefile feature. smp.tex - TeX document describing implementation of Multiprocessor Linux svga.txt diff -u --recursive --new-file v2.1.80/linux/Documentation/binfmt_misc.txt linux/Documentation/binfmt_misc.txt --- v2.1.80/linux/Documentation/binfmt_misc.txt Sun Aug 31 09:40:01 1997 +++ linux/Documentation/binfmt_misc.txt Fri Jan 23 16:40:13 1998 @@ -54,10 +54,10 @@ - enable support for packed DOS applications (pre-configured dosemu hdimages): echo ':DEXE:M::\x0eDEX::/usr/bin/dosexec:' > register -- enable support for DOS/Windows executables (using mzloader and dosemu/wine): - echo ':DOSWin:M::MZ::/usr/sbin/mzloader:' > register - echo ':DOScom:E::com::/usr/sbin/mzloader:' > register - echo ':DOSexe:E::exe::/usr/sbin/mzloader:' > register +- enable support for Windows executables using wine: + echo ':DOSWin:M::MZ::/usr/local/bin/wine:' > register + +For java support see Documentation/java.txt You can enable/disable binfmt_misc or one binary type by echoing 0 (to disable) @@ -68,73 +68,12 @@ or /proc/sys/fs/binfmt_misc/status. -Emulating binfmt_java: -====================== - -To emulate binfmt_java the following register-strings could be used: -for compiled Java programs use - ':Java:M::\xca\xfe\xba\xbe::/usr/local/java/bin/javawrapper:' -for simple applet support use - ':Applet:E::html::/usr/local/java/bin/appletviewer:' -for more selective applet support (like binfmt_java) use - ':Applet:M:: in the first line to -let this work! - -For the compiled Java programs you need a wrapper script like the -following (this is because Java is broken in case of the filename -handling): - -====================== Cut here =================== -#!/bin/bash -# /usr/local/java/bin/javawrapper - the wrapper for binfmt_misc/java -CLASS=$1 - -# if classname is a link, we follow it (this could be done easier - how?) -if [ -L "$1" ] ; then - CLASS=`ls --color=no -l $1 | tr -s '\t ' ' ' | cut -d ' ' -f 11` -fi -CLASSN=`basename $CLASS .class` -CLASSP=`dirname $CLASS` - -FOO=$PATH -PATH=$CLASSPATH -if [ -z "`type -p -a $CLASSN.class`" ] ; then - # class is not in CLASSPATH - if [ -e "$CLASSP/$CLASSN.class" ] ; then - # append dir of class to CLASSPATH - if [ -z "${CLASSPATH}" ] ; then - export CLASSPATH=$CLASSP - else - export CLASSPATH=$CLASSP:$CLASSPATH - fi - else - # uh! now we would have to create a symbolic link - really - # ugly, i.e. print a message that one has to change the setup - echo "Hey! This is not a good setup to run $1 !" - exit 1 - fi -fi -PATH=$FOO - -shift -/usr/local/java/bin/java $CLASSN $@ -====================== Cut here =================== - -To add a Java program to your path best put a symbolic link to the main -.class file into /usr/bin (or another place you like) omitting the .class -extension. The directory containing the original .class file will be -added to your CLASSPATH during execution. - - - HINTS: ====== If you want to pass special arguments to your interpreter, you can -write a wrapper script for it. +write a wrapper script for it. See Documentation/java.txt for an +example. Your interpreter should NOT look in the PATH for the filename; the kernel passes it the full filename to use. Using the PATH can cause diff -u --recursive --new-file v2.1.80/linux/Documentation/filesystems/smbfs.txt linux/Documentation/filesystems/smbfs.txt --- v2.1.80/linux/Documentation/filesystems/smbfs.txt Mon Nov 24 10:30:40 1997 +++ linux/Documentation/filesystems/smbfs.txt Wed Jan 21 10:09:31 1998 @@ -1,27 +1,20 @@ Smbfs is a filesystem that implements the SMB protocol, which is the protocol used by Windows for Workgroups, Windows 95 and Windows NT. -Smbfs was inspired by samba, the program written by Andrew Tridgell +Smbfs was inspired by Samba, the program written by Andrew Tridgell that turns any unix host into a file server for DOS or Windows clients. See ftp://nimbus.anu.edu.au/pub/tridge/samba/ for this interesting program suite and much more information on SMB, NetBIOS over TCP/IP, and explanations for concepts like netbios name or share. -To use smbfs, you need to install the Samba package (Samba-1.9.17p1 or -later), and you need the special mount program from the smbfs package -(smbfs-2.1.0 or later), found on - - ftp://ftp.gwdg.de/pub/linux/misc/smbfs/dontuse - -After downloading the smbfs package, apply the patch to the smbclient -program and recompile. Smbfs can then be mounted from the smbclient -command line, as for example: - - smb: \>mount /mnt/tmp -f 755 - -For convenience, you may wish to package the command in a script like this: - -#!/bin/sh -echo "mount /mnt/tmp -f 755" | smbclient //server/c$ -U administrator% +To use smbfs, you must first install the Samba package (Samba-1.9.18p1 or +later). This package includes the special smbmount utility needed to mount +smbfs volumes. Refer to the smbmount(8) and smbmnt(8) manpages for the +details regarding smbfs mounts. + +The smbmount utility reads the Samba smb.conf config file for some of its +options, and at least one of these is important for smbfs operation. You +should enable the TCP_NODELAY socket option, or else directory listings +will be dramatically slower (under Win NT at least). Mount-Time Options Windows 95 has several bugs that affect SMB operations, and smbfs includes @@ -37,11 +30,12 @@ Option Value Effect Identify Win 95 Server 1 Enables bug fixes Use Core Attributes 2 Speeds up directory scans, only mtime +Use Dir Attributes 4 Alternate way to get file attributes To apply the options, sum the values and prepend it to the file mode. For -example, to use both options with file mode 755, you would prepend 3 to 755: +example, to use options 1 and 2 with file mode 755, you would specify 3755: - cnt>mount /mnt/tmp -f 3755 + mount /mnt/tmp -f 3755 Smbfs will print a message at mount time confirming the selected options. Note that _only_ Windows 95 servers require special treatment; using the diff -u --recursive --new-file v2.1.80/linux/Documentation/java.txt linux/Documentation/java.txt --- v2.1.80/linux/Documentation/java.txt Thu Nov 21 01:00:33 1996 +++ linux/Documentation/java.txt Fri Jan 23 16:40:13 1998 @@ -4,45 +4,92 @@ Linux beats them ALL! While all other OS's are TALKING about direct support of Java Binaries in the OS, Linux is doing it! -You execute Java classes as you would any other executable, after a few -small details: +You can execute Java applications and Java Applets just like any +other program after you have done the following: + +1) You MUST FIRST install the Java Developers Kit for Linux. + The Java on Linux HOWTO gives the details on getting and + installing this. This HOWTO can be found at: + + ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO/Java-HOWTO + + You should also set up a reasonable CLASSPATH environment + variable to use Java applications that make use of any + nonstandard classes (not included in the same directory + as the application itself). + +2) You have to compile BINFMT_MISC either as module or into + the kernel (CONFIG_BINFMT_MISC) and set it up properly. + If you choose to compile it as a module, you will have + to insert it manually with modprobe/insmod, as kerneld + can not easy be supported with binfmt_misc. + Read the file 'binfmt_misc.txt' in this directory to know + more about the configuration process. + +3) Add the following configuration items to binfmt_misc + (you should really have read binfmt_misc.txt now): + support for Java applications: + ':Java:M::\xca\xfe\xba\xbe::/usr/local/java/bin/javawrapper:' + support for Java Applets: + ':Applet:E::html::/usr/local/java/bin/appletviewer:' + or the following, if you want to be more selective: + ':Applet:M:: in the first line + ('<' has to be the first character!) to let this work! + + For the compiled Java programs you need a wrapper script like the + following (this is because Java is broken in case of the filename + handling), again fix the path names, both in the script and in the + above given configuration string: + +====================== Cut here =================== +#!/bin/bash +# /usr/local/java/bin/javawrapper - the wrapper for binfmt_misc/java +CLASS=$1 + +# if classname is a link, we follow it (this could be done easier - how?) +if [ -L "$1" ] ; then + CLASS=`ls --color=no -l $1 | tr -s '\t ' ' ' | cut -d ' ' -f 11` +fi +CLASSN=`basename $CLASS .class` +CLASSP=`dirname $CLASS` + +FOO=$PATH +PATH=$CLASSPATH +if [ -z "`type -p -a $CLASSN.class`" ] ; then + # class is not in CLASSPATH + if [ -e "$CLASSP/$CLASSN.class" ] ; then + # append dir of class to CLASSPATH + if [ -z "${CLASSPATH}" ] ; then + export CLASSPATH=$CLASSP + else + export CLASSPATH=$CLASSP:$CLASSPATH + fi + else + # uh! now we would have to create a symbolic link - really + # ugly, i.e. print a message that one has to change the setup + echo "Hey! This is not a good setup to run $1 !" + exit 1 + fi +fi +PATH=$FOO + +shift +/usr/local/java/bin/java $CLASSN "$@" +====================== Cut here =================== + + +Now simply chmod +x the .class and/or .html files you want to execute. +To add a Java program to your path best put a symbolic link to the main +.class file into /usr/bin (or another place you like) omitting the .class +extension. The directory containing the original .class file will be +added to your CLASSPATH during execution. - 1) You MUST FIRST install the Java Developers Kit for Linux. - The Java on Linux HOWTO gives the details on getting and - installing this. This HOWTO can be found at: - - ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO/Java-HOWTO - - If you install the JDK in a location other than /usr/bin/java, - then you will need to tell the kernel where you put the Java - interpreter. - There are two ways to do this. - One, edit fs/binfmt_java.c file and make the needed change to - the _PATH_JAVA definition at the top of that file. - Two, as root, issue the command: - echo "/path/to/java/interpreter" > /proc/sys/kernel/java-interpreter - (Currently, this does not work if you're using a module for - Java support.) - - 2) You must chmod the '*.class' files you wish to execute with - the execute bit. This is not normally (till now) done with - '.class' files. - - 3) You must optionally export a CLASSPATH environment variable, - if you plan to use Java applications installed outside of - /usr/local/java/classes/*. - - 4) Either compile your kernel with Java support builtin, or - as a loadable module. If a module, load it with insmod or - kerneld. - - 5) A caveat. When executing a java file, the java interpreter is - invoked only with the class name, not with the complete file path. - Therefore it is possible that the file the shell finds with PATH - is not the same file the java interpreter finds with CLASSPATH. - The recommended solution is to make symbolic links from a directory - in PATH to the actual class file in CLASSPATH, e.g., - /usr/local/bin/myapp -> /usr/local/java/classes/myapp.class. To test your new setup, enter in the following simple Java app, and name it "HelloWorld.java": @@ -53,59 +100,20 @@ } } - Now compile the application with: - - /usr/local/java/bin/javac HelloWorld.java + javac HelloWorld.java Set the executable permissions of the binary file, with: - chmod 755 HelloWorld.class And then execute it: - ./HelloWorld.class -Yes, it's JUST THAT EASY! ;-) - ------------------------------------------------------------------ - -Nope, I didn't forget about Java Applets! ;-) - -While this may not be the best way to do this, it works! - -Take any html file used with the Java appletviewer (like the -demo/Blink/example1.html file), and: - - 1) Insert a new first line of: - - - - Make sure the '<' is the first character in the file. This - will be treated as a valid HTML comment outside of this - Java Applet support, so the modified file can still be used - with all known browsers. - - 2) If you install the applet viewer in a location other than - /usr/bin/appletviewer, then you will need to tell the - kernel where you put the Java appletviewer. - There are two ways to do this. - One, edit fs/binfmt_java.c file and make the needed change to - the _PATH_APPLET definition at the top of that file. - Two, as root, issue the command: - echo "/path/to/java/appletviewer" > /proc/sys/kernel/java-appletviewer - (Currently, this does not work if you're using a module for - Java support.) - - 3) You must chmod the '*.html' files you wish to execute with - the execute bit. This is not normally (till now) done with - '.html' files. - - 4) And then execute it. - +To execute Java Applets, simple chmod the *.html files to include +the execution bit, then just do + ./Applet.html -Brian A. Lantz -brian@lantz.com -(/proc/sys/kernel/java-* support by Mike Shaver (shaver@ingenia.com)) +originally by Brian A. Lantz, brian@lantz.com +heavily edited for binfmt_misc by Richard Günther. diff -u --recursive --new-file v2.1.80/linux/Documentation/smart-config.txt linux/Documentation/smart-config.txt --- v2.1.80/linux/Documentation/smart-config.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/smart-config.txt Wed Jan 21 17:51:11 1998 @@ -0,0 +1,103 @@ +Smart CONFIG_* Dependencies +Fri 2 Dec 1997 + +Michael Chastain +Werner Almesberger +Martin von Loewis + +Here is the problem: + + Suppose that drivers/net/foo.c has the following lines: + + #include + + ... + + #ifdef CONFIG_FOO_AUTOFROB + /* Code for auto-frobbing */ + #else + /* Manual frobbing only */ + #endif + + ... + + #ifdef CONFIG_FOO_MODEL_TWO + /* Code for model two */ + #endif + + Now suppose the user (the person building kernels) reconfigures the + kernel to change some unrelated setting. This will regenerate the + file include/linux/autoconf.h, which will cause include/linux/config.h + to be out of date, which will cause drivers/net/foo.c to be recompiled. + + Most kernel sources, perhaps 80% of them, have at least one CONFIG_* + dependency somewhere. So changing _any_ CONFIG_* setting requires + almost _all_ of the kernel to be recompiled. + +Here is the solution: + + We've made the dependency generator, mkdep.c, smarter. Instead of + generating this dependency: + + drivers/net/foo.c: include/linux/config.h + + It now generates these dependencies: + + drivers/net/foo.c: \ + include/config/foo_autofrob.h \ + include/config/foo_model_two.h + + So drivers/net/foo.c depends only on the CONFIG_* lines that + it actually uses. + + A new program, split-include.c, runs at the end of make config (also + make oldconfig, make menuconfig, and make xconfig). split-include + reads include/linux/autoconf.h and updates the include/linux/*.h + directory, writing one file per option. It updates only the files + that changed. + + mkdep.c also generates much better warning messages for missing + or unneeded lines. In fact, you can get these + messages without generating dependencies with the new top-level + target 'make checkconfig'. + +Flag Dependencies + + Martin Von Loewis contributed another feature to this patch: + 'flag dependencies'. The idea is that a .o file depends on + the compilation flags used to build it. The file foo.o has + its flags stored in .flags.foo.o. + + Suppose the user changes the foo driver from resident to + modular, 'make' will notice that the foo.o was not compiled + with -DMODULE and will recompile foo.c. + + Flag dependencies also work with per-source-file flags such + as those in drivers/net/CONFIG. + + All .a and .o files made from C source or with 'ld' or 'ar' + have flag dependencies. .S files do not have flag dependencies. + +Per-source-file Flags + + You can specify compilation flags for individual source files + like this: + + CFLAGS_foo.o = -DSPECIAL_FOO_DEFINE + + This helps clean up drivers/net/Makefile, drivers/scsi/Makefile, + and several other Makefiles. + +Credit + + Werner Almesberger had the original idea and wrote the first + version of this patch. + + Michael Chastain picked it up and continued development. He is + now the principal author and maintainer. Report bugs to him, + or to all three people together. + + Martin von Loewis wrote flag dependencies, with some modifications + by Michael Chastain. + + Thanks to all of the beta testers. diff -u --recursive --new-file v2.1.80/linux/Makefile linux/Makefile --- v2.1.80/linux/Makefile Wed Jan 14 11:25:15 1998 +++ linux/Makefile Fri Jan 23 16:36:22 1998 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 1 -SUBLEVEL = 80 +SUBLEVEL = 81 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/) @@ -343,14 +343,16 @@ clean: archclean rm -f kernel/ksyms.lst include/linux/compile.h - rm -f `find . -name '*.[oas]' ! -regex '.*lxdialog/.*' -print` - rm -f `find . -type f -name 'core' -print` - rm -f `find . -name '.*.flags' -print` + rm -f core `find . -name '*.[oas]' ! -regex '.*lxdialog/.*' -print` + rm -f core `find . -type f -name 'core' -print` + rm -f core `find . -name '.*.flags' -print` rm -f vmlinux System.map rm -f .tmp* rm -f drivers/char/consolemap_deftbl.c drivers/char/conmakehash rm -f drivers/sound/bin2hex drivers/sound/hex2hex - rm -f `find modules/ -type f -print` + if [ -d modules ]; then \ + rm -f core `find modules/ -type f -print`; \ + fi rm -f submenu* mrproper: clean @@ -368,6 +370,7 @@ rm -f include/asm rm -rf include/config rm -f .depend `find . -name .depend -print` + rm -f core `find . -size 0 -print` rm -f .hdepend scripts/mkdep scripts/split-include rm -f $(TOPDIR)/include/linux/modversions.h rm -rf $(TOPDIR)/include/linux/modules diff -u --recursive --new-file v2.1.80/linux/arch/alpha/kernel/irq.c linux/arch/alpha/kernel/irq.c --- v2.1.80/linux/arch/alpha/kernel/irq.c Mon Jan 12 14:51:14 1998 +++ linux/arch/alpha/kernel/irq.c Wed Jan 21 17:46:00 1998 @@ -373,7 +373,7 @@ if (!action) continue; len += sprintf(buf+len, "%2d: %10u %c %s", - i, kstat.interrupts[i], + i, kstat.interrupts[0][i], (action->flags & SA_INTERRUPT) ? '+' : ' ', action->name); for (action=action->next; action; action = action->next) { @@ -567,7 +567,7 @@ int cpu = smp_processor_id(); irq_enter(cpu, irq); - kstat.interrupts[irq]++; + kstat.interrupts[0][irq] += 1; if (!action) { unexpected_irq(irq, regs); } else { @@ -590,7 +590,7 @@ } irq_enter(cpu, irq); - kstat.interrupts[irq]++; + kstat.interrupts[0][irq] += 1; action = irq_action[irq]; /* * For normal interrupts, we mask it out, and then ACK it. @@ -1050,7 +1050,6 @@ */ int probe_irq_off(unsigned long irqs) { - unsigned long delay; int i; irqs &= irq_mask; diff -u --recursive --new-file v2.1.80/linux/arch/alpha/lib/csum_partial_copy.c linux/arch/alpha/lib/csum_partial_copy.c --- v2.1.80/linux/arch/alpha/lib/csum_partial_copy.c Sun Nov 30 10:59:02 1997 +++ linux/arch/alpha/lib/csum_partial_copy.c Wed Jan 21 17:46:00 1998 @@ -112,7 +112,7 @@ * easy. */ static inline unsigned long -csum_partial_cfu_dest_aligned(unsigned long *src, unsigned long *dst, +csum_partial_cfu_dest_aligned(const unsigned long *src, unsigned long *dst, unsigned long soff, long len, unsigned long checksum, int *errp) diff -u --recursive --new-file v2.1.80/linux/arch/i386/kernel/entry.S linux/arch/i386/kernel/entry.S --- v2.1.80/linux/arch/i386/kernel/entry.S Sat Jan 10 11:57:29 1998 +++ linux/arch/i386/kernel/entry.S Fri Jan 23 16:23:44 1998 @@ -532,7 +532,8 @@ .long SYMBOL_NAME(sys_rt_sigsuspend) .long SYMBOL_NAME(sys_pread) /* 180 */ .long SYMBOL_NAME(sys_pwrite) + .long SYMBOL_NAME(sys_lchown); - .rept NR_syscalls-181 + .rept NR_syscalls-182 .long SYMBOL_NAME(sys_ni_syscall) .endr diff -u --recursive --new-file v2.1.80/linux/arch/i386/kernel/i386_ksyms.c linux/arch/i386/kernel/i386_ksyms.c --- v2.1.80/linux/arch/i386/kernel/i386_ksyms.c Sat Jan 10 18:04:59 1998 +++ linux/arch/i386/kernel/i386_ksyms.c Fri Jan 23 11:21:28 1998 @@ -39,7 +39,7 @@ EXPORT_SYMBOL_NOVERS(__down_failed); EXPORT_SYMBOL_NOVERS(__down_failed_interruptible); EXPORT_SYMBOL_NOVERS(__up_wakeup); -EXPORT_SYMBOL(__intel_bh_counter); +EXPORT_SYMBOL(global_bh_lock); /* Networking helper routines. */ EXPORT_SYMBOL(csum_partial_copy); /* Delay loops */ diff -u --recursive --new-file v2.1.80/linux/arch/i386/kernel/irq.c linux/arch/i386/kernel/irq.c --- v2.1.80/linux/arch/i386/kernel/irq.c Tue Jan 20 14:20:55 1998 +++ linux/arch/i386/kernel/irq.c Fri Jan 23 17:29:49 1998 @@ -68,12 +68,8 @@ # define SYNC_OTHER_CORES(x) __asm__ __volatile__ ("nop") #endif +unsigned int local_bh_count[NR_CPUS]; unsigned int local_irq_count[NR_CPUS]; -#ifdef __SMP__ -atomic_t __intel_bh_counter; -#else -int __intel_bh_counter; -#endif atomic_t nmi_counter; @@ -120,69 +116,31 @@ #ifndef __SMP__ static const unsigned int io_apic_irqs = 0; #else - /* - * the timer interrupt is not connected to the IO-APIC on all boards - * (mine is such ;), and since it is not performance critical anyway, - * we route it through the INTA pin and win lots of design simplicity. - * Ditto the obsolete EISA dma chaining irq. All other interrupts are - * routed through the IO-APIC, distributed amongst all CPUs, dependent - * on irq traffic and CPU load. - */ - const unsigned int io_apic_irqs = ~((1<<0)|(1<<2)|(1<<13)); + /* + * Default to all normal IRQ's _not_ using the IO APIC. + * + * To get IO-APIC interrupts you should either: + * - turn some of them into IO-APIC interrupts at runtime + * with some magic system call interface. + * - explicitly use irq 16-19 depending on which PCI irq + * line your PCI controller uses. + */ + unsigned int io_apic_irqs = 0xff0000; #endif -static inline int ack_irq(int irq) +static inline void mask_8259A(int irq) { - /* - * The IO-APIC part will be moved to assembly, nested - * interrupts will be ~5 instructions from entry to iret ... - */ - int should_handle_irq = 0; - int cpu = smp_processor_id(); - - /* - * We always call this with local irqs disabled - */ - spin_lock(&irq_controller_lock); - - if (!irq_events[irq]++ && !disabled_irq[irq]) { - should_handle_irq = 1; -#ifdef __SMP__ - irq_owner[irq] = cpu; -#endif - hardirq_enter(cpu); - } - - if (IO_APIC_IRQ(irq)) - ack_APIC_irq (); - else { - /* - * 8259-triggered INTA-cycle interrupt - */ - if (should_handle_irq) - mask_irq(irq); - - if (irq & 8) { - inb(0xA1); /* DUMMY */ - outb(0x62,0x20); /* Specific EOI to cascade */ - outb(0x20,0xA0); - } else { - inb(0x21); /* DUMMY */ - outb(0x20,0x20); - } + cached_irq_mask |= 1 << irq; + if (irq & 8) { + outb(cached_A1,0xA1); + } else { + outb(cached_21,0x21); } - - spin_unlock(&irq_controller_lock); - - return (should_handle_irq); } -void set_8259A_irq_mask(int irq) +static inline void unmask_8259A(int irq) { - if (irq >= 16) { - printk ("HUH #3 (%d)?\n", irq); - return; - } + cached_irq_mask &= ~(1 << irq); if (irq & 8) { outb(cached_A1,0xA1); } else { @@ -190,6 +148,21 @@ } } +void set_8259A_irq_mask(int irq) +{ + /* + * (it might happen that we see IRQ>15 on a UP box, with SMP + * emulation) + */ + if (irq < 16) { + if (irq & 8) { + outb(cached_A1,0xA1); + } else { + outb(cached_21,0x21); + } + } +} + /* * These have to be protected by the spinlock * before being called. @@ -356,12 +329,13 @@ continue; p += sprintf(p, "%3d: ",i); #ifndef __SMP__ - p += sprintf(p, "%10u ", kstat.interrupts[0][i]); + p += sprintf(p, "%10u ", kstat_irqs(i)); #else for (j=0; j (unsigned long) &init_task_union && x < (unsigned long) &vsprintf) { + printk("<[%08lx]> ", x); + } + } +} + + +#define MAXCOUNT 100000000 + +static inline void wait_on_bh(void) { - int local_count = local_irq_count[cpu]; + int count = MAXCOUNT; + do { + if (!--count) { + show("wait_on_bh"); + count = ~0; + } + /* nothing .. wait for the other bh's to go away */ + } while (atomic_read(&global_bh_count) != 0); +} + +static inline void wait_on_irq(int cpu) +{ + int count = MAXCOUNT; + + while (atomic_read(&global_irq_count)) { + clear_bit(0,&global_irq_lock); - /* Are we the only one in an interrupt context? */ - while (local_count != atomic_read(&global_irq_count)) { - /* - * No such luck. Now we need to release the lock, - * _and_ release our interrupt context, because - * otherwise we'd have dead-locks and live-locks - * and other fun things. - */ - atomic_sub(local_count, &global_irq_count); - global_irq_holder = NO_PROC_ID; - global_irq_lock = 0; - - /* - * Wait for everybody else to go away and release - * their things before trying to get the lock again. - */ for (;;) { - atomic_add(local_count, &global_irq_count); + if (!--count) { + show("wait_on_irq"); + count = ~0; + } __sti(); SYNC_OTHER_CORES(cpu); __cli(); - atomic_sub(local_count, &global_irq_count); - SYNC_OTHER_CORES(cpu); check_smp_invalidate(cpu); if (atomic_read(&global_irq_count)) continue; @@ -445,8 +440,24 @@ if (!test_and_set_bit(0,&global_irq_lock)) break; } - atomic_add(local_count, &global_irq_count); - global_irq_holder = cpu; + } +} + +/* + * This is called when we want to synchronize with + * bottom half handlers. We need to wait until + * no other CPU is executing any bottom half handler. + * + * Don't wait if we're already running in an interrupt + * context or are inside a bh handler. + */ +void synchronize_bh(void) +{ + if (atomic_read(&global_bh_count)) { + int cpu = smp_processor_id(); + if (!local_irq_count[cpu] && !local_bh_count[cpu]) { + wait_on_bh(); + } } } @@ -456,37 +467,15 @@ * stop sending interrupts: but to make sure there * are no interrupts that are executing on another * CPU we need to call this function. - * - * We have to give pending interrupts a chance to - * arrive (ie. let them get until hard_irq_enter()), - * even if they are arriving to another CPU. - * - * On UP this is a no-op. - * - * UPDATE: this method is not quite safe, as it wont - * catch irq handlers polling for the irq lock bit - * in __global_cli():get_interrupt_lock():wait_on_irq(). - * drivers should rather use disable_irq()/enable_irq() - * and/or synchronize_one_irq() */ void synchronize_irq(void) { - int local_count = local_irq_count[smp_processor_id()]; - - if (local_count != atomic_read(&global_irq_count)) { - int i; - - /* The very stupid way to do this */ - for (i=0; iflags & SA_INTERRUPT)) __sti(); -#endif do { status |= action->flags; @@ -616,23 +571,7 @@ __cli(); } - spin_lock(&irq_controller_lock); - -#ifdef __SMP__ - release_irqlock(cpu); -#endif - - if ((--irq_events[irq]) && (!disabled_irq[irq])) { - spin_unlock(&irq_controller_lock); - goto again; - } -#ifdef __SMP__ - /* FIXME: move this into hardirq.h */ - irq_owner[irq] = NO_PROC_ID; -#endif - hardirq_exit(cpu); - - spin_unlock(&irq_controller_lock); + return status; } @@ -642,94 +581,103 @@ */ void disable_irq(unsigned int irq) { -#ifdef __SMP__ - int cpu = smp_processor_id(); -#endif - unsigned long f, flags; - - save_flags(flags); - __save_flags(f); - __cli(); - spin_lock(&irq_controller_lock); + unsigned long flags; + spin_lock_irqsave(&irq_controller_lock, flags); disabled_irq[irq]++; + mask_irq(irq); + spin_unlock_irqrestore(&irq_controller_lock, flags); -#ifdef __SMP__ - /* - * We have to wait for all irq handlers belonging to this IRQ - * vector to finish executing. - */ - if ((irq_owner[irq] == NO_PROC_ID) || (irq_owner[irq] == cpu) || - (disabled_irq[irq] > 1)) { - - spin_unlock(&irq_controller_lock); - __restore_flags(f); - restore_flags(flags); - if (disabled_irq[irq] > 100) - printk("disable_irq(%d), infinit recursion!\n",irq); - return; - } -#endif - - spin_unlock(&irq_controller_lock); - -#ifdef __SMP__ - synchronize_one_irq(irq); -#endif - - __restore_flags(f); - restore_flags(flags); + synchronize_irq(); } void enable_irq(unsigned int irq) { unsigned long flags; - int cpu = smp_processor_id(); - spin_lock_irqsave(&irq_controller_lock,flags); + spin_lock_irqsave(&irq_controller_lock, flags); + disabled_irq[irq]--; + unmask_irq(irq); + spin_unlock_irqrestore(&irq_controller_lock, flags); +} - if (!disabled_irq[irq]) { - spin_unlock_irqrestore(&irq_controller_lock,flags); - printk("more enable_irq(%d)'s than disable_irq(%d)'s!!",irq,irq); - return; +/* + * Careful! The 8259A is a fragile beast, it pretty + * much _has_ to be done exactly like this (mask it + * first, _then_ send the EOI, and the order of EOI + * to the two 8259s is important! + */ +static inline void mask_and_ack_8259A(int irq_nr) +{ + spin_lock(&irq_controller_lock); + cached_irq_mask |= 1 << irq_nr; + if (irq_nr & 8) { + inb(0xA1); /* DUMMY */ + outb(cached_A1,0xA1); + outb(0x62,0x20); /* Specific EOI to cascade */ + outb(0x20,0xA0); + } else { + inb(0x21); /* DUMMY */ + outb(cached_21,0x21); + outb(0x20,0x20); } + spin_unlock(&irq_controller_lock); +} - disabled_irq[irq]--; +static void do_8259A_IRQ(int irq, int cpu, struct pt_regs * regs) +{ + mask_and_ack_8259A(irq); -#ifndef __SMP__ - if (disabled_irq[irq]) { - spin_unlock_irqrestore(&irq_controller_lock,flags); - return; - } -#else - if (disabled_irq[irq] || (irq_owner[irq] != NO_PROC_ID)) { - spin_unlock_irqrestore(&irq_controller_lock,flags); - return; + irq_enter(cpu, irq); + + if (handle_IRQ_event(irq, regs)) { + spin_lock(&irq_controller_lock); + unmask_8259A(irq); + spin_unlock(&irq_controller_lock); } -#endif - /* - * Nobody is executing this irq handler currently, lets check - * wether we have outstanding events to be handled. - */ + irq_exit(cpu, irq); +} - if (irq_events[irq]) { - struct pt_regs regs; +/* + * FIXME! This is completely broken. + */ +static void do_ioapic_IRQ(int irq, int cpu, struct pt_regs * regs) +{ + int should_handle_irq; -#ifdef __SMP__ + spin_lock(&irq_controller_lock); + should_handle_irq = 0; + if (!irq_events[irq]++ && !disabled_irq[irq]) { + should_handle_irq = 1; irq_owner[irq] = cpu; -#endif hardirq_enter(cpu); -#ifdef __SMP__ - release_irqlock(cpu); -#endif - spin_unlock(&irq_controller_lock); + } + + ack_APIC_irq(); + + spin_unlock(&irq_controller_lock); + + if (should_handle_irq) { +again: + if (!handle_IRQ_event(irq, regs)) + disabled_irq[irq] = 1; - handle_IRQ_event(irq,®s); - __restore_flags(flags); - return; } - spin_unlock_irqrestore(&irq_controller_lock,flags); + + spin_lock(&irq_controller_lock); + release_irqlock(cpu); + + if ((--irq_events[irq]) && (!disabled_irq[irq]) && should_handle_irq) { + spin_unlock(&irq_controller_lock); + goto again; + } + + irq_owner[irq] = NO_PROC_ID; + hardirq_exit(cpu); + spin_unlock(&irq_controller_lock); + + enable_IO_APIC_irq(irq); } /* @@ -747,7 +695,9 @@ * overlapping ... i saw no driver problem so far. */ asmlinkage void do_IRQ(struct pt_regs regs) -{ +{ + void (*do_lowlevel_IRQ)(int, int, struct pt_regs *); + /* * We ack quickly, we don't want the irq controller * thinking we're snobs just because some other CPU has @@ -759,16 +709,15 @@ * handled by some other CPU. (or is disabled) */ int irq = regs.orig_eax & 0xff; + int cpu = smp_processor_id(); -/* - printk("<%d>",irq); - */ - if (!ack_irq(irq)) - return; - - handle_IRQ_event(irq,®s); + kstat.irqs[cpu][irq]++; - unmask_irq(irq); + do_lowlevel_IRQ = do_8259A_IRQ; + if (IO_APIC_IRQ(irq)) + do_lowlevel_IRQ = do_ioapic_IRQ; + + do_lowlevel_IRQ(irq, cpu, ®s); /* * This should be conditional: we should really get @@ -897,7 +846,7 @@ /* * save current irq counts */ - memcpy(probe_irqs,kstat.interrupts,NR_CPUS*NR_IRQS*sizeof(int)); + memcpy(probe_irqs,kstat.irqs,NR_CPUS*NR_IRQS*sizeof(int)); /* * first, enable any unassigned irqs @@ -922,7 +871,7 @@ */ for (i=0; i static inline void irq_enter(int cpu, int irq) { diff -u --recursive --new-file v2.1.80/linux/arch/i386/kernel/smp.c linux/arch/i386/kernel/smp.c --- v2.1.80/linux/arch/i386/kernel/smp.c Tue Jan 20 12:52:09 1998 +++ linux/arch/i386/kernel/smp.c Wed Jan 21 12:04:45 1998 @@ -115,7 +115,7 @@ int smp_num_cpus = 1; /* Total count of live CPU's */ int smp_threads_ready=0; /* Set when the idlers are all forked */ volatile int cpu_number_map[NR_CPUS]; /* which CPU maps to which logical number */ -volatile int cpu_logical_map[NR_CPUS]; /* which logical number maps to which CPU */ +volatile int __cpu_logical_map[NR_CPUS]; /* which logical number maps to which CPU */ volatile unsigned long cpu_callin_map[NR_CPUS] = {0,}; /* We always use 0 the rest is ready for parallel delivery */ volatile unsigned long smp_invalidate_needed; /* Used for the invalidate map that's also checked in the spinlock */ volatile unsigned long kstack_ptr; /* Stack vector for booting CPU's */ @@ -526,7 +526,7 @@ * set some other information about it. */ nlong = boot_cpu_id<<24; /* Dummy 'self' for bootup */ - cpu_logical_map[0] = boot_cpu_id; + __cpu_logical_map[0] = boot_cpu_id; global_irq_holder = boot_cpu_id; current->processor = boot_cpu_id; @@ -717,7 +717,7 @@ panic("No idle process for CPU %d", i); idle->processor = i; - cpu_logical_map[cpucount] = i; + __cpu_logical_map[cpucount] = i; cpu_number_map[i] = cpucount; /* start_eip had better be page-aligned! */ @@ -861,7 +861,7 @@ /* number CPUs logically, starting from 1 (BSP is 0) */ #if 0 cpu_number_map[i] = cpucount; - cpu_logical_map[cpucount] = i; + __cpu_logical_map[cpucount] = i; #endif printk("OK.\n"); printk("CPU%d: ", i); @@ -927,6 +927,7 @@ if (!smp_found_config) { printk(KERN_NOTICE "SMP motherboard not detected. Using dummy APIC emulation.\n"); + io_apic_irqs = 0; return; } @@ -1087,6 +1088,12 @@ if(smp_b_stepping) printk(KERN_WARNING "WARNING: SMP operation may be unreliable with B stepping processors.\n"); SMP_PRINTK(("Boot done.\n")); + + /* + * Here we can be sure that there is an IO-APIC in the system, lets + * go and set it up: + */ + setup_IO_APIC(); } /* diff -u --recursive --new-file v2.1.80/linux/arch/i386/lib/usercopy.c linux/arch/i386/lib/usercopy.c --- v2.1.80/linux/arch/i386/lib/usercopy.c Sat Jan 10 21:28:41 1998 +++ linux/arch/i386/lib/usercopy.c Fri Jan 23 16:34:36 1998 @@ -89,7 +89,7 @@ " .long 0b,3b\n" \ " .long 1b,2b\n" \ ".previous" \ - : "=c"(size) \ + : "=&c"(size) \ : "r"(size & 3), "0"(size / 4), "D"(addr), "a"(0) \ : "di") diff -u --recursive --new-file v2.1.80/linux/drivers/block/floppy.c linux/drivers/block/floppy.c --- v2.1.80/linux/drivers/block/floppy.c Mon Jan 12 14:57:50 1998 +++ linux/drivers/block/floppy.c Fri Jan 23 11:07:07 1998 @@ -1710,10 +1710,11 @@ } while ((ST0 & 0x83) != UNIT(current_drive) && inr == 2); } if (handler) { - if(softirq_trylock()) { + int cpu = smp_processor_id(); + if(softirq_trylock(cpu)) { /* got the lock, call the handler immediately */ handler(); - softirq_endlock(); + softirq_endlock(cpu); } else /* we interrupted a bottom half. Defer handler */ schedule_bh( (void *)(void *) handler); diff -u --recursive --new-file v2.1.80/linux/drivers/block/genhd.c linux/drivers/block/genhd.c --- v2.1.80/linux/drivers/block/genhd.c Sun Jan 4 10:40:15 1998 +++ linux/drivers/block/genhd.c Fri Jan 23 17:38:04 1998 @@ -776,7 +776,9 @@ int blk, blocks_in_map; int dev_bsize, dev_pos, pos; unsigned secsize; +#ifdef CONFIG_PMAC int first_bootable = 1; +#endif struct mac_partition *part; struct mac_driver_desc *md; diff -u --recursive --new-file v2.1.80/linux/drivers/block/md.c linux/drivers/block/md.c --- v2.1.80/linux/drivers/block/md.c Thu Jan 15 14:33:05 1998 +++ linux/drivers/block/md.c Fri Jan 23 17:38:04 1998 @@ -493,7 +493,7 @@ /* * ioctl : one open channel */ - printk ("STOP_MD md%x failed : i_count=%ld, busy=%d\n", + printk ("STOP_MD md%x failed : i_count=%d, busy=%d\n", minor, inode->i_count, md_dev[minor].busy); return -EBUSY; } @@ -846,6 +846,7 @@ static struct proc_dir_entry proc_md = { PROC_MD, 6, "mdstat", S_IFREG | S_IRUGO, 1, 0, 0, + 0, &proc_array_inode_operations, }; static void md_geninit (struct gendisk *gdisk) diff -u --recursive --new-file v2.1.80/linux/drivers/block/ps2esdi.c linux/drivers/block/ps2esdi.c --- v2.1.80/linux/drivers/block/ps2esdi.c Tue May 13 22:41:05 1997 +++ linux/drivers/block/ps2esdi.c Fri Jan 23 17:38:04 1998 @@ -1038,14 +1038,9 @@ } - static int ps2esdi_open(struct inode *inode, struct file *file) { - int dev = DEVICE_NR(MINOR(inode->i_rdev)); - -#if 0 - printk("%s: dev= %d\n", DEVICE_NAME, dev); -#endif + int dev = DEVICE_NR(inode->i_rdev); if (dev < ps2esdi_drives) { while (!ps2esdi_valid[dev]) @@ -1062,7 +1057,7 @@ static int ps2esdi_release(struct inode *inode, struct file *file) { - int dev = DEVICE_NR(MINOR(inode->i_rdev)); + int dev = DEVICE_NR(inode->i_rdev); if (dev < ps2esdi_drives) { sync_dev(dev); @@ -1078,7 +1073,7 @@ { struct ps2esdi_geometry *geometry = (struct ps2esdi_geometry *) arg; - int dev = DEVICE_NR(MINOR(inode->i_rdev)), err; + int dev = DEVICE_NR(inode->i_rdev), err; if (inode && (dev < ps2esdi_drives)) switch (cmd) { @@ -1133,7 +1128,7 @@ static int ps2esdi_reread_partitions(int dev) { - int target = DEVICE_NR(MINOR(dev)); + int target = DEVICE_NR(dev); int start = target << ps2esdi_gendisk.minor_shift; int partition; @@ -1145,15 +1140,20 @@ for (partition = ps2esdi_gendisk.max_p - 1; partition >= 0; partition--) { - sync_dev(MAJOR_NR << 8 | start | partition); - invalidate_inodes(MAJOR_NR << 8 | start | partition); - invalidate_buffers(MAJOR_NR << 8 | start | partition); + int minor = (start | partition); + kdev_t devp = MKDEV(MAJOR_NR, minor); + struct super_block * sb = get_super(devp); + + sync_dev(devp); + if (sb) + invalidate_inodes(sb); + invalidate_buffers(devp); ps2esdi_gendisk.part[start + partition].start_sect = 0; ps2esdi_gendisk.part[start + partition].nr_sects = 0; - }; + } ps2esdi_gendisk.part[start].nr_sects = ps2esdi_info[target].head * - ps2esdi_info[target].cyl * ps2esdi_info[target].sect; + ps2esdi_info[target].cyl * ps2esdi_info[target].sect; resetup_one_dev(&ps2esdi_gendisk, target); ps2esdi_valid[target] = 1; diff -u --recursive --new-file v2.1.80/linux/drivers/cdrom/cdu31a.c linux/drivers/cdrom/cdu31a.c --- v2.1.80/linux/drivers/cdrom/cdu31a.c Mon Jan 5 00:06:26 1998 +++ linux/drivers/cdrom/cdu31a.c Fri Jan 23 17:38:04 1998 @@ -1242,6 +1242,7 @@ buf[2] = size % 256; } +#if 0 /* Uniform cdrom interface function. Return the status of the current disc: If it is recognized as CD-I -> return XA Mode 2 Form 2 @@ -1268,6 +1269,7 @@ } else return CDS_NO_INFO; } +#endif /* Starts a read operation. Returns 0 on success and 1 on failure. The read operation used here allows multiple sequential sectors diff -u --recursive --new-file v2.1.80/linux/drivers/char/bttv.c linux/drivers/char/bttv.c --- v2.1.80/linux/drivers/char/bttv.c Thu Jan 15 14:33:05 1998 +++ linux/drivers/char/bttv.c Fri Jan 23 16:41:00 1998 @@ -129,16 +129,22 @@ btwrite(BT848_INT_I2CDONE, BT848_INT_STAT); btwrite(((addr & 0xff) << 24) | I2C_COMMAND, BT848_I2C); - - for (i=0x7fffffff; i; i--) + + /* + * Timeout for I2CRead is 1 second (this should be enough, really!) + */ + for (i=1000; i; i--) { stat=btread(BT848_INT_STAT); if (stat & BT848_INT_I2CDONE) break; + udelay(1000); /* 1ms, as I2C is 1kHz (?) */ } - if (!i) + if (!i) { + printk(KERN_DEBUG "bttv: I2CRead timeout\n"); return -1; + } if (!(stat & BT848_INT_RACK)) return -2; @@ -167,15 +173,18 @@ btwrite(data, BT848_I2C); - for (i=0x7fffffff; i; i--) + for (i=1000; i; i--) { stat=btread(BT848_INT_STAT); if (stat & BT848_INT_I2CDONE) break; + udelay(1000); } - if (!i) + if (!i) { + printk(KERN_DEBUG "bttv: I2CWrite timeout\n"); return -1; + } if (!(stat & BT848_INT_RACK)) return -2; @@ -772,7 +781,7 @@ /* * 32bit depth frame buffers need extra flags setting */ - + if (depth==4) mask=BT848_RISC_BYTE3; else @@ -1093,13 +1102,13 @@ case VIDIOCGPICT: { struct video_picture p=btv->picture; - if(btv->win.bpp==8) + if(btv->win.bpp==1) p.palette=VIDEO_PALETTE_HI240; - if(btv->win.bpp==16) + if(btv->win.bpp==2) p.palette=VIDEO_PALETTE_RGB565; - if(btv->win.bpp==24) + if(btv->win.bpp==3) p.palette=VIDEO_PALETTE_RGB24; - if(btv->win.bpp==32) + if(btv->win.bpp==4) p.palette=VIDEO_PALETTE_RGB32; if(copy_to_user(arg, &p, sizeof(p))) return -EFAULT; diff -u --recursive --new-file v2.1.80/linux/drivers/char/busmouse.c linux/drivers/char/busmouse.c --- v2.1.80/linux/drivers/char/busmouse.c Mon Nov 3 15:14:20 1997 +++ linux/drivers/char/busmouse.c Fri Jan 23 17:38:04 1998 @@ -109,7 +109,6 @@ static int fasync_mouse(struct file *filp, int on) { int retval; - struct inode *inode = filp->f_dentry->d_inode; retval = fasync_helper(filp, on, &mouse.fasyncptr); if (retval < 0) diff -u --recursive --new-file v2.1.80/linux/drivers/char/bw-qcam.c linux/drivers/char/bw-qcam.c --- v2.1.80/linux/drivers/char/bw-qcam.c Mon Jan 12 14:46:16 1998 +++ linux/drivers/char/bw-qcam.c Fri Jan 23 17:38:04 1998 @@ -923,11 +923,12 @@ close_bwqcam(qcams[i]); } #else -__initfunc(int init_bwqcams(struct video_init *unused)) +__initfunc(int init_bw_qcams(struct video_init *unused)) { struct parport *port; for (port = parport_enumerate(); port; port=port->next) init_bwqcam(port); + return 0; } #endif diff -u --recursive --new-file v2.1.80/linux/drivers/char/c-qcam.c linux/drivers/char/c-qcam.c --- v2.1.80/linux/drivers/char/c-qcam.c Mon Jan 12 14:46:16 1998 +++ linux/drivers/char/c-qcam.c Fri Jan 23 17:38:04 1998 @@ -771,5 +771,6 @@ for (port = parport_enumerate(); port; port=port->next) init_cqcam(port); + return 0; } #endif diff -u --recursive --new-file v2.1.80/linux/drivers/char/ftape/lowlevel/fdc-io.c linux/drivers/char/ftape/lowlevel/fdc-io.c --- v2.1.80/linux/drivers/char/ftape/lowlevel/fdc-io.c Tue Dec 2 09:33:16 1997 +++ linux/drivers/char/ftape/lowlevel/fdc-io.c Fri Jan 23 17:38:04 1998 @@ -385,7 +385,7 @@ int fdc_interrupt_wait(unsigned int time) { struct wait_queue wait = {current, NULL}; - int current_blocked = current->blocked; + sigset_t old_sigmask; static int resetting = 0; TRACE_FUN(ft_t_fdc_dma); @@ -401,14 +401,23 @@ /* timeout time will be up to USPT microseconds too long ! */ current->timeout = jiffies + (1000 * time + FT_USPT - 1) / FT_USPT; current->state = TASK_INTERRUPTIBLE; - current->blocked = _BLOCK_ALL; /* isn't this already set by the - * high level routines? - */ + + spin_lock_irq(¤t->sigmask_lock); + old_sigmask = current->blocked; + siginitset(¤t->blocked, _BLOCK_ALL); + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + add_wait_queue(&ftape_wait_intr, &wait); while (!ft_interrupt_seen && current->state != TASK_RUNNING) { schedule(); /* sets TASK_RUNNING on timeout */ } - current->blocked = current_blocked; /* restore */ + + spin_lock_irq(¤t->sigmask_lock); + current->blocked = old_sigmask; + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + remove_wait_queue(&ftape_wait_intr, &wait); /* the following IS necessary. True: as well * wake_up_interruptible() as the schedule() set TASK_RUNNING diff -u --recursive --new-file v2.1.80/linux/drivers/char/ftape/lowlevel/ftape-ctl.c linux/drivers/char/ftape/lowlevel/ftape-ctl.c --- v2.1.80/linux/drivers/char/ftape/lowlevel/ftape-ctl.c Tue Nov 25 14:45:27 1997 +++ linux/drivers/char/ftape/lowlevel/ftape-ctl.c Fri Jan 23 17:38:04 1998 @@ -794,8 +794,8 @@ i, *ft_buffer[i]->address); } } - if ((current->signal & _DONT_BLOCK) && - !(current->signal & _NEVER_BLOCK) && + if (sigtestsetmask(¤t->signal, _DONT_BLOCK) && + !(sigtestsetmask(¤t->signal, _NEVER_BLOCK)) && ftape_tape_running) { TRACE(ft_t_warn, "Interrupted by fatal signal and tape still running"); diff -u --recursive --new-file v2.1.80/linux/drivers/char/ftape/lowlevel/ftape-init.h linux/drivers/char/ftape/lowlevel/ftape-init.h --- v2.1.80/linux/drivers/char/ftape/lowlevel/ftape-init.h Tue Nov 25 14:45:27 1997 +++ linux/drivers/char/ftape/lowlevel/ftape-init.h Fri Jan 23 17:38:04 1998 @@ -32,12 +32,9 @@ #include #include -#define _S(nr) (1<<((nr)-1)) -#define _NEVER_BLOCK (_S(SIGKILL)|_S(SIGSTOP)) -#define _DONT_BLOCK (_NEVER_BLOCK|_S(SIGINT)) -#define _DO_BLOCK (_S(SIGPIPE)) -#define _BLOCK_ALL (0xffffffffL) - +#define _NEVER_BLOCK (sigmask(SIGKILL) | sigmask(SIGSTOP)) +#define _DONT_BLOCK (_NEVER_BLOCK | sigmask(SIGINT)) +#define _DO_BLOCK (sigmask(SIGPIPE)) #ifndef QIC117_TAPE_MAJOR #define QIC117_TAPE_MAJOR 27 diff -u --recursive --new-file v2.1.80/linux/drivers/char/ftape/lowlevel/ftape-rw.c linux/drivers/char/ftape/lowlevel/ftape-rw.c --- v2.1.80/linux/drivers/char/ftape/lowlevel/ftape-rw.c Tue Nov 25 14:45:27 1997 +++ linux/drivers/char/ftape/lowlevel/ftape-rw.c Fri Jan 23 17:38:04 1998 @@ -432,7 +432,8 @@ */ result = ftape_ready_wait(ftape_timeout.pause,&status); } - } while (ftape_tape_running && (current->signal & _NEVER_BLOCK) == 0); + } while (ftape_tape_running + && !(sigtestsetmask(¤t->signal, _NEVER_BLOCK))); #ifndef TESTING ft_location.known = 0; #endif @@ -660,7 +661,7 @@ * to find a way to skip an EMPTY_SEGMENT. !!! FIXME !!! */ if (ftape_read_id() < 0 || !ft_location.known || - (current->signal & _DONT_BLOCK)) { + sigtestsetmask(¤t->signal, _DONT_BLOCK)) { ft_location.known = 0; if (!ftape_tape_running || ++failures > FT_SECTORS_PER_SEGMENT) { @@ -775,7 +776,7 @@ fast_seek(count, 1); logical_forward(); if (ftape_read_id() < 0 || !ft_location.known || - (current->signal & _DONT_BLOCK)) { + (sigtestsetmask(¤t->signal, _DONT_BLOCK))) { if ((!ftape_tape_running && !ft_location.known) || ++failures > FT_SECTORS_PER_SEGMENT) { TRACE_ABORT(-EIO, ft_t_err, @@ -1001,7 +1002,7 @@ while (result < 0 && retry++ <= 5 && !ft_failure && - (current->signal & _DONT_BLOCK) == 0) { + !(sigtestsetmask(¤t->signal, _DONT_BLOCK))) { if (retry && start_offset < 5) { start_offset ++; diff -u --recursive --new-file v2.1.80/linux/drivers/char/ftape/lowlevel/ftape-tracing.h linux/drivers/char/ftape/lowlevel/ftape-tracing.h --- v2.1.80/linux/drivers/char/ftape/lowlevel/ftape-tracing.h Tue Nov 25 14:45:27 1997 +++ linux/drivers/char/ftape/lowlevel/ftape-tracing.h Fri Jan 23 17:38:04 1998 @@ -171,7 +171,7 @@ * but rather into ftape-rw.h (maybe) */ #define FT_SIGNAL_EXIT(sig_mask) \ - if (current->signal & (sig_mask)) { \ + if (sigtestsetmask(¤t->signal, sig_mask)) { \ TRACE_ABORT(-EINTR, \ ft_t_warn, \ "interrupted by non-blockable signal"); \ diff -u --recursive --new-file v2.1.80/linux/drivers/char/ftape/zftape/zftape-init.c linux/drivers/char/ftape/zftape/zftape-init.c --- v2.1.80/linux/drivers/char/ftape/zftape/zftape-init.c Tue Nov 25 14:45:28 1997 +++ linux/drivers/char/ftape/zftape/zftape-init.c Fri Jan 23 17:38:04 1998 @@ -73,7 +73,7 @@ /* Local vars. */ static int busy_flag = 0; -static int orig_sigmask; +static sigset_t orig_sigmask; /* the interface to the kernel vfs layer */ @@ -171,7 +171,7 @@ TRACE_ABORT(-ENXIO, ft_t_err, "failed: illegal unit nr"); } orig_sigmask = current->blocked; - current->blocked = _BLOCK_ALL; + sigfillset(¤t->blocked); result = _zft_open(MINOR(ino->i_rdev), filep->f_flags & O_ACCMODE); if (result < 0) { current->blocked = orig_sigmask; /* restore mask */ @@ -186,18 +186,15 @@ /* Mask signals that will disturb proper operation of the * program that is calling. */ - current->blocked = orig_sigmask | _DO_BLOCK; + current->blocked = orig_sigmask; + sigaddsetmask (¤t->blocked, _DO_BLOCK); TRACE_EXIT 0; } } /* Close floppy tape device */ -#if LINUX_VERSION_CODE >= KERNEL_VER(2,1,31) static int zft_close(struct inode *ino, struct file *filep) -#else -static void zft_close(struct inode *ino, struct file *filep) -#endif { int result; TRACE_FUN(ft_t_flow); @@ -210,7 +207,7 @@ TRACE_EXIT; /* keep busy_flag !(?) */ #endif } - current->blocked = _BLOCK_ALL; + sigfillset(¤t->blocked); result = _zft_close(); if (result < 0) { TRACE(ft_t_err, "_zft_close failed"); @@ -235,7 +232,7 @@ unsigned int command, unsigned long arg) { int result = -EIO; - int old_sigmask; + sigset_t old_sigmask; TRACE_FUN(ft_t_flow); if (!busy_flag || MINOR(ino->i_rdev) != zft_unit || ft_failure) { @@ -243,7 +240,7 @@ "failed: not busy, failure or wrong unit"); } old_sigmask = current->blocked; /* save mask */ - current->blocked = _BLOCK_ALL; + sigfillset(¤t->blocked); /* This will work as long as sizeof(void *) == sizeof(long) */ result = _zft_ioctl(command, (void *) arg); current->blocked = old_sigmask; /* restore mask */ @@ -261,7 +258,7 @@ #endif { int result = -EIO; - int old_sigmask; + sigset_t old_sigmask; TRACE_FUN(ft_t_flow); if (!busy_flag || @@ -276,7 +273,7 @@ "failed: not busy, failure or wrong unit"); } old_sigmask = current->blocked; /* save mask */ - current->blocked = _BLOCK_ALL; + sigfillset(¤t->blocked); if ((result = ftape_mmap(vma)) >= 0) { #ifndef MSYNC_BUG_WAS_FIXED static struct vm_operations_struct dummy = { NULL, }; @@ -307,7 +304,7 @@ #endif { int result = -EIO; - int old_sigmask; + sigset_t old_sigmask; #if LINUX_VERSION_CODE >= KERNEL_VER(2,1,60) struct inode *ino = fp->f_dentry->d_inode; #endif @@ -319,7 +316,7 @@ "failed: not busy, failure or wrong unit"); } old_sigmask = current->blocked; /* save mask */ - current->blocked = _BLOCK_ALL; + sigfillset(¤t->blocked); result = _zft_read(buff, req_len); current->blocked = old_sigmask; /* restore mask */ TRACE(ft_t_data_flow, "return with count: %d", result); @@ -343,7 +340,7 @@ #endif { int result = -EIO; - int old_sigmask; + sigset_t old_sigmask; #if LINUX_VERSION_CODE >= KERNEL_VER(2,1,60) struct inode *ino = fp->f_dentry->d_inode; #endif @@ -355,7 +352,7 @@ "failed: not busy, failure or wrong unit"); } old_sigmask = current->blocked; /* save mask */ - current->blocked = _BLOCK_ALL; + sigfillset(¤t->blocked); result = _zft_write(buff, req_len); current->blocked = old_sigmask; /* restore mask */ TRACE(ft_t_data_flow, "return with count: %d", result); diff -u --recursive --new-file v2.1.80/linux/drivers/char/hfmodem/gentbl.c linux/drivers/char/hfmodem/gentbl.c --- v2.1.80/linux/drivers/char/hfmodem/gentbl.c Tue Aug 5 09:48:55 1997 +++ linux/drivers/char/hfmodem/gentbl.c Wed Jan 21 15:34:19 1998 @@ -25,8 +25,8 @@ */ /*****************************************************************************/ - -#include + +/* This is compiled with HOSTCC - do not include any headers. */ #include #include diff -u --recursive --new-file v2.1.80/linux/drivers/char/keyboard.c linux/drivers/char/keyboard.c --- v2.1.80/linux/drivers/char/keyboard.c Wed Dec 3 15:21:57 1997 +++ linux/drivers/char/keyboard.c Wed Jan 21 14:27:21 1998 @@ -603,7 +603,7 @@ static void do_pad(unsigned char value, char up_flag) { static const char *pad_chars = "0123456789+-*/\015,.?()"; - static const char *app_map = "pqrstuvwxylSRQMnn?PQ"; + static const char *app_map = "pqrstuvwxylSRQMnnmPQ"; if (up_flag) return; /* no action, if this is a key release */ diff -u --recursive --new-file v2.1.80/linux/drivers/char/mem.c linux/drivers/char/mem.c --- v2.1.80/linux/drivers/char/mem.c Mon Dec 22 08:42:36 1997 +++ linux/drivers/char/mem.c Fri Jan 23 17:38:04 1998 @@ -30,10 +30,13 @@ void soundcard_init(void); #endif #ifdef CONFIG_ISDN -void isdn_init(void); +int isdn_init(void); #endif #ifdef CONFIG_PCWATCHDOG -void pcwatchdog_init(void); +int pcwatchdog_init(void); +#endif +#ifdef CONFIG_VIDEO_DEV +extern int videodev_init(void); #endif static ssize_t do_write_mem(struct file * file, void *p, unsigned long realp, diff -u --recursive --new-file v2.1.80/linux/drivers/char/misc.c linux/drivers/char/misc.c --- v2.1.80/linux/drivers/char/misc.c Sat Nov 29 10:33:19 1997 +++ linux/drivers/char/misc.c Fri Jan 23 17:38:04 1998 @@ -78,6 +78,9 @@ extern int nvram_init(void); extern int radio_init(void); extern void hfmodem_init(void); +#ifdef CONFIG_PC110_PAD +extern int pc110pad_init(void); +#endif #ifdef CONFIG_PROC_FS static int misc_read_proc(char *buf, char **start, off_t offset, diff -u --recursive --new-file v2.1.80/linux/drivers/char/pms.c linux/drivers/char/pms.c --- v2.1.80/linux/drivers/char/pms.c Sun Jan 4 10:40:15 1998 +++ linux/drivers/char/pms.c Fri Jan 23 17:38:04 1998 @@ -610,7 +610,7 @@ { int y; int dw = 2*dev->width; - char *src = (char *)bus_to_virt((void *)mem_base); + char *src = (char *)bus_to_virt(mem_base); char tmp[dw+32]; /* using a temp buffer is faster than direct */ int cnt = 0; diff -u --recursive --new-file v2.1.80/linux/drivers/char/tpqic02.c linux/drivers/char/tpqic02.c --- v2.1.80/linux/drivers/char/tpqic02.c Sat Nov 29 10:33:19 1997 +++ linux/drivers/char/tpqic02.c Fri Jan 23 17:38:04 1998 @@ -1766,8 +1766,10 @@ if (TP_DIAGS(current_tape_dev)) /* can't print a ``long long'' (for filp->f_pos), so chop it */ - printk(TPQIC02_NAME ": request READ, minor=%x, buf=%p, count=%lx, pos=%lx, flags=%x\n", - MINOR(dev), buf, count, (unsigned long) filp->f_pos, flags); + printk(TPQIC02_NAME ": request READ, minor=%x, buf=%p, count=%lx" + ", pos=%lx, flags=%x\n", + MINOR(dev), buf, (long) count, + (unsigned long) filp->f_pos, flags); if (count % TAPE_BLKSIZE) /* Only allow mod 512 bytes at a time. */ { @@ -1980,8 +1982,10 @@ if (TP_DIAGS(current_tape_dev)) { /* can't print a ``long long'' (for filp->f_pos), so chop it */ - printk(TPQIC02_NAME ": request WRITE, minor=%x, buf=%p, count=%lx, pos=%lx, flags=%x\n", - MINOR(dev), buf, count, (unsigned long) filp->f_pos, flags); + printk(TPQIC02_NAME ": request WRITE, minor=%x, buf=%p" + ", count=%lx, pos=%lx, flags=%x\n", + MINOR(dev), buf, + (long) count, (unsigned long) filp->f_pos, flags); } if (count % TAPE_BLKSIZE) /* only allow mod 512 bytes at a time */ @@ -2128,7 +2132,9 @@ tpqputs(TPQD_ALWAYS, "write request for <0 bytes"); if (TPQDBG(DEBUG)) { - printk(TPQIC02_NAME ": status_bytes_wr %x, buf %p, total_bytes_done %lx, count %lx\n", status_bytes_wr, buf, total_bytes_done, count); + printk(TPQIC02_NAME ": status_bytes_wr %x, buf %p" + ", total_bytes_done %lx, count %lx\n", + status_bytes_wr, buf, total_bytes_done, (long) count); } return -EINVAL; } /* qic02_tape_write */ @@ -2865,7 +2871,7 @@ return 0; } /* qic02_get_resources */ -__initfunc(static int qic02_tape_init(void)) +__initfunc(int qic02_tape_init(void)) { if (TPSTATSIZE != 6) { diff -u --recursive --new-file v2.1.80/linux/drivers/char/videodev.c linux/drivers/char/videodev.c --- v2.1.80/linux/drivers/char/videodev.c Mon Jan 12 14:46:16 1998 +++ linux/drivers/char/videodev.c Fri Jan 23 17:38:04 1998 @@ -36,17 +36,15 @@ static struct video_device *video_device[VIDEO_NUM_DEVICES]; -/* - * Initialiser list - */ - -struct video_init -{ - char *name; - int (*init)(struct video_init *); -}; - +#ifdef CONFIG_VIDEO_BT848 extern int init_bttv_cards(struct video_init *); +#endif +#ifdef CONFIG_VIDEO_CQCAM +extern int init_colour_qcams(struct video_init *); +#endif +#ifdef CONFIG_VIDEO_BWQCAM +extern int init_bw_qcams(struct video_init *); +#endif static struct video_init video_init_list[]={ #ifdef CONFIG_VIDEO_BT848 @@ -59,7 +57,7 @@ {"bw-qcam", init_bw_qcams}, #endif #ifdef CONFIG_VIDEO_PMS - {"PMS", init_pms_cards}, + {"PMS", init_pms_cards}, /* not defined anywhere */ #endif {"end", NULL} }; @@ -72,7 +70,6 @@ static ssize_t video_read(struct file *file, char *buf, size_t count, loff_t *ppos) { - int err; struct video_device *vfl=video_device[MINOR(file->f_dentry->d_inode->i_rdev)]; return vfl->read(vfl, buf, count, file->f_flags&O_NONBLOCK); } @@ -85,7 +82,6 @@ static ssize_t video_write(struct file *file, const char *buf, size_t count, loff_t *ppos) { - int err; struct video_device *vfl=video_device[MINOR(file->f_dentry->d_inode->i_rdev)]; return vfl->write(vfl, buf, count, file->f_flags&O_NONBLOCK); } diff -u --recursive --new-file v2.1.80/linux/drivers/isdn/hisax/avm_a1.c linux/drivers/isdn/hisax/avm_a1.c --- v2.1.80/linux/drivers/isdn/hisax/avm_a1.c Mon Nov 3 09:54:38 1997 +++ linux/drivers/isdn/hisax/avm_a1.c Wed Jan 21 23:42:12 1998 @@ -772,7 +772,7 @@ int loop = 0; char tmp[40]; - sp->counter = kstat.interrupts[sp->irq]; + sp->counter = kstat_irqs(sp->irq); sprintf(tmp, "IRQ %d count %d", sp->irq, sp->counter); debugl1(sp, tmp); clear_pending_ints(sp); @@ -785,16 +785,16 @@ /* At least 1-3 irqs must happen * (one from HSCX A, one from HSCX B, 3rd from ISAC) */ - if (kstat.interrupts[sp->irq] > sp->counter) + if (kstat_irqs(sp->irq) > sp->counter) break; current->state = TASK_INTERRUPTIBLE; current->timeout = jiffies + 1; schedule(); } sprintf(tmp, "IRQ %d count %d", sp->irq, - kstat.interrupts[sp->irq]); + kstat_irqs(sp->irq)); debugl1(sp, tmp); - if (kstat.interrupts[sp->irq] == sp->counter) { + if (kstat_irqs(sp->irq) == sp->counter) { printk(KERN_WARNING "AVM A1: IRQ(%d) getting no interrupts during init\n", sp->irq); diff -u --recursive --new-file v2.1.80/linux/drivers/isdn/hisax/elsa.c linux/drivers/isdn/hisax/elsa.c --- v2.1.80/linux/drivers/isdn/hisax/elsa.c Mon Nov 3 09:54:38 1997 +++ linux/drivers/isdn/hisax/elsa.c Wed Jan 21 23:42:12 1998 @@ -1180,7 +1180,7 @@ int ret, irq_cnt, cnt = 3; long flags; - irq_cnt = kstat.interrupts[sp->irq]; + irq_cnt = kstat_irqs(sp->irq); printk(KERN_INFO "Elsa: IRQ %d count %d\n", sp->irq, irq_cnt); ret = get_irq(sp->cardnr, &elsa_interrupt); #ifdef CONFIG_HISAX_ELSA_PCC @@ -1213,8 +1213,8 @@ } #endif printk(KERN_INFO "Elsa: IRQ %d count %d\n", sp->irq, - kstat.interrupts[sp->irq]); - if (kstat.interrupts[sp->irq] == irq_cnt) { + kstat_irqs(sp->irq)); + if (kstat_irqs(sp->irq) == irq_cnt) { printk(KERN_WARNING "Elsa: IRQ(%d) getting no interrupts during init %d\n", sp->irq, 4 - cnt); diff -u --recursive --new-file v2.1.80/linux/drivers/isdn/hisax/ix1_micro.c linux/drivers/isdn/hisax/ix1_micro.c --- v2.1.80/linux/drivers/isdn/hisax/ix1_micro.c Mon Nov 3 09:54:38 1997 +++ linux/drivers/isdn/hisax/ix1_micro.c Wed Jan 21 23:42:12 1998 @@ -841,7 +841,7 @@ int loop = 0; char tmp[40]; - sp->counter = kstat.interrupts[sp->irq]; + sp->counter = kstat_irqs(sp->irq); sprintf(tmp, "IRQ %d count %d", sp->irq, sp->counter); debugl1(sp, tmp); clear_pending_ints(sp); @@ -854,16 +854,16 @@ /* At least 1-3 irqs must happen * (one from HSCX A, one from HSCX B, 3rd from ISAC) */ - if (kstat.interrupts[sp->irq] > sp->counter) + if (kstat_irqs(sp->irq) > sp->counter) break; current->state = TASK_INTERRUPTIBLE; current->timeout = jiffies + 1; schedule(); } sprintf(tmp, "IRQ %d count %d", sp->irq, - kstat.interrupts[sp->irq]); + kstat_irqs(sp->irq)); debugl1(sp, tmp); - if (kstat.interrupts[sp->irq] == sp->counter) { + if (kstat_irqs(sp->irq) == sp->counter) { printk(KERN_WARNING "ix1-Micro: IRQ(%d) getting no interrupts during init\n", sp->irq); diff -u --recursive --new-file v2.1.80/linux/drivers/isdn/hisax/teles0.c linux/drivers/isdn/hisax/teles0.c --- v2.1.80/linux/drivers/isdn/hisax/teles0.c Mon Nov 3 09:54:38 1997 +++ linux/drivers/isdn/hisax/teles0.c Wed Jan 21 23:42:12 1998 @@ -802,7 +802,7 @@ int loop = 0; char tmp[40]; - sp->counter = kstat.interrupts[sp->irq]; + sp->counter = kstat_irqs(sp->irq); sprintf(tmp, "IRQ %d count %d", sp->irq, sp->counter); debugl1(sp, tmp); clear_pending_ints(sp); @@ -815,16 +815,16 @@ /* At least 1-3 irqs must happen * (one from HSCX A, one from HSCX B, 3rd from ISAC) */ - if (kstat.interrupts[sp->irq] > sp->counter) + if (kstat_irqs(sp->irq) > sp->counter) break; current->state = TASK_INTERRUPTIBLE; current->timeout = jiffies + 1; schedule(); } sprintf(tmp, "IRQ %d count %d", sp->irq, - kstat.interrupts[sp->irq]); + kstat_irqs(sp->irq)); debugl1(sp, tmp); - if (kstat.interrupts[sp->irq] == sp->counter) { + if (kstat_irqs(sp->irq) == sp->counter) { printk(KERN_WARNING "Teles0: IRQ(%d) getting no interrupts during init\n", sp->irq); diff -u --recursive --new-file v2.1.80/linux/drivers/isdn/hisax/teles3.c linux/drivers/isdn/hisax/teles3.c --- v2.1.80/linux/drivers/isdn/hisax/teles3.c Mon Nov 3 09:54:38 1997 +++ linux/drivers/isdn/hisax/teles3.c Wed Jan 21 23:43:24 1998 @@ -801,7 +801,7 @@ int loop = 0; char tmp[40]; - sp->counter = kstat.interrupts[sp->irq]; + sp->counter = kstat_irqs(sp->irq); sprintf(tmp, "IRQ %d count %d", sp->irq, sp->counter); debugl1(sp, tmp); clear_pending_ints(sp); @@ -816,16 +816,16 @@ /* At least 1-3 irqs must happen * (one from HSCX A, one from HSCX B, 3rd from ISAC) */ - if (kstat.interrupts[sp->irq] > sp->counter) + if (kstat_irqs(sp->irq) > sp->counter) break; current->state = TASK_INTERRUPTIBLE; current->timeout = jiffies + 1; schedule(); } sprintf(tmp, "IRQ %d count %d loop %d", sp->irq, - kstat.interrupts[sp->irq], loop); + kstat_irqs(sp->irq), loop); debugl1(sp, tmp); - if (kstat.interrupts[sp->irq] <= sp->counter) { + if (kstat_irqs(sp->irq) <= sp->counter) { printk(KERN_WARNING "Teles3: IRQ(%d) getting no interrupts during init\n", sp->irq); diff -u --recursive --new-file v2.1.80/linux/drivers/misc/parport_init.c linux/drivers/misc/parport_init.c --- v2.1.80/linux/drivers/misc/parport_init.c Sat Nov 29 16:19:41 1997 +++ linux/drivers/misc/parport_init.c Fri Jan 23 17:38:04 1998 @@ -68,8 +68,6 @@ #else __initfunc(int parport_init(void)) { - struct parport *pb; - if (io[0] == PARPORT_DISABLE) return 1; diff -u --recursive --new-file v2.1.80/linux/drivers/net/3c59x.c linux/drivers/net/3c59x.c --- v2.1.80/linux/drivers/net/3c59x.c Mon Jan 12 15:28:18 1998 +++ linux/drivers/net/3c59x.c Fri Jan 23 17:38:04 1998 @@ -482,9 +482,11 @@ /* This driver uses 'options' to pass the media type, full-duplex flag, etc. */ /* Note: this is the only limit on the number of cards supported!! */ static int options[8] = { -1, -1, -1, -1, -1, -1, -1, -1,}; +#ifdef MODULE static int full_duplex[8] = {-1, -1, -1, -1, -1, -1, -1, -1}; /* A list of all installed Vortex devices, for removing the driver module. */ static struct device *root_vortex_dev = NULL; +#endif #ifdef MODULE /* Variables to work-around the Compaq PCI BIOS32 problem. */ diff -u --recursive --new-file v2.1.80/linux/drivers/net/dgrs.c linux/drivers/net/dgrs.c --- v2.1.80/linux/drivers/net/dgrs.c Sun Jan 4 10:55:08 1998 +++ linux/drivers/net/dgrs.c Fri Jan 23 17:38:04 1998 @@ -1250,12 +1250,12 @@ )) { DGRS_PRIV *priv; - int i; #ifdef MODULE { /* Allocate and fill new device structure. */ int dev_size = sizeof(struct device) + sizeof(DGRS_PRIV); + int i; dev = (struct device *) kmalloc(dev_size, GFP_KERNEL); memset(dev, 0, dev_size); diff -u --recursive --new-file v2.1.80/linux/drivers/net/lance.c linux/drivers/net/lance.c --- v2.1.80/linux/drivers/net/lance.c Mon Nov 3 09:29:30 1997 +++ linux/drivers/net/lance.c Fri Jan 23 17:38:04 1998 @@ -611,7 +611,7 @@ can watch the LEDs even if the board isn't opened. */ outw(0x0002, ioaddr+LANCE_ADDR); /* set autoselect and clean xmausel */ - outw(inw(ioaddr+LANCE_BUS_IF) & 0xfffe | 0x0002, ioaddr+LANCE_BUS_IF); + outw((inw(ioaddr+LANCE_BUS_IF) & 0xfffe) | 0x0002, ioaddr+LANCE_BUS_IF); } if (lance_debug > 0 && did_version++ == 0) @@ -667,7 +667,7 @@ /* This is 79C960-specific: Turn on auto-select of media (AUI, BNC). */ outw(0x0002, ioaddr+LANCE_ADDR); /* set autoselect and clean xmausel */ - outw(inw(ioaddr+LANCE_BUS_IF) & 0xfffe | 0x0002, ioaddr+LANCE_BUS_IF); + outw((inw(ioaddr+LANCE_BUS_IF) & 0xfffe) | 0x0002, ioaddr+LANCE_BUS_IF); } if (lance_debug > 1) diff -u --recursive --new-file v2.1.80/linux/drivers/net/sdla_fr.c linux/drivers/net/sdla_fr.c --- v2.1.80/linux/drivers/net/sdla_fr.c Thu Jan 15 14:33:06 1998 +++ linux/drivers/net/sdla_fr.c Thu Jan 22 01:00:39 1998 @@ -1,4 +1,4 @@ - +/**************************************************************************** * sdla_fr.c WANPIPE(tm) Multiprotocol WAN Link Driver. Frame relay module. * * Author(s): Gene Kozin diff -u --recursive --new-file v2.1.80/linux/drivers/scsi/53c7,8xx.c linux/drivers/scsi/53c7,8xx.c --- v2.1.80/linux/drivers/scsi/53c7,8xx.c Wed Aug 6 13:02:59 1997 +++ linux/drivers/scsi/53c7,8xx.c Fri Jan 23 17:38:04 1998 @@ -5958,7 +5958,7 @@ host->host_no, cmd->pid); /* print_dsa does sanity check on address, no need to check */ else - print_dsa (host, le32_to_cpu(((struct NCR53c7x0_cmd *) cmd->host_scribble)-> dsa), ""); + print_dsa (host, bus_to_virt(le32_to_cpu(((struct NCR53c7x0_cmd *) cmd->host_scribble)-> dsa)), ""); } else printk ("scsi%d : scsi pid %ld for target %d lun %d has no NCR53c7x0_cmd\n", host->host_no, cmd->pid, cmd->target, cmd->lun); diff -u --recursive --new-file v2.1.80/linux/drivers/scsi/BusLogic.c linux/drivers/scsi/BusLogic.c --- v2.1.80/linux/drivers/scsi/BusLogic.c Tue Jan 20 15:02:21 1998 +++ linux/drivers/scsi/BusLogic.c Wed Jan 21 12:04:45 1998 @@ -2338,15 +2338,11 @@ Issue the Test Command Complete Interrupt commands. */ - InitialInterruptCount = 0; - for (i=0; iIRQ_Channel]; + InitialInterruptCount = kstat_irqs(HostAdapter->IRQ_Channel); for (i = 0; i < TestCount; i++) BusLogic_Command(HostAdapter, BusLogic_TestCommandCompleteInterrupt, NULL, 0, NULL, 0); - FinalInterruptCount = 0; - for (i=0; iIRQ_Channel]; + FinalInterruptCount = kstat_irqs(HostAdapter->IRQ_Channel); /* Verify that BusLogic_InterruptHandler was called at least TestCount times. Shared IRQ Channels could cause more than TestCount interrupts to diff -u --recursive --new-file v2.1.80/linux/drivers/scsi/Makefile linux/drivers/scsi/Makefile --- v2.1.80/linux/drivers/scsi/Makefile Mon Jan 5 01:41:01 1998 +++ linux/drivers/scsi/Makefile Wed Jan 21 17:04:39 1998 @@ -430,6 +430,14 @@ endif endif +ifeq ($(CONFIG_SCSI_PLUTO),y) +L_OBJS += pluto.o +else + ifeq ($(CONFIG_SCSI_PLUTO),m) + M_OBJS += pluto.o + endif +endif + ifeq ($(CONFIG_SCSI_EATA),y) L_OBJS += eata.o else diff -u --recursive --new-file v2.1.80/linux/drivers/scsi/NCR5380.c linux/drivers/scsi/NCR5380.c --- v2.1.80/linux/drivers/scsi/NCR5380.c Wed Apr 23 19:01:21 1997 +++ linux/drivers/scsi/NCR5380.c Fri Jan 23 17:38:04 1998 @@ -625,7 +625,7 @@ */ -static int probe_irq __initdata; +static int probe_irq __initdata ; __initfunc(static void probe_intr (int irq, void *dev_id, struct pt_regs * regs)) { probe_irq = irq; }; diff -u --recursive --new-file v2.1.80/linux/drivers/scsi/NCR53c406a.c linux/drivers/scsi/NCR53c406a.c --- v2.1.80/linux/drivers/scsi/NCR53c406a.c Wed Apr 23 19:01:21 1997 +++ linux/drivers/scsi/NCR53c406a.c Fri Jan 23 17:38:04 1998 @@ -1012,7 +1012,7 @@ outb(SYNC_MODE, SYNCOFF); /* synchronous mode */ } -__initfunc(void calc_port_addr()) +__initfunc(void calc_port_addr(void)) { /* Control Register Set 0 */ TC_LSB = (port_base+0x00); diff -u --recursive --new-file v2.1.80/linux/drivers/scsi/advansys.c linux/drivers/scsi/advansys.c --- v2.1.80/linux/drivers/scsi/advansys.c Sun Dec 21 17:04:48 1997 +++ linux/drivers/scsi/advansys.c Fri Jan 23 17:35:23 1998 @@ -1,10 +1,10 @@ -/* $Id: advansys.c,v 1997/05/28 00:06:55 bobf Exp bobf $ */ -#define ASC_VERSION "2.8" /* AdvanSys Driver Version */ +/* $Id: advansys.c,v 1.49 1998/01/22 20:19:25 bobf Exp bobf $ */ +#define ASC_VERSION "3.1D" /* AdvanSys Driver Version */ /* * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters * - * Copyright (c) 1995-1997 Advanced System Products, Inc. + * Copyright (c) 1995-1998 Advanced System Products, Inc. * All Rights Reserved. * * Redistribution and use in source and binary forms, with or without @@ -16,13 +16,12 @@ * http://www.advansys.com/linux.html * * The latest version of the AdvanSys driver is available at: - * ftp://ftp.advansys.com/pub/linux + * ftp://ftp.advansys.com/pub/linux/linux.tgz * * Please send questions, comments, bug reports to: - * bobf@advansys.com (Bob Frey) + * bobf@advansys.com (Bob Frey) */ - /* Documentation for the AdvanSys Driver @@ -43,7 +42,7 @@ A. Linux Kernel Testing This driver has been tested in the following Linux kernels: v1.2.13, - v1.3.57, v2.0.30, v2.1.40. These kernel versions are major releases + v1.3.57, v2.0.33, v2.1.77. These kernel versions are major releases of Linux or the latest Linux kernel versions available when this version of the driver was released. The driver should also work in earlier versions of the Linux kernel. Beginning with v1.3.58 the AdvanSys driver @@ -53,8 +52,10 @@ B. Adapters Supported by this Driver AdvanSys (Advanced System Products, Inc.) manufactures the following - Bus-Mastering SCSI-2 Host Adapters for the ISA, EISA, VL, and PCI - buses. This Linux driver supports all of these adapters. + RISC-based, Bus-Mastering, Fast (10 Mhz) and Ultra (20 Mhz) Narrow + (8-bit transfer) SCSI Host Adapters for the ISA, EISA, VL, and PCI + buses and RISC-based, Bus-Mastering, Ultra (20 Mhz) Wide (16-bit + transfer) SCSI Host Adapters for the PCI bus. The CDB counts below indicate the number of SCSI CDB (Command Descriptor Block) requests that can be stored in the RISC chip @@ -72,7 +73,7 @@ ABP930U - Bus-Master PCI Ultra (16 CDB) ABP930UA - 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) + ABP960U - Bus-Master PCI MAC/PC Ultra (16 CDB) (Footnote 2) Single Channel Products: ABP542 - Bus-Master ISA with floppy (240 CDB) @@ -82,11 +83,14 @@ ABP940U - Bus-Master PCI Ultra (240 CDB) ABP970 - Bus-Master PCI MAC/PC (240 CDB) ABP970U - Bus-Master PCI MAC/PC Ultra (240 CDB) + ABP940UW - Bus-Master PCI Ultra-Wide (240 CDB) - Dual Channel Products: + Multi Channel Products: ABP752 - Dual Channel Bus-Master EISA (240 CDB Per Channel) ABP852 - Dual Channel Bus-Master VL (240 CDB Per Channel) ABP950 - Dual Channel Bus-Master PCI (240 CDB Per Channel) + ABP980 - Four Channel Bus-Master PCI (240 CDB Per Channel) + ABP980U - Four Channel Bus-Master PCI Ultra (240 CDB Per Channel) Footnotes: 1. This board has been shipped by HP with the 4020i CD-R drive. @@ -264,6 +268,7 @@ --- Driver Options --- Debugging Header --- Asc Library Constants and Macros + --- Adv Library Constants and Macros --- Driver Constants and Macros --- Driver Structures --- Driver Data @@ -272,20 +277,24 @@ --- Loadable Driver Support --- Miscellaneous Driver Functions --- Functions Required by the Asc Library + --- Functions Required by the Adv Library --- Tracing and Debugging Functions --- Asc Library Functions + --- Adv Library Functions 3. The string 'XXX' is used to flag code that needs to be re-written or that contains a problem that needs to be addressed. 4. I have stripped comments from and reformatted the source for the - Asc Library which is included in this file. I haven't done this - to obfuscate the code. Actually I have done this to deobfuscate - the code. The Asc Library source can be found under the following - headings. + Asc Library and Adv Library to reduce the size of this file. This + source can be found under the following headings. The Asc Library + is used to support Narrow Boards. The Adv Library is used to + support Wide Boards. --- Asc Library Constants and Macros + --- Adv Library Constants and Macros --- Asc Library Functions + --- Adv Library Functions G. Driver Compile Time Options and Debugging @@ -308,7 +317,7 @@ Enabling this option adds tracing functions to the driver and the ability to set a driver tracing level at boot time. This - option will also symbols not required outside the driver to + option will also export symbols not required outside the driver to the kernel name space. This option is very useful for debugging the driver, but it will add to the size of the driver execution image and add overhead to the execution of the driver. @@ -319,7 +328,7 @@ If the driver is loaded at boot time and the LILO Driver Option is included in the system, the debug level can be changed by - specifying a 5th (ASC_NUM_BOARD_SUPPORTED + 1) I/O Port. The + specifying a 5th (ASC_NUM_IOPORT_PROBE + 1) I/O Port. The first three hex digits of the pseudo I/O Port must be set to 'deb' and the fourth hex digit specifies the debug level: 0 - F. The following command line will look for an adapter at 0x330 @@ -350,11 +359,6 @@ I found that increasing LOG_BUF_LEN to 40960 in kernel/printk.c prevents most level 1 debug messages from being lost. - this constant for debugging purposes, but for normal use of - the driver the constant should not be defined. This option - does not add overhead to the driver, but it does add unnecessary - symbols to the kernel name space. - 3. ADVANSYS_STATS - Enable statistics (Def: Enabled >= v1.3.0) Enabling this option adds statistics collection and display @@ -379,7 +383,6 @@ When ADVANSYS_STATS is not defined the AdvanSys /proc files only contain adapter and device configuration information. - H. Driver LILO Option If init/main.c is modified as described in the 'Directions for Adding @@ -406,7 +409,7 @@ insmod advansys.o asc_iopflag=1 asc_ioport=0x110,0x330 - If ADVANSYS_DEBUG is defined a 5th (ASC_NUM_BOARD_SUPPORTED + 1) + If ADVANSYS_DEBUG is defined a 5th (ASC_NUM_IOPORT_PROBE + 1) I/O Port may be added to specify the driver debug level. Refer to the 'Driver Compile Time Options and Debugging' section above for more information. @@ -505,7 +508,7 @@ repeat busy or QUEUE FULL status returned by a device. 2. Incorporate miscellaneous Asc Library bug fixes. 3. To allow the driver to work in kernels with broken module - support set 'cmd_per_lun' if the driver is compile as a + support set 'cmd_per_lun' if the driver is compiled as a module. This change affects kernels v1.3.89 to present. 4. Remove PCI BIOS address from the driver banner. The PCI BIOS is relocated by the motherboard BIOS and its new address can @@ -541,13 +544,42 @@ option is enabled by default. 2.8 (5/26/97): - 1. Change version number to 2.8, skipping 2.3 through 2.7, in - order to synchronize the Linux driver version numbering with - other AdvanSys drivers. - 2. Reformat source files without tabs to give everyone everyone - the same view of the file regardless of the tab setting used. + 1. Change version number to 2.8 to synchronize the Linux driver + version numbering with other AdvanSys drivers. + 2. Reformat source files without tabs to present the same view + of the file to everyone regardless of the editor tab setting + being used. 3. Add Asc Library bug fixes. + 3.1A (1/8/98): + 1. Change version number to 3.1 to indicate that support for + Ultra-Wide adapters (ABP-940UW) is included in this release. + 2. Add Asc Library (Narrow Board) bug fixes. + 3. Report an underrun condition with the host status byte set + to DID_UNDERRUN. Currently DID_UNDERRUN is defined to 0 which + causes the underrun condition to be ignored. When Linux defines + its own DID_UNDERRUN the constant defined in this file can be + removed. + 4. Add patch to AscWaitTixISRDone(). + 5. Add support for up to 16 different AdvanSys host adapter SCSI + channels in one system. This allows four cards with four channels + to be used in one system. + + 3.1B (1/9/98): + 1. Handle that PCI register base addresses are not always page + aligned even though ioremap() requires that the address argument + be page aligned. + + 3.1C (1/10/98): + 1. Update latest BIOS version to 3.1E. + 2. Don't set microcode SDTR variable at initialization. Instead + wait until device capabilities have been detected from an Inquiry + command. + + 3.1D (1/21/98): + 1. Improve performance when the driver is compiled as module by + allowing up to 64 scatter-gather elements instead of 8. + J. Known Problems or Issues 1. Remove conditional constants (ASC_QUEUE_FLOW_CONTROL) around @@ -563,8 +595,15 @@ Thomas E Zerucha pointed out a bug in advansys_biosparam() which was fixed in the 1.3 release. - Erik Ratcliffe has done a lot of testing of - the AdvanSys driver in the Caldera releases. + Erik Ratcliffe has done testing of the + AdvanSys driver in the Caldera releases. + + Rik van Riel provided a patch to + AscWaitTixISRDone() which he found necessary to make the + driver work with a SCSI-1 disk. + + Mark Moran has helped test Ultra-Wide + support in the 3.1A driver. L. AdvanSys Contact Information @@ -576,7 +615,7 @@ Tech Support: 1-800-525-7440/1-408-467-2930 BBS: 1-408-383-9540 (14400,N,8,1) Interactive FAX: 1-408-383-9753 - Customer Direct Sales: 1-800-883-1099/1-408-383-5777 + Customer Direct Sales: 1-800-525-7443/1-408-383-5777 Tech Support E-Mail: support@advansys.com FTP Site: ftp.advansys.com (login: anonymous) Web Site: http://www.advansys.com @@ -613,6 +652,7 @@ #include #include #include +#include #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) #include #endif /* version >= v1.3.0 */ @@ -633,6 +673,13 @@ #include "sd.h" #include "advansys.h" +/* + * If Linux eventually defines a DID_UNDERRUN, the constant here can be + * removed. The current value of zero for DID_UNDERRUN results in underrun + * conditions being ignored. + */ +#define DID_UNDERRUN 0 + /* * --- Driver Options @@ -646,7 +693,7 @@ /* * Because of no /proc to display them, statistics are disabled - * for version prior to v1.3.0. + * for versions prior to v1.3.0. */ #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0) #undef ADVANSYS_STATS /* Disable statistics */ @@ -672,7 +719,7 @@ #define ASC_LIB_VERSION_MAJOR 1 #define ASC_LIB_VERSION_MINOR 22 -#define ASC_LIB_SERIAL_NUMBER 105 +#define ASC_LIB_SERIAL_NUMBER 111 typedef unsigned char uchar; @@ -769,27 +816,6 @@ #define ASC_MAX_SG_QUEUE 7 #define ASC_MAX_SG_LIST SG_ALL -#define CC_CLEAR_LRAM_SRB_PTR FALSE -#define CC_VERIFY_LRAM_COPY FALSE -#define CC_DEBUG_SG_LIST FALSE -#define CC_FAST_STRING_IO FALSE -#define CC_WRITE_IO_COUNT FALSE -#define CC_CLEAR_DMA_REMAIN FALSE -#define CC_DISABLE_PCI_PARITY_INT TRUE -#define CC_LITTLE_ENDIAN_HOST TRUE -#define CC_STRUCT_ALIGNED TRUE -#define CC_MEMORY_MAPPED_IO FALSE -#define CC_INCLUDE_EEP_CONFIG TRUE -#define CC_PCI_ULTRA TRUE -#define CC_ASC_SCSI_Q_USRDEF FALSE -#define CC_ASC_SCSI_REQ_Q_USRDEF FALSE -#define CC_ASCISR_CHECK_INT_PENDING TRUE -#define CC_CHK_FIX_EEP_CONTENT TRUE -#define CC_INCLUDE_EEP_CONFIG TRUE -#define CC_PLEXTOR_VL FALSE -#define CC_TMP_USE_EEP_SDTR FALSE -#define CC_CHK_COND_REDO_SDTR TRUE - #define ASC_CS_TYPE unsigned short #ifndef asc_ptr_type #define asc_ptr_type @@ -840,27 +866,6 @@ #define ASC_MAX_ISA_DMA_COUNT (0x00FFFFFFL) #define ASC_MAX_EISA_DMA_ADDR (0x07FFFFFFL) #define ASC_MAX_EISA_DMA_COUNT (0x07FFFFFFL) -#if !CC_STRUCT_ALIGNED -#define DvcGetQinfo(iop_base, s_addr, outbuf, words) \ -AscMemWordCopyFromLram(iop_base, s_addr, outbuf, words) -#define DvcPutScsiQ(iop_base, s_addr, outbuf, words) \ -AscMemWordCopyToLram(iop_base, s_addr, outbuf, words) -#endif -#ifdef ASC_CHIP_VERSION -#endif -#if CC_MEMORY_MAPPED_IO -#define inp(port) *((uchar *)(port)) -#define outp(port, data) *((uchar *)(port)) = (uchar)(data) -#if CC_LITTLE_ENDIAN_HOST -#define inpw(port) *((ushort *)(port)) -#define outpw(port, data) *((ushort *)(port)) = (ushort)(data) -#else -#define inpw(port) EndianSwap16Bit((*((ushort *)(port)))) -#define outpw(port, data) *((ushort *)(port)) = EndianSwap16Bit((ushort)(data)) -#define inpw_noswap(port) *((ushort *)(port)) -#define outpw_noswap(port, data) *((ushort *)(port)) = (ushort)(data) -#endif -#endif #ifndef inpw_noswap #define inpw_noswap(port) inpw(port) #endif @@ -901,6 +906,7 @@ #define ASC_MAX_SENSE_LEN 32 #define ASC_MIN_SENSE_LEN 14 #define ASC_MAX_CDB_LEN 12 +#define ASC_SCSI_RESET_HOLD_TIME_US 60 #define SCSICMD_TestUnitReady 0x00 #define SCSICMD_Rewind 0x01 #define SCSICMD_Rezero 0x01 @@ -963,6 +969,7 @@ #define SCSI_SENKEY_VOL_OVERFLOW 0x0D #define SCSI_SENKEY_MISCOMP 0x0E #define SCSI_SENKEY_RESERVED 0x0F +#define SCSI_ASC_NOMEDIA 0x3A #define ASC_SRB_HOST(x) ((uchar)((uchar)(x) >> 4)) #define ASC_SRB_TID(x) ((uchar)((uchar)(x) & (uchar)0x0F)) #define ASC_SRB_LUN(x) ((uchar)((uint)(x) >> 13)) @@ -1005,48 +1012,22 @@ #define M2_QTAG_MSG_ORDERED 0x22 #define M2_IGNORE_WIDE_RESIDUE 0x23 -#if CC_LITTLE_ENDIAN_HOST typedef struct { uchar peri_dvc_type:5; uchar peri_qualifier:3; } ASC_SCSI_INQ0; -#else -typedef struct { - uchar peri_qualifier:3; - uchar peri_dvc_type:5; -} ASC_SCSI_INQ0; - -#endif -#if CC_LITTLE_ENDIAN_HOST typedef struct { uchar dvc_type_modifier:7; uchar rmb:1; } ASC_SCSI_INQ1; -#else -typedef struct { - uchar rmb:1; - uchar dvc_type_modifier:7; -} ASC_SCSI_INQ1; - -#endif -#if CC_LITTLE_ENDIAN_HOST typedef struct { uchar ansi_apr_ver:3; uchar ecma_ver:3; uchar iso_ver:2; } ASC_SCSI_INQ2; -#else -typedef struct { - uchar iso_ver:2; - uchar ecma_ver:3; - uchar ansi_apr_ver:3; -} ASC_SCSI_INQ2; - -#endif -#if CC_LITTLE_ENDIAN_HOST typedef struct { uchar rsp_data_fmt:4; uchar res:2; @@ -1054,16 +1035,6 @@ uchar aenc:1; } ASC_SCSI_INQ3; -#else -typedef struct { - uchar aenc:1; - uchar TemIOP:1; - uchar res:2; - uchar rsp_data_fmt:4; -} ASC_SCSI_INQ3; - -#endif -#if CC_LITTLE_ENDIAN_HOST typedef struct { uchar StfRe:1; uchar CmdQue:1; @@ -1075,19 +1046,6 @@ uchar RelAdr:1; } ASC_SCSI_INQ7; -#else -typedef struct { - uchar RelAdr:1; - uchar WBus32:1; - uchar WBus16:1; - uchar Sync:1; - uchar Linked:1; - uchar Reserved:1; - uchar CmdQue:1; - uchar StfRe:1; -} ASC_SCSI_INQ7; - -#endif typedef struct { ASC_SCSI_INQ0 byte0; ASC_SCSI_INQ1 byte1; @@ -1102,7 +1060,6 @@ uchar product_rev_level[4]; } ASC_SCSI_INQUIRY; -#if CC_LITTLE_ENDIAN_HOST typedef struct asc_req_sense { uchar err_code:7; uchar info_valid:1; @@ -1126,31 +1083,6 @@ uchar info2[4]; } ASC_REQ_SENSE; -#else -typedef struct asc_req_sense { - uchar info_valid:1; - uchar err_code:7; - uchar segment_no; - uchar file_mark:1; - uchar sense_EOM:1; - uchar sense_ILI:1; - uchar reserved_bit:1; - uchar sense_key:4; - uchar info1[4]; - uchar add_sense_len; - uchar cmd_sp_info[4]; - uchar asc; - uchar ascq; - uchar fruc; - uchar sks_valid:1; - uchar sks_byte0:7; - uchar sks_bytes[2]; - uchar notused[2]; - uchar ex_sense_code; - uchar info2[4]; -} ASC_REQ_SENSE; - -#endif #define ASC_SG_LIST_PER_Q 7 #define QS_FREE 0x00 #define QS_READY 0x01 @@ -1348,9 +1280,6 @@ ASC_SCSIQ_2 q2; uchar *cdbptr; ASC_SG_HEAD *sg_head; -#if CC_ASC_SCSI_Q_USRDEF - ASC_SCSI_Q_USR usr; -#endif } ASC_SCSI_Q; typedef struct asc_scsi_req_q { @@ -1362,9 +1291,6 @@ ASC_SCSIQ_3 r3; uchar cdb[ASC_MAX_CDB_LEN]; uchar sense[ASC_MIN_SENSE_LEN]; -#if CC_ASC_SCSI_REQ_Q_USRDEF - ASC_SCSI_REQ_Q_USR usr; -#endif } ASC_SCSI_REQ_Q; typedef struct asc_scsi_bios_req_q { @@ -1569,9 +1495,10 @@ ushort mcode_date; ushort mcode_version; uchar max_tag_qng[ASC_MAX_TID + 1]; - uchar *overrun_buf; + uchar *overrun_buf; uchar sdtr_period_offset[ASC_MAX_TID + 1]; ushort pci_slot_info; + uchar adapter_info[6]; } ASC_DVC_CFG; #define ASC_DEF_DVC_CNTL 0xFFFF @@ -1856,7 +1783,7 @@ #define ASC_CFG0_SCSI_PARITY_ON 0x0800 #define ASC_CFG1_SCSI_TARGET_ON 0x0080 #define ASC_CFG1_LRAM_8BITS_ON 0x0800 -#define ASC_CFG_MSW_CLR_MASK 0x30C0 +#define ASC_CFG_MSW_CLR_MASK 0x3080 #define CSW_TEST1 (ASC_CS_TYPE)0x8000 #define CSW_AUTO_CONFIG (ASC_CS_TYPE)0x4000 #define CSW_RESERVED1 (ASC_CS_TYPE)0x2000 @@ -2000,7 +1927,7 @@ STATIC void AscDisableInterrupt(PortAddr); STATIC void AscEnableInterrupt(PortAddr); STATIC void AscSetBank(PortAddr, uchar); -STATIC int AscResetChipAndScsiBus(PortAddr); +STATIC int AscResetChipAndScsiBus(ASC_DVC_VAR *); STATIC ushort AscGetIsaDmaChannel(PortAddr); STATIC ushort AscSetIsaDmaChannel(PortAddr, ushort); STATIC uchar AscSetIsaDmaSpeed(PortAddr, uchar); @@ -2143,10 +2070,1120 @@ /* + * --- Adv Library Constants and Macros + */ + +#define ADV_LIB_VERSION_MAJOR 3 +#define ADV_LIB_VERSION_MINOR 34 + +/* d_os_dep.h */ +#define ADV_OS_LINUX + +/* + * Define Adv Library required special types. + */ +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0) +#define AdvPortAddr unsigned short /* I/O Port address size */ +#else /* version >= v1,3,0 */ +#define AdvPortAddr unsigned long /* Virtual memory address size */ +#endif /* version >= v1,3,0 */ + +/* + * Define Adv Library required memory access macros. + */ +#define ADV_MEM_READB(addr) readb(addr) +#define ADV_MEM_READW(addr) readw(addr) +#define ADV_MEM_WRITEB(addr, byte) writeb(byte, addr) +#define ADV_MEM_WRITEW(addr, word) writew(word, addr) + +/* + * The I/O memory mapping function names changed in 2.1.X. + */ +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,0) +#define ioremap vremap +#define iounmap vfree +#endif /* version < v2.1.0 */ + +/* + * Define total number of simultaneous maximum element scatter-gather + * requests, i.e. ADV_TOT_SG_LIST * ADV_MAX_SG_LIST is the total number + * of simultaneous scatter-gather elements supported per wide adapter. + */ +#define ADV_TOT_SG_LIST 64 + +/* + * Define Adv Library required per request scatter-gather element limit. + */ +#define ADV_MAX_SG_LIST 64 + +/* + * Scatter-Gather Definitions per request. + * + * Because SG block memory is allocated in virtual memory but is + * referenced by the microcode as physical memory, we need to do + * calculations to insure there will be enough physically contiguous + * memory to support ADV_MAX_SG_LIST SG entries. + */ + +/* Number of SG blocks needed. */ +#define ADV_NUM_SG_BLOCK \ + ((ADV_MAX_SG_LIST + (NO_OF_SG_PER_BLOCK - 1))/NO_OF_SG_PER_BLOCK) + +/* Total contiguous memory needed for SG blocks. */ +#define ADV_SG_TOTAL_MEM_SIZE \ + (sizeof(ADV_SG_BLOCK) * ADV_NUM_SG_BLOCK) + +#define ASC_PAGE_SIZE PAGE_SIZE + +/* + * Number of page crossings possible for the total contiguous virtual memory + * needed for SG blocks. + * + * We need to allocate this many additional SG blocks in virtual memory to + * insure there will be space for ADV_NUM_SG_BLOCK physically contiguous + * scatter-gather blocks. + */ +#define ADV_NUM_PAGE_CROSSING \ + ((ADV_SG_TOTAL_MEM_SIZE + (ASC_PAGE_SIZE - 1))/ASC_PAGE_SIZE) + +/* + * Define Adv Library Assertion Macro. + */ + +#define ADV_ASSERT(a) ASC_ASSERT(a) + +/* a_condor.h */ +#define ADV_PCI_VENDOR_ID 0x10CD +#define ADV_PCI_DEVICE_ID_REV_A 0x2300 + +#define ASC_EEP_DVC_CFG_BEGIN (0x00) +#define ASC_EEP_DVC_CFG_END (0x15) +#define ASC_EEP_DVC_CTL_BEGIN (0x16) /* location of OEM name */ +#define ASC_EEP_MAX_WORD_ADDR (0x1E) + +#define ASC_EEP_DELAY_MS 100 + +/* + * EEPROM bits reference by the RISC after initialization. + */ +#define ADV_EEPROM_BIG_ENDIAN 0x8000 /* EEPROM Bit 15 */ +#define ADV_EEPROM_BIOS_ENABLE 0x4000 /* EEPROM Bit 14 */ +#define ADV_EEPROM_TERM_POL 0x2000 /* EEPROM Bit 13 */ + +/* + * EEPROM configuration format + * + * Field naming convention: + * + * *_enable indicates the field enables or disables the feature. The + * value is never reset. + * + * *_able indicates both whether a feature should be enabled or disabled + * and whether a device isi capable of the feature. At initialization + * this field may be set, but later if a device is found to be incapable + * of the feature, the field is cleared. + * + * Default values are maintained in a_init.c in the structure + * Default_EEPROM_Config. + */ +typedef struct adveep_config +{ + /* Word Offset, Description */ + + ushort cfg_lsw; /* 00 power up initialization */ + /* bit 13 set - Term Polarity Control */ + /* bit 14 set - BIOS Enable */ + /* bit 15 set - Big Endian Mode */ + ushort cfg_msw; /* 01 unused */ + ushort disc_enable; /* 02 disconnect enable */ + ushort wdtr_able; /* 03 Wide DTR able */ + ushort sdtr_able; /* 04 Synchronous DTR able */ + ushort start_motor; /* 05 send start up motor */ + ushort tagqng_able; /* 06 tag queuing able */ + ushort bios_scan; /* 07 BIOS device control */ + ushort scam_tolerant; /* 08 no scam */ + + uchar adapter_scsi_id; /* 09 Host Adapter ID */ + uchar bios_boot_delay; /* power up wait */ + + uchar scsi_reset_delay; /* 10 reset delay */ + uchar bios_id_lun; /* first boot device scsi id & lun */ + /* high nibble is lun */ + /* low nibble is scsi id */ + + uchar termination; /* 11 0 - automatic */ + /* 1 - low off / high off */ + /* 2 - low off / high on */ + /* 3 - low on / high on */ + /* There is no low on / high off */ + + uchar reserved1; /* reserved byte (not used) */ + + ushort bios_ctrl; /* 12 BIOS control bits */ + /* bit 0 set: BIOS don't act as initiator. */ + /* bit 1 set: BIOS > 1 GB support */ + /* bit 2 set: BIOS > 2 Disk Support */ + /* bit 3 set: BIOS don't support removables */ + /* bit 4 set: BIOS support bootable CD */ + /* bit 5 set: */ + /* bit 6 set: BIOS support multiple LUNs */ + /* bit 7 set: BIOS display of message */ + /* bit 8 set: */ + /* bit 9 set: Reset SCSI bus during init. */ + /* bit 10 set: */ + /* bit 11 set: No verbose initialization. */ + /* bit 12 set: SCSI parity enabled */ + /* bit 13 set: */ + /* bit 14 set: */ + /* bit 15 set: */ + ushort ultra_able; /* 13 ULTRA speed able */ + ushort reserved2; /* 14 reserved */ + uchar max_host_qng; /* 15 maximum host queuing */ + uchar max_dvc_qng; /* maximum per device queuing */ + ushort dvc_cntl; /* 16 control bit for driver */ + ushort bug_fix; /* 17 control bit for bug fix */ + ushort serial_number_word1; /* 18 Board serial number word 1 */ + ushort serial_number_word2; /* 19 Board serial number word 2 */ + ushort serial_number_word3; /* 20 Board serial number word 3 */ + ushort check_sum; /* 21 EEP check sum */ + uchar oem_name[16]; /* 22 OEM name */ + ushort dvc_err_code; /* 30 last device driver error code */ + ushort adv_err_code; /* 31 last uc and Adv Lib error code */ + ushort adv_err_addr; /* 32 last uc error address */ + ushort saved_dvc_err_code; /* 33 saved last dev. driver error code */ + ushort saved_adv_err_code; /* 34 saved last uc and Adv Lib error code */ + ushort saved_adv_err_addr; /* 35 saved last uc error address */ + ushort num_of_err; /* 36 number of error */ +} ADVEEP_CONFIG; + +/* + * EEPROM Commands + */ +#define ASC_EEP_CMD_DONE 0x0200 +#define ASC_EEP_CMD_DONE_ERR 0x0001 + +/* cfg_word */ +#define EEP_CFG_WORD_BIG_ENDIAN 0x8000 + +/* bios_ctrl */ +#define BIOS_CTRL_BIOS 0x0001 +#define BIOS_CTRL_EXTENDED_XLAT 0x0002 +#define BIOS_CTRL_GT_2_DISK 0x0004 +#define BIOS_CTRL_BIOS_REMOVABLE 0x0008 +#define BIOS_CTRL_BOOTABLE_CD 0x0010 +#define BIOS_CTRL_MULTIPLE_LUN 0x0040 +#define BIOS_CTRL_DISPLAY_MSG 0x0080 +#define BIOS_CTRL_NO_SCAM 0x0100 +#define BIOS_CTRL_RESET_SCSI_BUS 0x0200 +#define BIOS_CTRL_INIT_VERBOSE 0x0800 +#define BIOS_CTRL_SCSI_PARITY 0x1000 + +/* + * ASC 3550 Internal Memory Size - 8KB + */ +#define ADV_CONDOR_MEMSIZE 0x2000 /* 8 KB Internal Memory */ + +/* + * ASC 3550 I/O Length - 64 bytes + */ +#define ADV_CONDOR_IOLEN 0x40 /* I/O Port Range in bytes */ + +/* + * Byte I/O register address from base of 'iop_base'. + */ +#define IOPB_INTR_STATUS_REG 0x00 +#define IOPB_CHIP_ID_1 0x01 +#define IOPB_INTR_ENABLES 0x02 +#define IOPB_CHIP_TYPE_REV 0x03 +#define IOPB_RES_ADDR_4 0x04 +#define IOPB_RES_ADDR_5 0x05 +#define IOPB_RAM_DATA 0x06 +#define IOPB_RES_ADDR_7 0x07 +#define IOPB_FLAG_REG 0x08 +#define IOPB_RES_ADDR_9 0x09 +#define IOPB_RISC_CSR 0x0A +#define IOPB_RES_ADDR_B 0x0B +#define IOPB_RES_ADDR_C 0x0C +#define IOPB_RES_ADDR_D 0x0D +#define IOPB_RES_ADDR_E 0x0E +#define IOPB_RES_ADDR_F 0x0F +#define IOPB_MEM_CFG 0x10 +#define IOPB_RES_ADDR_11 0x11 +#define IOPB_RES_ADDR_12 0x12 +#define IOPB_RES_ADDR_13 0x13 +#define IOPB_FLASH_PAGE 0x14 +#define IOPB_RES_ADDR_15 0x15 +#define IOPB_RES_ADDR_16 0x16 +#define IOPB_RES_ADDR_17 0x17 +#define IOPB_FLASH_DATA 0x18 +#define IOPB_RES_ADDR_19 0x19 +#define IOPB_RES_ADDR_1A 0x1A +#define IOPB_RES_ADDR_1B 0x1B +#define IOPB_RES_ADDR_1C 0x1C +#define IOPB_RES_ADDR_1D 0x1D +#define IOPB_RES_ADDR_1E 0x1E +#define IOPB_RES_ADDR_1F 0x1F +#define IOPB_DMA_CFG0 0x20 +#define IOPB_DMA_CFG1 0x21 +#define IOPB_TICKLE 0x22 +#define IOPB_DMA_REG_WR 0x23 +#define IOPB_SDMA_STATUS 0x24 +#define IOPB_SCSI_BYTE_CNT 0x25 +#define IOPB_HOST_BYTE_CNT 0x26 +#define IOPB_BYTE_LEFT_TO_XFER 0x27 +#define IOPB_BYTE_TO_XFER_0 0x28 +#define IOPB_BYTE_TO_XFER_1 0x29 +#define IOPB_BYTE_TO_XFER_2 0x2A +#define IOPB_BYTE_TO_XFER_3 0x2B +#define IOPB_ACC_GRP 0x2C +#define IOPB_RES_ADDR_2D 0x2D +#define IOPB_DEV_ID 0x2E +#define IOPB_RES_ADDR_2F 0x2F +#define IOPB_SCSI_DATA 0x30 +#define IOPB_RES_ADDR_31 0x31 +#define IOPB_RES_ADDR_32 0x32 +#define IOPB_SCSI_DATA_HSHK 0x33 +#define IOPB_SCSI_CTRL 0x34 +#define IOPB_RES_ADDR_35 0x35 +#define IOPB_RES_ADDR_36 0x36 +#define IOPB_RES_ADDR_37 0x37 +#define IOPB_RES_ADDR_38 0x38 +#define IOPB_RES_ADDR_39 0x39 +#define IOPB_RES_ADDR_3A 0x3A +#define IOPB_RES_ADDR_3B 0x3B +#define IOPB_RFIFO_CNT 0x3C +#define IOPB_RES_ADDR_3D 0x3D +#define IOPB_RES_ADDR_3E 0x3E +#define IOPB_RES_ADDR_3F 0x3F + +/* + * Word I/O register address from base of 'iop_base'. + */ +#define IOPW_CHIP_ID_0 0x00 /* CID0 */ +#define IOPW_CTRL_REG 0x02 /* CC */ +#define IOPW_RAM_ADDR 0x04 /* LA */ +#define IOPW_RAM_DATA 0x06 /* LD */ +#define IOPW_RES_ADDR_08 0x08 +#define IOPW_RISC_CSR 0x0A /* CSR */ +#define IOPW_SCSI_CFG0 0x0C /* CFG0 */ +#define IOPW_SCSI_CFG1 0x0E /* CFG1 */ +#define IOPW_RES_ADDR_10 0x10 +#define IOPW_SEL_MASK 0x12 /* SM */ +#define IOPW_RES_ADDR_14 0x14 +#define IOPW_FLASH_ADDR 0x16 /* FA */ +#define IOPW_RES_ADDR_18 0x18 +#define IOPW_EE_CMD 0x1A /* EC */ +#define IOPW_EE_DATA 0x1C /* ED */ +#define IOPW_SFIFO_CNT 0x1E /* SFC */ +#define IOPW_RES_ADDR_20 0x20 +#define IOPW_Q_BASE 0x22 /* QB */ +#define IOPW_QP 0x24 /* QP */ +#define IOPW_IX 0x26 /* IX */ +#define IOPW_SP 0x28 /* SP */ +#define IOPW_PC 0x2A /* PC */ +#define IOPW_RES_ADDR_2C 0x2C +#define IOPW_RES_ADDR_2E 0x2E +#define IOPW_SCSI_DATA 0x30 /* SD */ +#define IOPW_SCSI_DATA_HSHK 0x32 /* SDH */ +#define IOPW_SCSI_CTRL 0x34 /* SC */ +#define IOPW_HSHK_CFG 0x36 /* HCFG */ +#define IOPW_SXFR_STATUS 0x36 /* SXS */ +#define IOPW_SXFR_CNTL 0x38 /* SXL */ +#define IOPW_SXFR_CNTH 0x3A /* SXH */ +#define IOPW_RES_ADDR_3C 0x3C +#define IOPW_RFIFO_DATA 0x3E /* RFD */ + +/* + * Doubleword I/O register address from base of 'iop_base'. + */ +#define IOPDW_RES_ADDR_0 0x00 +#define IOPDW_RAM_DATA 0x04 +#define IOPDW_RES_ADDR_8 0x08 +#define IOPDW_RES_ADDR_C 0x0C +#define IOPDW_RES_ADDR_10 0x10 +#define IOPDW_RES_ADDR_14 0x14 +#define IOPDW_RES_ADDR_18 0x18 +#define IOPDW_RES_ADDR_1C 0x1C +#define IOPDW_SDMA_ADDR0 0x20 +#define IOPDW_SDMA_ADDR1 0x24 +#define IOPDW_SDMA_COUNT 0x28 +#define IOPDW_SDMA_ERROR 0x2C +#define IOPDW_RDMA_ADDR0 0x30 +#define IOPDW_RDMA_ADDR1 0x34 +#define IOPDW_RDMA_COUNT 0x38 +#define IOPDW_RDMA_ERROR 0x3C + +#define ADV_CHIP_ID_BYTE 0x25 +#define ADV_CHIP_ID_WORD 0x04C1 + +#define ADV_SC_SCSI_BUS_RESET 0x2000 + +#define ADV_INTR_ENABLE_HOST_INTR 0x01 +#define ADV_INTR_ENABLE_SEL_INTR 0x02 +#define ADV_INTR_ENABLE_DPR_INTR 0x04 +#define ADV_INTR_ENABLE_RTA_INTR 0x08 +#define ADV_INTR_ENABLE_RMA_INTR 0x10 +#define ADV_INTR_ENABLE_RST_INTR 0x20 +#define ADV_INTR_ENABLE_DPE_INTR 0x40 +#define ADV_INTR_ENABLE_GLOBAL_INTR 0x80 + +#define ADV_INTR_STATUS_INTRA 0x01 +#define ADV_INTR_STATUS_INTRB 0x02 +#define ADV_INTR_STATUS_INTRC 0x04 + +#define ADV_RISC_CSR_STOP (0x0000) +#define ADV_RISC_TEST_COND (0x2000) +#define ADV_RISC_CSR_RUN (0x4000) +#define ADV_RISC_CSR_SINGLE_STEP (0x8000) + +#define ADV_CTRL_REG_HOST_INTR 0x0100 +#define ADV_CTRL_REG_SEL_INTR 0x0200 +#define ADV_CTRL_REG_DPR_INTR 0x0400 +#define ADV_CTRL_REG_RTA_INTR 0x0800 +#define ADV_CTRL_REG_RMA_INTR 0x1000 +#define ADV_CTRL_REG_RES_BIT14 0x2000 +#define ADV_CTRL_REG_DPE_INTR 0x4000 +#define ADV_CTRL_REG_POWER_DONE 0x8000 +#define ADV_CTRL_REG_ANY_INTR 0xFF00 + +#define ADV_CTRL_REG_CMD_RESET 0x00C6 +#define ADV_CTRL_REG_CMD_WR_IO_REG 0x00C5 +#define ADV_CTRL_REG_CMD_RD_IO_REG 0x00C4 +#define ADV_CTRL_REG_CMD_WR_PCI_CFG_SPACE 0x00C3 +#define ADV_CTRL_REG_CMD_RD_PCI_CFG_SPACE 0x00C2 + +#define ADV_SCSI_CTRL_RSTOUT 0x2000 + +#define AdvIsIntPending(port) \ + (AdvReadWordRegister(port, IOPW_CTRL_REG) & ADV_CTRL_REG_HOST_INTR) + +/* + * SCSI_CFG0 Register bit definitions + */ +#define TIMER_MODEAB 0xC000 /* Watchdog, Second, and Select. Timer Ctrl. */ +#define PARITY_EN 0x2000 /* Enable SCSI Parity Error detection */ +#define EVEN_PARITY 0x1000 /* Select Even Parity */ +#define WD_LONG 0x0800 /* Watchdog Interval, 1: 57 min, 0: 13 sec */ +#define QUEUE_128 0x0400 /* Queue Size, 1: 128 byte, 0: 64 byte */ +#define PRIM_MODE 0x0100 /* Primitive SCSI mode */ +#define SCAM_EN 0x0080 /* Enable SCAM selection */ +#define SEL_TMO_LONG 0x0040 /* Sel/Resel Timeout, 1: 400 ms, 0: 1.6 ms */ +#define CFRM_ID 0x0020 /* SCAM id sel. confirm., 1: fast, 0: 6.4 ms */ +#define OUR_ID_EN 0x0010 /* Enable OUR_ID bits */ +#define OUR_ID 0x000F /* SCSI ID */ + +/* + * SCSI_CFG1 Register bit definitions + */ +#define BIG_ENDIAN 0x8000 /* Enable Big Endian Mode MIO:15, EEP:15 */ +#define TERM_POL 0x2000 /* Terminator Polarity Ctrl. MIO:13, EEP:13 */ +#define SLEW_RATE 0x1000 /* SCSI output buffer slew rate */ +#define FILTER_SEL 0x0C00 /* Filter Period Selection */ +#define FLTR_DISABLE 0x0000 /* Input Filtering Disabled */ +#define FLTR_11_TO_20NS 0x0800 /* Input Filtering 11ns to 20ns */ +#define FLTR_21_TO_39NS 0x0C00 /* Input Filtering 21ns to 39ns */ +#define ACTIVE_DBL 0x0200 /* Disable Active Negation */ +#define DIFF_MODE 0x0100 /* SCSI differential Mode (Read-Only) */ +#define DIFF_SENSE 0x0080 /* 1: No SE cables, 0: SE cable (Read-Only) */ +#define TERM_CTL_SEL 0x0040 /* Enable TERM_CTL_H and TERM_CTL_L */ +#define TERM_CTL 0x0030 /* External SCSI Termination Bits */ +#define TERM_CTL_H 0x0020 /* Enable External SCSI Upper Termination */ +#define TERM_CTL_L 0x0010 /* Enable External SCSI Lower Termination */ +#define CABLE_DETECT 0x000F /* External SCSI Cable Connection Status */ + +#define CABLE_ILLEGAL_A 0x7 + /* x 0 0 0 | on on | Illegal (all 3 connectors are used) */ + +#define CABLE_ILLEGAL_B 0xB + /* 0 x 0 0 | on on | Illegal (all 3 connectors are used) */ + +/* + The following table details the SCSI_CFG1 Termination Polarity, + Termination Control and Cable Detect bits. + + Cable Detect | Termination + Bit 3 2 1 0 | 5 4 | Notes + _____________|________|____________________ + 1 1 1 0 | on on | Internal wide only + 1 1 0 1 | on on | Internal narrow only + 1 0 1 1 | on on | External narrow only + 0 x 1 1 | on on | External wide only + 1 1 0 0 | on off| Internal wide and internal narrow + 1 0 1 0 | on off| Internal wide and external narrow + 0 x 1 0 | off off| Internal wide and external wide + 1 0 0 1 | on off| Internal narrow and external narrow + 0 x 0 1 | on off| Internal narrow and external wide + 1 1 1 1 | on on | No devices are attached + x 0 0 0 | on on | Illegal (all 3 connectors are used) + 0 x 0 0 | on on | Illegal (all 3 connectors are used) + + x means don't-care (either '0' or '1') + + If term_pol (bit 13) is '0' (active-low terminator enable), then: + 'on' is '0' and 'off' is '1'. + + If term_pol bit is '1' (meaning active-hi terminator enable), then: + 'on' is '1' and 'off' is '0'. + */ + +/* + * MEM_CFG Register bit definitions + */ +#define BIOS_EN 0x40 /* BIOS Enable MIO:14,EEP:14 */ +#define FAST_EE_CLK 0x20 /* Diagnostic Bit */ +#define RAM_SZ 0x1C /* Specify size of RAM to RISC */ +#define RAM_SZ_2KB 0x00 /* 2 KB */ +#define RAM_SZ_4KB 0x04 /* 4 KB */ +#define RAM_SZ_8KB 0x08 /* 8 KB */ +#define RAM_SZ_16KB 0x0C /* 16 KB */ +#define RAM_SZ_32KB 0x10 /* 32 KB */ +#define RAM_SZ_64KB 0x14 /* 64 KB */ + +/* + * DMA_CFG0 Register bit definitions + * + * This register is only accessible to the host. + */ +#define BC_THRESH_ENB 0x80 /* PCI DMA Start Conditions */ +#define FIFO_THRESH 0x70 /* PCI DMA FIFO Threshold */ +#define FIFO_THRESH_16B 0x00 /* 16 bytes */ +#define FIFO_THRESH_32B 0x20 /* 32 bytes */ +#define FIFO_THRESH_48B 0x30 /* 48 bytes */ +#define FIFO_THRESH_64B 0x40 /* 64 bytes */ +#define FIFO_THRESH_80B 0x50 /* 80 bytes (default) */ +#define FIFO_THRESH_96B 0x60 /* 96 bytes */ +#define FIFO_THRESH_112B 0x70 /* 112 bytes */ +#define START_CTL 0x0C /* DMA start conditions */ +#define START_CTL_TH 0x00 /* Wait threshold level (default) */ +#define START_CTL_ID 0x04 /* Wait SDMA/SBUS idle */ +#define START_CTL_THID 0x08 /* Wait threshold and SDMA/SBUS idle */ +#define START_CTL_EMFU 0x0C /* Wait SDMA FIFO empty/full */ +#define READ_CMD 0x03 /* Memory Read Method */ +#define READ_CMD_MR 0x00 /* Memory Read */ +#define READ_CMD_MRL 0x02 /* Memory Read Long */ +#define READ_CMD_MRM 0x03 /* Memory Read Multiple (default) */ + +/* a_advlib.h */ + +/* + * Adv Library Status Definitions + */ +#define ADV_TRUE 1 +#define ADV_FALSE 0 +#define ADV_NOERROR 1 +#define ADV_SUCCESS 1 +#define ADV_BUSY 0 +#define ADV_ERROR (-1) + + +/* + * ASC_DVC_VAR 'warn_code' values + */ +#define ASC_WARN_EEPROM_CHKSUM 0x0002 /* EEP check sum error */ +#define ASC_WARN_EEPROM_TERMINATION 0x0004 /* EEP termination bad field */ +#define ASC_WARN_SET_PCI_CONFIG_SPACE 0x0080 /* PCI config space set error */ +#define ASC_WARN_ERROR 0xFFFF /* ADV_ERROR return */ + +#define ADV_MAX_TID 15 /* max. target identifier */ +#define ADV_MAX_LUN 7 /* max. logical unit number */ + + +/* + * AscInitGetConfig() and AscInitAsc1000Driver() Definitions + * + * Error code values are set in ASC_DVC_VAR 'err_code'. + */ +#define ASC_IERR_WRITE_EEPROM 0x0001 /* write EEPROM error */ +#define ASC_IERR_MCODE_CHKSUM 0x0002 /* micro code check sum error */ +#define ASC_IERR_START_STOP_CHIP 0x0008 /* start/stop chip failed */ +#define ASC_IERR_CHIP_VERSION 0x0040 /* wrong chip version */ +#define ASC_IERR_SET_SCSI_ID 0x0080 /* set SCSI ID failed */ +#define ASC_IERR_BAD_SIGNATURE 0x0200 /* signature not found */ +#define ASC_IERR_ILLEGAL_CONNECTION 0x0400 /* Illegal cable connection */ +#define ASC_IERR_SINGLE_END_DEVICE 0x0800 /* Single-end used w/differential */ +#define ASC_IERR_REVERSED_CABLE 0x1000 /* Narrow flat cable reversed */ +#define ASC_IERR_RW_LRAM 0x8000 /* read/write local RAM error */ + +/* + * Fixed locations of microcode operating variables. + */ +#define ASC_MC_CODE_BEGIN_ADDR 0x0028 /* microcode start address */ +#define ASC_MC_CODE_END_ADDR 0x002A /* microcode end address */ +#define ASC_MC_CODE_CHK_SUM 0x002C /* microcode code checksum */ +#define ASC_MC_STACK_BEGIN 0x002E /* microcode stack begin */ +#define ASC_MC_STACK_END 0x0030 /* microcode stack end */ +#define ASC_MC_VERSION_DATE 0x0038 /* microcode version */ +#define ASC_MC_VERSION_NUM 0x003A /* microcode number */ +#define ASCV_VER_SERIAL_W 0x003C /* used in dos_init */ +#define ASC_MC_BIOSMEM 0x0040 /* BIOS RISC Memory Start */ +#define ASC_MC_BIOSLEN 0x0050 /* BIOS RISC Memory Length */ +#define ASC_MC_HALTCODE 0x0094 /* microcode halt code */ +#define ASC_MC_CALLERPC 0x0096 /* microcode halt caller PC */ +#define ASC_MC_ADAPTER_SCSI_ID 0x0098 /* one ID byte + reserved */ +#define ASC_MC_ULTRA_ABLE 0x009C +#define ASC_MC_SDTR_ABLE 0x009E +#define ASC_MC_TAGQNG_ABLE 0x00A0 +#define ASC_MC_DISC_ENABLE 0x00A2 +#define ASC_MC_IDLE_CMD 0x00A6 +#define ASC_MC_IDLE_PARA_STAT 0x00A8 +#define ASC_MC_DEFAULT_SCSI_CFG0 0x00AC +#define ASC_MC_DEFAULT_SCSI_CFG1 0x00AE +#define ASC_MC_DEFAULT_MEM_CFG 0x00B0 +#define ASC_MC_DEFAULT_SEL_MASK 0x00B2 +#define ASC_MC_RISC_NEXT_READY 0x00B4 +#define ASC_MC_RISC_NEXT_DONE 0x00B5 +#define ASC_MC_SDTR_DONE 0x00B6 +#define ASC_MC_NUMBER_OF_QUEUED_CMD 0x00C0 +#define ASC_MC_NUMBER_OF_MAX_CMD 0x00D0 +#define ASC_MC_DEVICE_HSHK_CFG_TABLE 0x0100 +#define ASC_MC_WDTR_ABLE 0x0120 /* Wide Transfer TID bitmask. */ +#define ASC_MC_CONTROL_FLAG 0x0122 /* Microcode control flag. */ +#define ASC_MC_WDTR_DONE 0x0124 +#define ASC_MC_HOST_NEXT_READY 0x0128 /* Host Next Ready RQL Entry. */ +#define ASC_MC_HOST_NEXT_DONE 0x0129 /* Host Next Done RQL Entry. */ + +/* + * BIOS LRAM variable absolute offsets. + */ +#define BIOS_CODESEG 0x54 +#define BIOS_CODELEN 0x56 +#define BIOS_SIGNATURE 0x58 +#define BIOS_VERSION 0x5A +#define BIOS_SIGNATURE 0x58 + +/* + * Microcode Control Flags + * + * Flags set by the Adv Library in RISC variable 'control_flag' (0x122) + * and handled by the microcode. + */ +#define CONTROL_FLAG_IGNORE_PERR 0x0001 /* Ignore DMA Parity Errors */ + +/* + * ASC_MC_DEVICE_HSHK_CFG_TABLE microcode table or HSHK_CFG register format + */ +#define HSHK_CFG_WIDE_XFR 0x8000 +#define HSHK_CFG_RATE 0x0F00 +#define HSHK_CFG_OFFSET 0x001F + +/* + * LRAM RISC Queue Lists (LRAM addresses 0x1200 - 0x19FF) + * + * Each of the 255 Adv Library/Microcode RISC queue lists or mailboxes + * starting at LRAM address 0x1200 is 8 bytes and has the following + * structure. Only 253 of these are actually used for command queues. + */ + +#define ASC_MC_RISC_Q_LIST_BASE 0x1200 +#define ASC_MC_RISC_Q_LIST_SIZE 0x0008 +#define ASC_MC_RISC_Q_TOTAL_CNT 0x00FF /* Num. queue slots in LRAM. */ +#define ASC_MC_RISC_Q_FIRST 0x0001 +#define ASC_MC_RISC_Q_LAST 0x00FF + +#define ASC_DEF_MAX_HOST_QNG 0xFD /* Max. number of host commands (253) */ +#define ASC_DEF_MIN_HOST_QNG 0x10 /* Min. number of host commands (16) */ +#define ASC_DEF_MAX_DVC_QNG 0x3F /* Max. number commands per device (63) */ +#define ASC_DEF_MIN_DVC_QNG 0x04 /* Min. number commands per device (4) */ + +/* RISC Queue List structure - 8 bytes */ +#define RQL_FWD 0 /* forward pointer (1 byte) */ +#define RQL_BWD 1 /* backward pointer (1 byte) */ +#define RQL_STATE 2 /* state byte - free, ready, done, aborted (1 byte) */ +#define RQL_TID 3 /* request target id (1 byte) */ +#define RQL_PHYADDR 4 /* request physical pointer (4 bytes) */ + +/* RISC Queue List state values */ +#define ASC_MC_QS_FREE 0x00 +#define ASC_MC_QS_READY 0x01 +#define ASC_MC_QS_DONE 0x40 +#define ASC_MC_QS_ABORTED 0x80 + +/* RISC Queue List pointer values */ +#define ASC_MC_NULL_Q 0x00 /* NULL_Q == 0 */ +#define ASC_MC_BIOS_Q 0xFF /* BIOS_Q = 255 */ + +/* ASC_SCSI_REQ_Q 'cntl' field values */ +#define ASC_MC_QC_START_MOTOR 0x02 /* Issue start motor. */ +#define ASC_MC_QC_NO_OVERRUN 0x04 /* Don't report overrun. */ +#define ASC_MC_QC_FIRST_DMA 0x08 /* Internal microcode flag. */ +#define ASC_MC_QC_ABORTED 0x10 /* Request aborted by host. */ +#define ASC_MC_QC_REQ_SENSE 0x20 /* Auto-Request Sense. */ +#define ASC_MC_QC_DOS_REQ 0x80 /* Request issued by DOS. */ + + +/* + * ASC_SCSI_REQ_Q 'a_flag' definitions + * + * The Adv Library should limit use to the lower nibble (4 bits) of + * a_flag. Drivers are free to use the upper nibble (4 bits) of a_flag. + */ +#define ADV_POLL_REQUEST 0x01 /* poll for request completion */ +#define ADV_SCSIQ_DONE 0x02 /* request done */ + +/* + * Adapter temporary configuration structure + * + * This structure can be discarded after initialization. Don't add + * fields here needed after initialization. + * + * Field naming convention: + * + * *_enable indicates the field enables or disables a feature. The + * value of the field is never reset. + */ +typedef struct adv_dvc_cfg { + ushort disc_enable; /* enable disconnection */ + uchar chip_version; /* chip version */ + uchar termination; /* Term. Ctrl. bits 6-5 of SCSI_CFG1 register */ + ushort pci_device_id; /* PCI device code number */ + ushort lib_version; /* Adv Library version number */ + ushort control_flag; /* Microcode Control Flag */ + ushort mcode_date; /* Microcode date */ + ushort mcode_version; /* Microcode version */ + ushort pci_slot_info; /* high byte device/function number */ + /* bits 7-3 device num., bits 2-0 function num. */ + /* low byte bus num. */ + ushort bios_boot_wait; /* BIOS boot time delay */ + ushort serial1; /* EEPROM serial number word 1 */ + ushort serial2; /* EEPROM serial number word 2 */ + ushort serial3; /* EEPROM serial number word 3 */ +} ADV_DVC_CFG; + +/* + * Adapter operation variable structure. + * + * One structure is required per host adapter. + * + * Field naming convention: + * + * *_able indicates both whether a feature should be enabled or disabled + * and whether a device isi capable of the feature. At initialization + * this field may be set, but later if a device is found to be incapable + * of the feature, the field is cleared. + */ +typedef struct adv_dvc_var { + AdvPortAddr iop_base; /* I/O port address */ + ushort err_code; /* fatal error code */ + ushort bios_ctrl; /* BIOS control word, EEPROM word 12 */ + Ptr2Func isr_callback; /* pointer to function, called in AdvISR() */ + Ptr2Func sbreset_callback; /* pointer to function, called in AdvISR() */ + ushort wdtr_able; /* try WDTR for a device */ + ushort sdtr_able; /* try SDTR for a device */ + ushort ultra_able; /* try SDTR Ultra speed for a device */ + ushort tagqng_able; /* try tagged queuing with a device */ + uchar max_dvc_qng; /* maximum number of tagged commands per device */ + ushort start_motor; /* start motor command allowed */ + uchar scsi_reset_wait; /* delay in seconds after scsi bus reset */ + uchar chip_no; /* should be assigned by caller */ + uchar max_host_qng; /* maximum number of Q'ed command allowed */ + uchar cur_host_qng; /* total number of queue command */ + uchar irq_no; /* IRQ number */ + ushort no_scam; /* scam_tolerant of EEPROM */ + ushort idle_cmd_done; /* microcode idle command done set by AdvISR() */ + ulong drv_ptr; /* driver pointer to private structure */ + uchar chip_scsi_id; /* chip SCSI target ID */ + /* + * Note: The following fields will not be used after initialization. The + * driver may discard the buffer after initialization is done. + */ + ADV_DVC_CFG *cfg; /* temporary configuration structure */ +} ADV_DVC_VAR; + +#define NO_OF_SG_PER_BLOCK 15 + +typedef struct asc_sg_block { + uchar reserved1; + uchar reserved2; + uchar first_entry_no; /* starting entry number */ + uchar last_entry_no; /* last entry number */ + struct asc_sg_block *sg_ptr; /* links to the next sg block */ + struct { + ulong sg_addr; /* SG element address */ + ulong sg_count; /* SG element count */ + } sg_list[NO_OF_SG_PER_BLOCK]; +} ADV_SG_BLOCK; + +/* + * ASC_SCSI_REQ_Q - microcode request structure + * + * All fields in this structure up to byte 60 are used by the microcode. + * The microcode makes assumptions about the size and ordering of fields + * in this structure. Do not change the structure definition here without + * coordinating the change with the microcode. + */ +typedef struct adv_scsi_req_q { + uchar cntl; /* Ucode flags and state (ASC_MC_QC_*). */ + uchar sg_entry_cnt; /* SG element count. Zero for no SG. */ + uchar target_id; /* Device target identifier. */ + uchar target_lun; /* Device target logical unit number. */ + ulong data_addr; /* Data buffer physical address. */ + ulong data_cnt; /* Data count. Ucode sets to residual. */ + ulong sense_addr; /* Sense buffer physical address. */ + ulong srb_ptr; /* Driver request pointer. */ + uchar a_flag; /* Adv Library flag field. */ + uchar sense_len; /* Auto-sense length. Ucode sets to residual. */ + uchar cdb_len; /* SCSI CDB length. */ + uchar tag_code; /* SCSI-2 Tag Queue Code: 00, 20-22. */ + uchar done_status; /* Completion status. */ + uchar scsi_status; /* SCSI status byte. */ + uchar host_status; /* Ucode host status. */ + uchar ux_sg_ix; /* Ucode working SG variable. */ + uchar cdb[12]; /* SCSI command block. */ + ulong sg_real_addr; /* SG list physical address. */ + struct adv_scsi_req_q *free_scsiq_link; + ulong ux_wk_data_cnt; /* Saved data count at disconnection. */ + struct adv_scsi_req_q *scsiq_ptr; + ADV_SG_BLOCK *sg_list_ptr; /* SG list virtual address. */ + /* + * End of microcode structure - 60 bytes. The rest of the structure + * is used by the Adv Library and ignored by the microcode. + */ + ulong vsense_addr; /* Sense buffer virtual address. */ + ulong vdata_addr; /* Data buffer virtual address. */ + uchar orig_sense_len; /* Original length of sense buffer. */ +} ADV_SCSI_REQ_Q; /* BIOS - 70 bytes, DOS - 76 bytes, W95, WNT - 69 bytes */ + +/* + * Microcode idle loop commands + */ +#define IDLE_CMD_COMPLETED 0 +#define IDLE_CMD_STOP_CHIP 0x0001 +#define IDLE_CMD_STOP_CHIP_SEND_INT 0x0002 +#define IDLE_CMD_SEND_INT 0x0004 +#define IDLE_CMD_ABORT 0x0008 +#define IDLE_CMD_DEVICE_RESET 0x0010 +#define IDLE_CMD_SCSI_RESET 0x0020 + +/* + * AdvSendIdleCmd() flag definitions. + */ +#define ADV_NOWAIT 0x01 + +/* + * Wait loop time out values. + */ +#define SCSI_WAIT_10_SEC 10 /* 10 seconds */ +#define SCSI_MS_PER_SEC 1000 /* milliseconds per second */ + +/* + * Device drivers must define the following functions. + */ +STATIC int DvcEnterCritical(void); +STATIC void DvcLeaveCritical(int); +STATIC void DvcSleepMilliSecond(ulong); +STATIC uchar DvcAdvReadPCIConfigByte(ADV_DVC_VAR *, ushort); +STATIC void DvcAdvWritePCIConfigByte(ADV_DVC_VAR *, ushort, uchar); +STATIC ulong DvcGetPhyAddr(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *, + uchar *, long *, int); +STATIC void DvcDelayMicroSecond(ADV_DVC_VAR *, ushort); + +/* + * Adv Library functions available to drivers. + */ +STATIC int AdvExeScsiQueue(ADV_DVC_VAR *, + ADV_SCSI_REQ_Q *); +STATIC int AdvISR(ADV_DVC_VAR *); +STATIC int AdvInitGetConfig(ADV_DVC_VAR *); +STATIC int AdvInitAsc3550Driver(ADV_DVC_VAR *); +STATIC int AdvResetSB(ADV_DVC_VAR *); + +/* + * Internal Adv Library functions. + */ +STATIC int AdvSendIdleCmd(ADV_DVC_VAR *, ushort, ulong, int); +STATIC void AdvResetChip(ADV_DVC_VAR *); +STATIC int AdvSendScsiCmd(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *); +STATIC void AdvInquiryHandling(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *); +STATIC int AdvInitFromEEP(ADV_DVC_VAR *); +STATIC ushort AdvGetEEPConfig(AdvPortAddr, ADVEEP_CONFIG *); +STATIC void AdvSetEEPConfig(AdvPortAddr, ADVEEP_CONFIG *); +STATIC void AdvWaitEEPCmd(AdvPortAddr); +STATIC ushort AdvReadEEPWord(AdvPortAddr, int); +STATIC void AdvResetSCSIBus(ADV_DVC_VAR *); + +/* + * PCI Bus Definitions + */ +#define AscPCICmdRegBits_BusMastering 0x0007 +#define AscPCICmdRegBits_ParErrRespCtrl 0x0040 + +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0) + +/* Read byte from a register. */ +#define AdvReadByteRegister(iop_base, reg_off) \ + (inp((iop_base) + (reg_off))) + +/* Write byte to a register. */ +#define AdvWriteByteRegister(iop_base, reg_off, byte) \ + (outp((iop_base) + (reg_off), (byte))) + +/* Read word (2 bytes) from a register. */ +#define AdvReadWordRegister(iop_base, reg_off) \ + (inpw((iop_base) + (reg_off))) + +/* Write word (2 bytes) to a register. */ +#define AdvWriteWordRegister(iop_base, reg_off, word) \ + (outpw((iop_base) + (reg_off), (word))) + +/* Read byte from LRAM. */ +#define AdvReadByteLram(iop_base, addr, byte) \ +do { \ + outpw((iop_base) + IOPW_RAM_ADDR, (addr)); \ + (byte) = inp((iop_base) + IOPB_RAM_DATA); \ +} while (0) + +/* Write byte to LRAM. */ +#define AdvWriteByteLram(iop_base, addr, byte) \ + (outpw((iop_base) + IOPW_RAM_ADDR, (addr)), \ + outp((iop_base) + IOPB_RAM_DATA, (byte))) + +/* Read word (2 bytes) from LRAM. */ +#define AdvReadWordLram(iop_base, addr, word) \ +do { \ + outpw((iop_base) + IOPW_RAM_ADDR, (addr)); \ + (word) = inpw((iop_base) + IOPW_RAM_DATA); \ +} while (0) + +/* Write word (2 bytes) to LRAM. */ +#define AdvWriteWordLram(iop_base, addr, word) \ + (outpw((iop_base) + IOPW_RAM_ADDR, (addr)), \ + outpw((iop_base) + IOPW_RAM_DATA, (word))) + +/* Write double word (4 bytes) to LRAM */ +/* Because of unspecified C language ordering don't use auto-increment. */ +#define AdvWriteDWordLram(iop_base, addr, dword) \ + ((outpw((iop_base) + IOPW_RAM_ADDR, (addr)), \ + outpw((iop_base) + IOPW_RAM_DATA, (ushort) ((dword) & 0xFFFF))), \ + (outpw((iop_base) + IOPW_RAM_ADDR, (addr) + 2), \ + outpw((iop_base) + IOPW_RAM_DATA, (ushort) ((dword >> 16) & 0xFFFF)))) + +/* Read word (2 bytes) from LRAM assuming that the address is already set. */ +#define AdvReadWordAutoIncLram(iop_base) \ + (inpw((iop_base) + IOPW_RAM_DATA)) + +/* Write word (2 bytes) to LRAM assuming that the address is already set. */ +#define AdvWriteWordAutoIncLram(iop_base, word) \ + (outpw((iop_base) + IOPW_RAM_DATA, (word))) + +#else /* version >= v1,3,0 */ + +/* Read byte from a register. */ +#define AdvReadByteRegister(iop_base, reg_off) \ + (ADV_MEM_READB((iop_base) + (reg_off))) + +/* Write byte to a register. */ +#define AdvWriteByteRegister(iop_base, reg_off, byte) \ + (ADV_MEM_WRITEB((iop_base) + (reg_off), (byte))) + +/* Read word (2 bytes) from a register. */ +#define AdvReadWordRegister(iop_base, reg_off) \ + (ADV_MEM_READW((iop_base) + (reg_off))) + +/* Write word (2 bytes) to a register. */ +#define AdvWriteWordRegister(iop_base, reg_off, word) \ + (ADV_MEM_WRITEW((iop_base) + (reg_off), (word))) + +/* Read byte from LRAM. */ +#define AdvReadByteLram(iop_base, addr, byte) \ +do { \ + ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)); \ + (byte) = ADV_MEM_READB((iop_base) + IOPB_RAM_DATA); \ +} while (0) + +/* Write byte to LRAM. */ +#define AdvWriteByteLram(iop_base, addr, byte) \ + (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)), \ + ADV_MEM_WRITEB((iop_base) + IOPB_RAM_DATA, (byte))) + +/* Read word (2 bytes) from LRAM. */ +#define AdvReadWordLram(iop_base, addr, word) \ +do { \ + ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)); \ + (word) = ADV_MEM_READW((iop_base) + IOPW_RAM_DATA); \ +} while (0) + +/* Write word (2 bytes) to LRAM. */ +#define AdvWriteWordLram(iop_base, addr, word) \ + (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)), \ + ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, (word))) + +/* Write double word (4 bytes) to LRAM */ +/* Because of unspecified C language ordering don't use auto-increment. */ +#define AdvWriteDWordLram(iop_base, addr, dword) \ + ((ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)), \ + ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, \ + (ushort) ((dword) & 0xFFFF))), \ + (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr) + 2), \ + ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, \ + (ushort) ((dword >> 16) & 0xFFFF)))) + +/* Read word (2 bytes) from LRAM assuming that the address is already set. */ +#define AdvReadWordAutoIncLram(iop_base) \ + (ADV_MEM_READW((iop_base) + IOPW_RAM_DATA)) + +/* Write word (2 bytes) to LRAM assuming that the address is already set. */ +#define AdvWriteWordAutoIncLram(iop_base, word) \ + (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, (word))) + +#endif /* version >= v1,3,0 */ + +/* + * Define macro to check for Condor signature. + * + * Evaluate to ADV_TRUE if a Condor chip is found the specified port + * address 'iop_base'. Otherwise evalue to ADV_FALSE. + */ +#define AdvFindSignature(iop_base) \ + (((AdvReadByteRegister((iop_base), IOPB_CHIP_ID_1) == \ + ADV_CHIP_ID_BYTE) && \ + (AdvReadWordRegister((iop_base), IOPW_CHIP_ID_0) == \ + ADV_CHIP_ID_WORD)) ? ADV_TRUE : ADV_FALSE) + +/* + * Define macro to Return the version number of the chip at 'iop_base'. + * + * The second parameter 'bus_type' is currently unused. + */ +#define AdvGetChipVersion(iop_base, bus_type) \ + AdvReadByteRegister((iop_base), IOPB_CHIP_TYPE_REV) + +/* + * Abort an SRB in the chip's RISC Memory. The 'srb_ptr' argument must + * match the ASC_SCSI_REQ_Q 'srb_ptr' field. + * + * If the request has not yet been sent to the device it will simply be + * aborted from RISC memory. If the request is disconnected it will be + * aborted on reselection by sending an Abort Message to the target ID. + * + * Return value: + * ADV_TRUE(1) - Queue was successfully aborted. + * ADV_FALSE(0) - Queue was not found on the active queue list. + */ +#define AdvAbortSRB(asc_dvc, srb_ptr) \ + AdvSendIdleCmd((asc_dvc), (ushort) IDLE_CMD_ABORT, \ + (ulong) (srb_ptr), 0) + +/* + * Send a Bus Device Reset Message to the specified target ID. + * + * All outstanding commands will be purged if sending the + * Bus Device Reset Message is successful. + * + * Return Value: + * ADV_TRUE(1) - All requests on the target are purged. + * ADV_FALSE(0) - Couldn't issue Bus Device Reset Message; Requests + * are not purged. + */ +#define AdvResetDevice(asc_dvc, target_id) \ + AdvSendIdleCmd((asc_dvc), (ushort) IDLE_CMD_DEVICE_RESET, \ + (ulong) (target_id), 0) + +/* + * SCSI Wide Type definition. + */ +#define ADV_SCSI_BIT_ID_TYPE ushort + +/* + * AdvInitScsiTarget() 'cntl_flag' options. + */ +#define ADV_SCAN_LUN 0x01 +#define ADV_CAPINFO_NOLUN 0x02 + +/* + * Convert target id to target id bit mask. + */ +#define ADV_TID_TO_TIDMASK(tid) (0x01 << ((tid) & ADV_MAX_TID)) + +/* + * ASC_SCSI_REQ_Q 'done_status' and 'host_status' return values. + */ + +#define QD_NO_STATUS 0x00 /* Request not completed yet. */ +#define QD_NO_ERROR 0x01 +#define QD_ABORTED_BY_HOST 0x02 +#define QD_WITH_ERROR 0x04 + +#define QHSTA_NO_ERROR 0x00 +#define QHSTA_M_SEL_TIMEOUT 0x11 +#define QHSTA_M_DATA_OVER_RUN 0x12 +#define QHSTA_M_UNEXPECTED_BUS_FREE 0x13 +#define QHSTA_M_QUEUE_ABORTED 0x15 +#define QHSTA_M_SXFR_SDMA_ERR 0x16 /* SXFR_STATUS SCSI DMA Error */ +#define QHSTA_M_SXFR_SXFR_PERR 0x17 /* SXFR_STATUS SCSI Bus Parity Error */ +#define QHSTA_M_RDMA_PERR 0x18 /* RISC PCI DMA parity error */ +#define QHSTA_M_SXFR_OFF_UFLW 0x19 /* SXFR_STATUS Offset Underflow */ +#define QHSTA_M_SXFR_OFF_OFLW 0x20 /* SXFR_STATUS Offset Overflow */ +#define QHSTA_M_SXFR_WD_TMO 0x21 /* SXFR_STATUS Watchdog Timeout */ +#define QHSTA_M_SXFR_DESELECTED 0x22 /* SXFR_STATUS Deselected */ +/* Note: QHSTA_M_SXFR_XFR_OFLW is identical to QHSTA_M_DATA_OVER_RUN. */ +#define QHSTA_M_SXFR_XFR_OFLW 0x12 /* SXFR_STATUS Transfer Overflow */ +#define QHSTA_M_SXFR_XFR_PH_ERR 0x24 /* SXFR_STATUS Transfer Phase Error */ +#define QHSTA_M_SXFR_UNKNOWN_ERROR 0x25 /* SXFR_STATUS Unknown Error */ +#define QHSTA_M_WTM_TIMEOUT 0x41 +#define QHSTA_M_BAD_CMPL_STATUS_IN 0x42 +#define QHSTA_M_NO_AUTO_REQ_SENSE 0x43 +#define QHSTA_M_AUTO_REQ_SENSE_FAIL 0x44 +#define QHSTA_M_INVALID_DEVICE 0x45 /* Bad target ID */ + +typedef int (* ADV_ISR_CALLBACK) + (ADV_DVC_VAR *, ADV_SCSI_REQ_Q *); + +typedef int (* ADV_SBRESET_CALLBACK) + (ADV_DVC_VAR *); + +/* + * Default EEPROM Configuration structure defined in a_init.c. + */ +extern ADVEEP_CONFIG Default_EEPROM_Config; + +/* + * DvcGetPhyAddr() flag arguments + */ +#define ADV_IS_SCSIQ_FLAG 0x01 /* 'addr' is ASC_SCSI_REQ_Q pointer */ +#define ADV_ASCGETSGLIST_VADDR 0x02 /* 'addr' is AscGetSGList() virtual addr */ +#define ADV_IS_SENSE_FLAG 0x04 /* 'addr' is sense virtual pointer */ +#define ADV_IS_DATA_FLAG 0x08 /* 'addr' is data virtual pointer */ +#define ADV_IS_SGLIST_FLAG 0x10 /* 'addr' is sglist virtual pointer */ + +/* 'IS_SCSIQ_FLAG is now obsolete; Instead use ADV_IS_SCSIQ_FLAG. */ +#define IS_SCSIQ_FLAG ADV_IS_SCSIQ_FLAQ + + +/* Return the address that is aligned at the next doubleword >= to 'addr'. */ +#define ADV_DWALIGN(addr) (((ulong) (addr) + 0x3) & ~0x3) + +/* + * Total contiguous memory needed for driver SG blocks. + * + * ADV_MAX_SG_LIST must be defined by a driver. It is the maximum + * number of scatter-gather elements the driver supports in a + * single request. + */ + +#ifndef ADV_MAX_SG_LIST +Forced Error: Driver must define ADV_MAX_SG_LIST. +#endif /* ADV_MAX_SG_LIST */ + +#define ADV_SG_LIST_MAX_BYTE_SIZE \ + (sizeof(ADV_SG_BLOCK) * \ + ((ADV_MAX_SG_LIST + (NO_OF_SG_PER_BLOCK - 1))/NO_OF_SG_PER_BLOCK)) + +/* + * A driver may optionally define the assertion macro ADV_ASSERT() in + * its d_os_dep.h file. If the macro has not already been defined, + * then define the macro to a no-op. + */ +#ifndef ADV_ASSERT +#define ADV_ASSERT(a) +#endif /* ADV_ASSERT */ + + +/* * --- Driver Constants and Macros */ -#define ASC_NUM_BOARD_SUPPORTED 4 +#define ASC_NUM_BOARD_SUPPORTED 16 +#define ASC_NUM_IOPORT_PROBE 4 #define ASC_NUM_BUS 4 /* Reference Scsi_Host hostdata */ @@ -2155,22 +3192,27 @@ /* asc_board_t flags */ #define ASC_HOST_IN_RESET 0x01 #define ASC_HOST_IN_ABORT 0x02 +#define ASC_IS_WIDE_BOARD 0x04 /* AdvanSys Wide Board */ +#define ASC_SELECT_QUEUE_DEPTHS 0x08 + +#define ASC_NARROW_BOARD(boardp) (((boardp)->flags & ASC_IS_WIDE_BOARD) == 0) +#define ASC_WIDE_BOARD(boardp) ((boardp)->flags & ASC_IS_WIDE_BOARD) #define NO_ISA_DMA 0xff /* No ISA DMA Channel Used */ /* - * If the Linux kernel version supports throwing away initialization code + * If the Linux kernel version supports freeing initialization code * and data after loading, define macros for this purpose. These macros * are not used when the driver is built as a module, cf. linux/init.h. */ -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,23) -#define ASC_INITFUNC(func) __initfunc(func) -#define ASC_INITDATA __initdata -#define ASC_INIT __init -#else /* version >= v2.1.23 */ +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,23) #define ASC_INITFUNC(func) func #define ASC_INITDATA #define ASC_INIT +#else /* version >= v2.1.23 */ +#define ASC_INITFUNC(func) __initfunc(func) +#define ASC_INITDATA __initdata +#define ASC_INIT __init #endif /* version >= v2.1.23 */ #define ASC_INFO_SIZE 128 /* advansys_info() line size */ @@ -2216,11 +3258,11 @@ * REQTIMESTAMP() - system time stamp value */ typedef Scsi_Cmnd REQ, *REQP; -#define REQPNEXT(reqp) ((REQP) ((reqp)->host_scribble)) -#define REQPNEXTP(reqp) ((REQP *) &((reqp)->host_scribble)) +#define REQPNEXT(reqp) ((REQP) ((reqp)->host_scribble)) +#define REQPNEXTP(reqp) ((REQP *) &((reqp)->host_scribble)) #define REQPTID(reqp) ((reqp)->target) -#define REQPTIME(reqp) ((reqp)->SCp.this_residual) -#define REQTIMESTAMP() (jiffies) +#define REQPTIME(reqp) ((reqp)->SCp.this_residual) +#define REQTIMESTAMP() (jiffies) #define REQTIMESTAT(function, ascq, reqp, tid) \ { \ @@ -2253,7 +3295,7 @@ } /* asc_enqueue() flags */ -#define ASC_FRONT 1 +#define ASC_FRONT 1 #define ASC_BACK 2 /* asc_dequeue_list() argument */ @@ -2316,6 +3358,7 @@ #define ASC_PCI_DEVICE_ID_1100 0x1100 #define ASC_PCI_DEVICE_ID_1200 0x1200 #define ASC_PCI_DEVICE_ID_1300 0x1300 +#define ASC_PCI_DEVICE_ID_2300 0x2300 /* PCI IO Port Addresses to generate special cycle */ @@ -2397,8 +3440,10 @@ #define ASC_DBG4(lvl, s, a1, a2, a3, a4) #define ASC_DBG_PRT_SCSI_HOST(lvl, s) #define ASC_DBG_PRT_SCSI_CMND(lvl, s) -#define ASC_DBG_PRT_SCSI_Q(lvl, scsiqp) -#define ASC_DBG_PRT_QDONE_INFO(lvl, qdone) +#define ASC_DBG_PRT_ASC_SCSI_Q(lvl, scsiqp) +#define ASC_DBG_PRT_ADV_SCSI_REQ_Q(lvl, scsiqp) +#define ASC_DBG_PRT_ASC_QDONE_INFO(lvl, qdone) +#define ADV_DBG_PRT_ADV_SCSI_REQ_Q(lvl, scsiqp) #define ASC_DBG_PRT_HEX(lvl, name, start, length) #define ASC_DBG_PRT_CDB(lvl, cdb, len) #define ASC_DBG_PRT_SENSE(lvl, sense, len) @@ -2462,17 +3507,24 @@ } \ } -#define ASC_DBG_PRT_SCSI_Q(lvl, scsiqp) \ +#define ASC_DBG_PRT_ASC_SCSI_Q(lvl, scsiqp) \ + { \ + if (asc_dbglvl >= (lvl)) { \ + asc_prt_asc_scsi_q(scsiqp); \ + } \ + } + +#define ASC_DBG_PRT_ASC_QDONE_INFO(lvl, qdone) \ { \ if (asc_dbglvl >= (lvl)) { \ - asc_prt_scsi_q(scsiqp); \ + asc_prt_asc_qdone_info(qdone); \ } \ } -#define ASC_DBG_PRT_QDONE_INFO(lvl, qdone) \ +#define ASC_DBG_PRT_ADV_SCSI_REQ_Q(lvl, scsiqp) \ { \ if (asc_dbglvl >= (lvl)) { \ - asc_prt_qdone_info(qdone); \ + asc_prt_adv_scsi_req_q(scsiqp); \ } \ } @@ -2522,15 +3574,17 @@ ulong abort; /* # calls to advansys_abort() */ ulong reset; /* # calls to advansys_reset() */ ulong biosparam; /* # calls to advansys_biosparam() */ - 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. */ - ulong asc_error; /* # AscExeScsiQueue() ASC_ERROR returns. */ - ulong asc_unknown; /* # AscExeScsiQueue() unknown returns. */ + ulong interrupt; /* # advansys_interrupt() calls */ + ulong callback; /* # calls to asc/adv_isr_callback() */ + ulong done; /* # calls to request's scsi_done function */ + ulong build_error; /* # asc/adv_build_req() ASC_ERROR returns. */ + ulong adv_build_noreq; /* # adv_build_req() adv_req_t alloc. fail. */ + ulong adv_build_nosg; /* # adv_build_req() adv_sgblk_t alloc. fail. */ + /* AscExeScsiQueue()/AdvExeScsiQueue() Statistics */ + ulong exe_noerror; /* # ASC_NOERROR returns. */ + ulong exe_busy; /* # ASC_BUSY returns. */ + ulong exe_error; /* # ASC_ERROR returns. */ + ulong exe_unknown; /* # unknown returns. */ /* Data Transfer Statistics */ ulong cont_cnt; /* # non-scatter-gather I/O requests received */ ulong cont_xfer; /* # contiguous transfer 512-bytes */ @@ -2544,20 +3598,49 @@ * Request queuing structure */ typedef struct asc_queue { - 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 */ + ADV_SCSI_BIT_ID_TYPE q_tidmask; /* queue mask */ + REQP q_first[ADV_MAX_TID+1]; /* first queued request */ + REQP q_last[ADV_MAX_TID+1]; /* last queued request */ #ifdef ADVANSYS_STATS - short q_cur_cnt[ASC_MAX_TID+1]; /* current queue count */ - short q_max_cnt[ASC_MAX_TID+1]; /* maximum queue count */ - ulong q_tot_cnt[ASC_MAX_TID+1]; /* total enqueue count */ - ulong q_tot_tim[ASC_MAX_TID+1]; /* total time queued */ - ushort q_max_tim[ASC_MAX_TID+1]; /* maximum time queued */ - ushort q_min_tim[ASC_MAX_TID+1]; /* minimum time queued */ + short q_cur_cnt[ADV_MAX_TID+1]; /* current queue count */ + short q_max_cnt[ADV_MAX_TID+1]; /* maximum queue count */ + ulong q_tot_cnt[ADV_MAX_TID+1]; /* total enqueue count */ + ulong q_tot_tim[ADV_MAX_TID+1]; /* total time queued */ + ushort q_max_tim[ADV_MAX_TID+1]; /* maximum time queued */ + ushort q_min_tim[ADV_MAX_TID+1]; /* minimum time queued */ #endif /* ADVANSYS_STATS */ } asc_queue_t; /* + * Adv Library Request Structures + * + * The following two se structures are used to process Wide Board requests. + * One structure is needed for each command received from the Mid-Level SCSI + * driver. + * + * The ADV_SCSI_REQ_Q structure in adv_req_t is passed to the Adv Library + * and microcode with the ADV_SCSI_REQ_Q field 'srb_ptr' pointing to the + * adv_req_t. The adv_req_t structure 'cmndp' field in turn points to the + * Mid-Level SCSI request structure. + * + * The adv_sgblk_t structure is used to handle requests that include + * scatter-gather elements. + */ +typedef struct adv_sgblk { + ADV_SG_BLOCK sg_block[ADV_NUM_SG_BLOCK + ADV_NUM_PAGE_CROSSING]; + uchar align2[4]; /* Sgblock structure padding. */ + struct adv_sgblk *next_sgblkp; /* Next scatter-gather structure. */ +} adv_sgblk_t; + +typedef struct adv_req { + ADV_SCSI_REQ_Q scsi_req_q; /* Adv Library request structure. */ + uchar align1[4]; /* Request structure padding. */ + Scsi_Cmnd *cmndp; /* Mid-Level SCSI command pointer. */ + adv_sgblk_t *sgblkp; /* Adv Library scatter-gather pointer. */ + struct adv_req *next_reqp; /* Next Request Structure. */ +} adv_req_t; + +/* * Structure allocated for each board. * * This structure is allocated by scsi_register() at the end @@ -2565,35 +3648,60 @@ * field. It is guaranteed to be allocated from DMA-able memory. */ 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_queue_t done; /* Done command queue */ - ASC_SCSI_BIT_ID_TYPE init_tidmask; /* Target initialized mask */ - /* The following three structures must be in DMA-able memory. */ - ASC_SCSI_REQ_Q scsireqq; - ASC_CAP_INFO cap_info; - ASC_SCSI_INQUIRY inquiry; - Scsi_Device *device[ASC_MAX_TID+1]; /* Mid-Level Scsi Device */ - ushort reqcnt[ASC_MAX_TID+1]; /* Starvation request count */ - uchar sdtr_data[ASC_MAX_TID+1]; /* SDTR information */ + int id; /* Board Id */ + uint flags; /* Board flags */ + union { + ASC_DVC_VAR asc_dvc_var; /* Narrow board */ + ADV_DVC_VAR adv_dvc_var; /* Wide board */ + } dvc_var; + union { + ASC_DVC_CFG asc_dvc_cfg; /* Narrow board */ + ADV_DVC_CFG adv_dvc_cfg; /* Wide board */ + } dvc_cfg; + asc_queue_t active; /* Active command queue */ + asc_queue_t waiting; /* Waiting command queue */ + asc_queue_t done; /* Done command queue */ + ADV_SCSI_BIT_ID_TYPE init_tidmask; /* Target init./valid mask */ + Scsi_Device *device[ADV_MAX_TID+1]; /* Mid-Level Scsi Device */ + ushort reqcnt[ADV_MAX_TID+1]; /* Starvation request count */ #if ASC_QUEUE_FLOW_CONTROL - ushort nerrcnt[ASC_MAX_TID+1]; /* No error request count */ + ushort nerrcnt[ADV_MAX_TID+1]; /* No error request count */ #endif /* ASC_QUEUE_FLOW_CONTROL */ - ASC_SCSI_BIT_ID_TYPE queue_full; /* Queue full mask */ - ushort queue_full_cnt[ASC_MAX_TID+1]; /* Queue full count */ - ASCEEP_CONFIG eep_config; /* EEPROM configuration */ - ulong last_reset; /* Saved last reset time */ + ADV_SCSI_BIT_ID_TYPE queue_full; /* Queue full mask */ + ushort queue_full_cnt[ADV_MAX_TID+1]; /* Queue full count */ + union { + ASCEEP_CONFIG asc_eep; /* Narrow EEPROM config. */ + ADVEEP_CONFIG adv_eep; /* Wide EEPROM config. */ + } eep_config; + ulong last_reset; /* Saved last reset time */ #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 */ + /* + * The following fields are used only for Narrow Boards. + */ + /* The following three structures must be in DMA-able memory. */ + ASC_SCSI_REQ_Q scsireqq; + ASC_CAP_INFO cap_info; + ASC_SCSI_INQUIRY inquiry; + uchar sdtr_data[ASC_MAX_TID+1]; /* SDTR information */ + /* + * The following fields are used only for Wide Boards. + */ + void *ioremap_addr; /* I/O Memory remap address. */ + ushort ioport; /* I/O Port address. */ + adv_req_t *orig_reqp; /* adv_req_t memory block. */ + adv_req_t *adv_reqp; /* Request structures. */ + adv_sgblk_t *orig_sgblkp; /* adv_sgblk_t memory block. */ + adv_sgblk_t *adv_sgblkp; /* Scatter-gather structures. */ + ushort bios_signature; /* BIOS Signature. */ + ushort bios_version; /* BIOS Version. */ + ushort bios_codeseg; /* BIOS Code Segment. */ + ushort bios_codelen; /* BIOS Code Segment Length. */ } asc_board_t; /* @@ -2655,10 +3763,10 @@ #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) struct proc_dir_entry proc_scsi_advansys = { - PROC_SCSI_ADVANSYS, /* unsigned short low_ino */ - 8, /* unsigned short namelen */ - "advansys", /* const char *name */ - S_IFDIR | S_IRUGO | S_IXUGO, /* mode_t mode */ + PROC_SCSI_ADVANSYS, /* unsigned short low_ino */ + 8, /* unsigned short namelen */ + "advansys", /* const char *name */ + S_IFDIR | S_IRUGO | S_IXUGO, /* mode_t mode */ 2 /* nlink_t nlink */ }; #endif /* version >= v1.3.0 */ @@ -2691,7 +3799,18 @@ * limit I/O port probing at boot time, cf. advansys_setup(). */ STATIC int asc_iopflag = ASC_FALSE; -STATIC int asc_ioport[ASC_NUM_BOARD_SUPPORTED] = { 0, 0, 0, 0 }; +STATIC int asc_ioport[ASC_NUM_IOPORT_PROBE] = { 0, 0, 0, 0 }; + +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0) +/* + * In kernels earlier than v1.3.0, kmalloc() does not work + * during driver initialization. Therefore statically declare + * 16 elements of each structure. v1.3.0 kernels will probably + * not need any more than this number. + */ +uchar adv_req_buf[16 * sizeof(adv_req_t)] = { 0 }; +uchar adv_sgblk_buf[16 * sizeof(adv_sgblk_t)] = { 0 }; +#endif /* version >= v1,3,0 */ #ifdef ADVANSYS_DEBUG STATIC char * @@ -2727,47 +3846,59 @@ STATIC void advansys_select_queue_depths(struct Scsi_Host *, Scsi_Device *); #endif /* version >= v1.3.89 */ -STATIC void advansys_command_done(Scsi_Cmnd *); -STATIC void asc_scsi_done_list(Scsi_Cmnd *); -STATIC int asc_execute_scsi_cmnd(Scsi_Cmnd *); -STATIC void asc_isr_callback(ASC_DVC_VAR *, ASC_QDONE_INFO *); -STATIC int asc_init_dev(ASC_DVC_VAR *, Scsi_Cmnd *); -STATIC int asc_srch_pci_dev(PCI_DEVICE *); -STATIC uchar asc_scan_method(void); -STATIC int asc_pci_find_dev(PCI_DEVICE *); -STATIC void asc_get_pci_cfg(PCI_DEVICE *, PCI_CONFIG_SPACE *); -STATIC ushort asc_get_cfg_word(PCI_DATA *); -STATIC uchar asc_get_cfg_byte(PCI_DATA *); -STATIC void asc_put_cfg_byte(PCI_DATA *, uchar); -STATIC void asc_enqueue(asc_queue_t *, REQP, int); -STATIC REQP asc_dequeue(asc_queue_t *, int); -STATIC REQP asc_dequeue_list(asc_queue_t *, REQP *, int); -STATIC int asc_rmqueue(asc_queue_t *, REQP); -STATIC int asc_isqueued(asc_queue_t *, REQP); -STATIC void asc_execute_queue(asc_queue_t *); +STATIC void advansys_command_done(Scsi_Cmnd *); +STATIC void asc_scsi_done_list(Scsi_Cmnd *); +STATIC int asc_execute_scsi_cmnd(Scsi_Cmnd *); +STATIC int asc_build_req(asc_board_t *, Scsi_Cmnd *); +STATIC int adv_build_req(asc_board_t *, Scsi_Cmnd *, ADV_SCSI_REQ_Q **); +STATIC int adv_get_sglist(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *, Scsi_Cmnd *); +STATIC void asc_isr_callback(ASC_DVC_VAR *, ASC_QDONE_INFO *); +STATIC void adv_isr_callback(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *); +STATIC int asc_init_dev(ASC_DVC_VAR *, Scsi_Cmnd *); +STATIC int asc_srch_pci_dev(PCI_DEVICE *); +STATIC uchar asc_scan_method(void); +STATIC int asc_pci_find_dev(PCI_DEVICE *); +STATIC void asc_get_pci_cfg(PCI_DEVICE *, PCI_CONFIG_SPACE *); +STATIC ushort asc_get_cfg_word(PCI_DATA *); +STATIC uchar asc_get_cfg_byte(PCI_DATA *); +STATIC void asc_put_cfg_byte(PCI_DATA *, uchar); +STATIC void asc_enqueue(asc_queue_t *, REQP, int); +STATIC REQP asc_dequeue(asc_queue_t *, int); +STATIC REQP asc_dequeue_list(asc_queue_t *, REQP *, int); +STATIC int asc_rmqueue(asc_queue_t *, REQP); +STATIC int asc_isqueued(asc_queue_t *, REQP); +STATIC void asc_execute_queue(asc_queue_t *); #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) -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_prt_line(char *, int, char *fmt, ...); +STATIC int asc_prt_board_devices(struct Scsi_Host *, char *, int); +STATIC int asc_prt_adv_bios(struct Scsi_Host *, char *, int); +STATIC int asc_get_eeprom_string(ushort *serialnum, uchar *cp); +STATIC int asc_prt_asc_board_eeprom(struct Scsi_Host *, char *, int); +STATIC int asc_prt_adv_board_eeprom(struct Scsi_Host *, char *, int); +STATIC int asc_prt_driver_conf(struct Scsi_Host *, char *, int); +STATIC int asc_prt_asc_board_info(struct Scsi_Host *, char *, int); +STATIC int asc_prt_adv_board_info(struct Scsi_Host *, char *, int); +STATIC int asc_prt_line(char *, int, char *fmt, ...); #endif /* version >= v1.3.0 */ /* Declaration for Asc Library internal functions reference by driver. */ -STATIC int AscFindSignature(PortAddr); -STATIC ushort AscGetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort); +STATIC int AscFindSignature(PortAddr); +STATIC ushort AscGetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort); #ifdef ADVANSYS_STATS -STATIC int asc_prt_board_stats(struct Scsi_Host *, char *, int); +STATIC int asc_prt_board_stats(struct Scsi_Host *, char *, int); #endif /* ADVANSYS_STATS */ #ifdef ADVANSYS_DEBUG STATIC void asc_prt_scsi_host(struct Scsi_Host *); STATIC void asc_prt_scsi_cmnd(Scsi_Cmnd *); -STATIC void asc_prt_dvc_cfg(ASC_DVC_CFG *); -STATIC void asc_prt_dvc_var(ASC_DVC_VAR *); -STATIC void asc_prt_scsi_q(ASC_SCSI_Q *); -STATIC void asc_prt_qdone_info(ASC_QDONE_INFO *); +STATIC void asc_prt_asc_dvc_cfg(ASC_DVC_CFG *); +STATIC void asc_prt_asc_dvc_var(ASC_DVC_VAR *); +STATIC void asc_prt_asc_scsi_q(ASC_SCSI_Q *); +STATIC void asc_prt_asc_qdone_info(ASC_QDONE_INFO *); +STATIC void asc_prt_adv_dvc_cfg(ADV_DVC_CFG *); +STATIC void asc_prt_adv_dvc_var(ADV_DVC_VAR *); +STATIC void asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *); +STATIC void asc_prt_adv_sgblock(int, ADV_SG_BLOCK *); STATIC void asc_prt_hex(char *f, uchar *, int); #endif /* ADVANSYS_DEBUG */ @@ -2815,7 +3946,7 @@ int leftlen; char *curbuf; off_t advoffset; - Scsi_Device *scd = NULL; + Scsi_Device *scd; ASC_DBG(1, "advansys_proc_info: begin\n"); @@ -2870,6 +4001,24 @@ curbuf += cnt; /* + * Display Wide Board BIOS Information. + */ + if (ASC_WIDE_BOARD(boardp)) { + cp = boardp->prtbuf; + cplen = asc_prt_adv_bios(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; + } + + /* * Display driver information for each device attached to the board. */ cp = boardp->prtbuf; @@ -2889,7 +4038,13 @@ * Display target driver information for each device attached * to the board. */ - for (scd = scd->host->host_queue; scd; scd = scd->next) { +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,75) + for (scd = scsi_devices; scd; scd = scd->next) +#else /* version >= v2.1.75 */ + for (scd = shp->host_queue; scd; scd = scd->next) +#endif /* version >= v2.1.75 */ + { + if (scd->host == shp) { cp = boardp->prtbuf; /* * Note: If proc_print_scsidevice() writes more than @@ -2906,13 +4061,18 @@ } advoffset += cplen; curbuf += cnt; + } } /* * Display EEPROM configuration for the board. */ cp = boardp->prtbuf; - cplen = asc_prt_board_eeprom(shp, cp, ASC_PRTBUF_SIZE); + if (ASC_NARROW_BOARD(boardp)) { + cplen = asc_prt_asc_board_eeprom(shp, cp, ASC_PRTBUF_SIZE); + } else { + cplen = asc_prt_adv_board_eeprom(shp, cp, ASC_PRTBUF_SIZE); + } ASC_ASSERT(cplen < ASC_PRTBUF_SIZE); cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen); totcnt += cnt; @@ -2963,7 +4123,11 @@ * for the board. */ cp = boardp->prtbuf; - cplen = asc_prt_board_info(shp, cp, ASC_PRTBUF_SIZE); + if (ASC_NARROW_BOARD(boardp)) { + cplen = asc_prt_asc_board_info(shp, cp, ASC_PRTBUF_SIZE); + } else { + cplen = asc_prt_adv_board_info(shp, cp, ASC_PRTBUF_SIZE); + } ASC_ASSERT(cplen < ASC_PRTBUF_SIZE); cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen); totcnt += cnt; @@ -2981,7 +4145,6 @@ } #endif /* version >= v1.3.0 */ - /* * advansys_detect() * @@ -3005,17 +4168,19 @@ int bus; struct Scsi_Host *shp; asc_board_t *boardp; - ASC_DVC_VAR *asc_dvc_varp; + ASC_DVC_VAR *asc_dvc_varp = NULL; + ADV_DVC_VAR *adv_dvc_varp = NULL; int ioport = 0; int share_irq = FALSE; PCI_DEVICE pciDevice; PCI_CONFIG_SPACE pciConfig; + int warn_code, err_code; int ret; if (detect_called == ASC_FALSE) { detect_called = ASC_TRUE; } else { - printk("AdvanSys SCSI: advansys_detect() mulitple calls ignored\n"); + printk("AdvanSys SCSI: advansys_detect() multiple calls ignored\n"); return 0; } @@ -3032,7 +4197,7 @@ * clean-up the 'asc_ioport' list. */ if (asc_iopflag == ASC_TRUE) { - for (ioport = 0; ioport < ASC_NUM_BOARD_SUPPORTED; ioport++) { + for (ioport = 0; ioport < ASC_NUM_IOPORT_PROBE; ioport++) { ASC_DBG2(1, "advansys_detect: asc_ioport[%d] %x\n", ioport, asc_ioport[ioport]); if (asc_ioport[ioport] != 0) { @@ -3042,7 +4207,8 @@ } } if (iop == ASC_IOADR_TABLE_MAX_IX) { - printk("AdvanSys SCSI: specified I/O Port 0x%X is invalid\n", + printk( +"AdvanSys SCSI: specified I/O Port 0x%X is invalid\n", asc_ioport[ioport]); asc_ioport[ioport] = 0; } @@ -3082,7 +4248,7 @@ ASC_DBG(1, "advansys_detect: I/O port scanning modified\n"); ioport_try_again: iop = 0; - for (; ioport < ASC_NUM_BOARD_SUPPORTED; ioport++) { + for (; ioport < ASC_NUM_IOPORT_PROBE; ioport++) { if ((iop = asc_ioport[ioport]) != 0) { break; } @@ -3091,12 +4257,14 @@ ASC_DBG1(1, "advansys_detect: probing I/O port %x...\n", iop); if (check_region(iop, ASC_IOADR_GAP) != 0) { - printk("AdvanSys SCSI: specified I/O Port 0x%X is busy\n", iop); + printk( +"AdvanSys SCSI: specified I/O Port 0x%X is busy\n", iop); /* Don't try this I/O port twice. */ asc_ioport[ioport] = 0; goto ioport_try_again; } else if (AscFindSignature(iop) == ASC_FALSE) { - printk("AdvanSys SCSI: specified I/O Port 0x%X has no adapter\n", iop); + printk( +"AdvanSys SCSI: specified I/O Port 0x%X has no adapter\n", iop); /* Don't try this I/O port twice. */ asc_ioport[ioport] = 0; goto ioport_try_again; @@ -3142,7 +4310,10 @@ pciDevice.slotFound, pciDevice.busNumber); asc_get_pci_cfg(&pciDevice, &pciConfig); iop = pciConfig.baseAddress[0] & PCI_IOADDRESS_MASK; - ASC_DBG2(2, "advansys_detect: iop %x, irqLine %d\n", + ASC_DBG2(1, + "advansys_detect: vendorID %X, deviceID %X\n", + pciConfig.vendorID, pciConfig.deviceID); + ASC_DBG2(2, "advansys_detect: iop %X, irqLine %d\n", iop, pciConfig.irqLine); } break; @@ -3177,13 +4348,76 @@ boardp = ASC_BOARDP(shp); memset(boardp, 0, sizeof(asc_board_t)); boardp->id = asc_board_count - 1; - asc_dvc_varp = &boardp->asc_dvc_var; - asc_dvc_varp->drv_ptr = (ulong) boardp; - asc_dvc_varp->cfg = &boardp->asc_dvc_cfg; - asc_dvc_varp->cfg->overrun_buf = &overrun_buf[0]; - asc_dvc_varp->iop_base = iop; + + /* + * Handle both narrow and wide PCI boards. + * + * If a Wide board was detected, set the board structure + * wide board flag. Set-up the board structure based on + * the board type. + */ + if ((asc_bus[bus] == ASC_IS_PCI && + pciConfig.deviceID == ASC_PCI_DEVICE_ID_2300) == 0) { + ASC_DBG(1, "advansys_detect: narrow board\n"); + asc_dvc_varp = &boardp->dvc_var.asc_dvc_var; + asc_dvc_varp->bus_type = asc_bus[bus]; + asc_dvc_varp->drv_ptr = (ulong) boardp; + asc_dvc_varp->cfg = &boardp->dvc_cfg.asc_dvc_cfg; + asc_dvc_varp->cfg->overrun_buf = &overrun_buf[0]; + asc_dvc_varp->iop_base = iop; + asc_dvc_varp->isr_callback = (Ptr2Func) asc_isr_callback; + } else { + ASC_DBG(1, "advansys_detect: wide board\n"); + boardp->flags |= ASC_IS_WIDE_BOARD; + adv_dvc_varp = &boardp->dvc_var.adv_dvc_var; + adv_dvc_varp->drv_ptr = (ulong) boardp; + adv_dvc_varp->cfg = &boardp->dvc_cfg.adv_dvc_cfg; + adv_dvc_varp->isr_callback = (Ptr2Func) adv_isr_callback; + +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0) + adv_dvc_varp->iop_base = iop; +#else /* version >= v1,3,0 */ + /* + * Map the board's registers into virtual memory for + * PCI slave access. Only memory accesses are used to + * access the board's registers. + * + * Note: The PCI register base address is not always + * page aligned, but the address passed to ioremap() + * must be page aligned. It is guaranteed that the + * PCI register base address will not cross a page + * boundary. + */ + if ((boardp->ioremap_addr = + ioremap(pciConfig.baseAddress[1] & PAGE_MASK, + PAGE_SIZE)) == 0) { + ASC_PRINT3( +"advansys_detect: board %d: ioremap(%lx, %d) returned NULL\n", + boardp->id, pciConfig.baseAddress[1], ADV_CONDOR_IOLEN); + scsi_unregister(shp); + asc_board_count--; + continue; + } + adv_dvc_varp->iop_base = (AdvPortAddr) + (boardp->ioremap_addr + + (pciConfig.baseAddress[1] - + (pciConfig.baseAddress[1] & PAGE_MASK))); +#endif /* version >= v1,3,0 */ + + /* + * Even though it isn't used to access the board in + * kernels greater than or equal to v1.3.0, save + * the I/O Port address so that it can be reported and + * displayed. + */ + boardp->ioport = iop; + } #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) + /* + * Allocate buffer for printing information from + * /proc/scsi/advansys/[0...]. + */ if ((boardp->prtbuf = kmalloc(ASC_PRTBUF_SIZE, GFP_ATOMIC)) == NULL) { ASC_PRINT3( @@ -3195,90 +4429,122 @@ } #endif /* version >= v1.3.0 */ - /* - * Set the board bus type and PCI IRQ for AscInitGetConfig(). - */ - asc_dvc_varp->bus_type = asc_bus[bus]; - switch (asc_dvc_varp->bus_type) { - case ASC_IS_ISA: - shp->unchecked_isa_dma = TRUE; - share_irq = FALSE; - break; - case ASC_IS_VL: - shp->unchecked_isa_dma = FALSE; - share_irq = FALSE; - break; - case ASC_IS_EISA: - shp->unchecked_isa_dma = FALSE; - share_irq = TRUE; - break; - case ASC_IS_PCI: - shp->irq = asc_dvc_varp->irq_no = pciConfig.irqLine; - asc_dvc_varp->cfg->pci_device_id = pciConfig.deviceID; - asc_dvc_varp->cfg->pci_slot_info = + if (ASC_NARROW_BOARD(boardp)) { + /* + * Set the board bus type and PCI IRQ before + * calling AscInitGetConfig(). + */ + switch (asc_dvc_varp->bus_type) { + case ASC_IS_ISA: + shp->unchecked_isa_dma = TRUE; + share_irq = FALSE; + break; + case ASC_IS_VL: + shp->unchecked_isa_dma = FALSE; + share_irq = FALSE; + break; + case ASC_IS_EISA: + shp->unchecked_isa_dma = FALSE; + share_irq = TRUE; + break; + case ASC_IS_PCI: + shp->irq = asc_dvc_varp->irq_no = pciConfig.irqLine; + shp->unchecked_isa_dma = FALSE; + share_irq = TRUE; + asc_dvc_varp->cfg->pci_device_id = pciConfig.deviceID; + asc_dvc_varp->cfg->pci_slot_info = ASC_PCI_MKID(pciDevice.busNumber, - pciDevice.slotFound, - pciDevice.devFunc); + pciDevice.slotFound, + pciDevice.devFunc); + break; + default: + ASC_PRINT2( +"advansys_detect: board %d: unknown adapter type: %d\n", + boardp->id, asc_dvc_varp->bus_type); + shp->unchecked_isa_dma = TRUE; + share_irq = FALSE; + break; + } + } else { + /* + * For Wide boards set PCI information before calling + * AdvInitGetConfig(). + */ + shp->irq = adv_dvc_varp->irq_no = pciConfig.irqLine; shp->unchecked_isa_dma = FALSE; share_irq = TRUE; - break; - default: - ASC_PRINT2( -"advansys_detect: board %d: unknown adapter type: %d", - boardp->id, asc_dvc_varp->bus_type); - shp->unchecked_isa_dma = TRUE; - share_irq = FALSE; - break; + adv_dvc_varp->cfg->pci_device_id = pciConfig.deviceID; + adv_dvc_varp->cfg->pci_slot_info = + ASC_PCI_MKID(pciDevice.busNumber, + pciDevice.slotFound, + pciDevice.devFunc); } /* - * Get the board configuration. - * - * NOTE: AscInitGetConfig() may change the board's bus_type - * value. The asc_bus[bus] value should no longer be used. If - * the bus_type field must be referenced only use the bit-wise - * AND operator "&". + * Read the board configuration. */ - ASC_DBG(2, "advansys_detect: AscInitGetConfig()\n"); - switch(ret = AscInitGetConfig(asc_dvc_varp)) { - case 0: /* No error */ - break; - case ASC_WARN_IO_PORT_ROTATE: - ASC_PRINT1( + if (ASC_NARROW_BOARD(boardp)) { + /* + * NOTE: AscInitGetConfig() may change the board's + * bus_type value. The asc_bus[bus] value should no + * longer be used. If the bus_type field must be + * referenced only use the bit-wise AND operator "&". + */ + ASC_DBG(2, "advansys_detect: AscInitGetConfig()\n"); + switch(ret = AscInitGetConfig(asc_dvc_varp)) { + case 0: /* No error */ + break; + case ASC_WARN_IO_PORT_ROTATE: + ASC_PRINT1( "AscInitGetConfig: board %d: I/O port address modified\n", - boardp->id); - break; - case ASC_WARN_AUTO_CONFIG: - ASC_PRINT1( + boardp->id); + break; + case ASC_WARN_AUTO_CONFIG: + ASC_PRINT1( "AscInitGetConfig: board %d: I/O port increment switch enabled\n", - boardp->id); - break; - case ASC_WARN_EEPROM_CHKSUM: - ASC_PRINT1( + boardp->id); + break; + case ASC_WARN_EEPROM_CHKSUM: + ASC_PRINT1( "AscInitGetConfig: board %d: EEPROM checksum error\n", - boardp->id); - break; - case ASC_WARN_IRQ_MODIFIED: - ASC_PRINT1( + boardp->id); + break; + case ASC_WARN_IRQ_MODIFIED: + ASC_PRINT1( "AscInitGetConfig: board %d: IRQ modified\n", - boardp->id); - break; - case ASC_WARN_CMD_QNG_CONFLICT: - ASC_PRINT1( + boardp->id); + break; + case ASC_WARN_CMD_QNG_CONFLICT: + ASC_PRINT1( "AscInitGetConfig: board %d: tag queuing enabled w/o disconnects\n", - boardp->id); - break; - default: - ASC_PRINT2( + boardp->id); + break; + default: + ASC_PRINT2( "AscInitGetConfig: board %d: unknown warning: %x\n", - boardp->id, ret); - break; - } - if (asc_dvc_varp->err_code != 0) { - ASC_PRINT3( + boardp->id, ret); + break; + } + if ((err_code = asc_dvc_varp->err_code) != 0) { + ASC_PRINT3( "AscInitGetConfig: board %d error: init_state %x, err_code %x\n", - boardp->id, asc_dvc_varp->init_state, - asc_dvc_varp->err_code); + boardp->id, asc_dvc_varp->init_state, + asc_dvc_varp->err_code); + } + } else { + ASC_DBG(2, "advansys_detect: AdvInitGetConfig()\n"); + if ((ret = AdvInitGetConfig(adv_dvc_varp)) != 0) { + ASC_PRINT2("AdvInitGetConfig: board %d: warning: %x\n", + boardp->id, ret); + } + if ((err_code = adv_dvc_varp->err_code) != 0) { + ASC_PRINT2( +"AdvInitGetConfig: board %d error: err_code %x\n", + boardp->id, adv_dvc_varp->err_code); + } + } + + if (err_code != 0) { #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) kfree(boardp->prtbuf); #endif /* version >= v1.3.0 */ @@ -3288,110 +4554,180 @@ } /* - * Set the adapter's target id bit in the init_tidmask field. + * Save the EEPROM configuration so that it can be displayed + * from /proc/scsi/advansys/[0...]. */ - boardp->init_tidmask |= - ASC_TIX_TO_TARGET_ID(asc_dvc_varp->cfg->chip_scsi_id); + if (ASC_NARROW_BOARD(boardp)) { - /* - * Save EEPROM settings for the board. - */ - boardp->eep_config.init_sdtr = asc_dvc_varp->init_sdtr; - boardp->eep_config.disc_enable = asc_dvc_varp->cfg->disc_enable; - boardp->eep_config.use_cmd_qng = asc_dvc_varp->cfg->cmd_qng_enabled; - boardp->eep_config.isa_dma_speed = asc_dvc_varp->cfg->isa_dma_speed; - boardp->eep_config.start_motor = asc_dvc_varp->start_motor; - boardp->eep_config.cntl = asc_dvc_varp->dvc_cntl; - boardp->eep_config.no_scam = asc_dvc_varp->no_scam; - boardp->eep_config.max_total_qng = asc_dvc_varp->max_total_qng; - boardp->eep_config.chip_scsi_id = asc_dvc_varp->cfg->chip_scsi_id; - /* 'max_tag_qng' is set to the same value for every device. */ - boardp->eep_config.max_tag_qng = asc_dvc_varp->cfg->max_tag_qng[0]; + ASCEEP_CONFIG *ep; - /* - * Modify board configuration. - */ - asc_dvc_varp->isr_callback = (Ptr2Func) asc_isr_callback; - asc_dvc_varp->exe_callback = (Ptr2Func) NULL; + /* + * Set the adapter's target id bit in the 'init_tidmask' field. + */ + boardp->init_tidmask |= + ADV_TID_TO_TIDMASK(asc_dvc_varp->cfg->chip_scsi_id); - ASC_DBG(2, "advansys_detect: AscInitSetConfig()\n"); - switch (ret = AscInitSetConfig(asc_dvc_varp)) { - case 0: /* No error. */ - break; - case ASC_WARN_IO_PORT_ROTATE: - ASC_PRINT1( + /* + * Save EEPROM settings for the board. + */ + ep = &boardp->eep_config.asc_eep; + + ep->init_sdtr = asc_dvc_varp->init_sdtr; + ep->disc_enable = asc_dvc_varp->cfg->disc_enable; + ep->use_cmd_qng = asc_dvc_varp->cfg->cmd_qng_enabled; + ep->isa_dma_speed = asc_dvc_varp->cfg->isa_dma_speed; + ep->start_motor = asc_dvc_varp->start_motor; + ep->cntl = asc_dvc_varp->dvc_cntl; + ep->no_scam = asc_dvc_varp->no_scam; + ep->max_total_qng = asc_dvc_varp->max_total_qng; + ep->chip_scsi_id = asc_dvc_varp->cfg->chip_scsi_id; + /* 'max_tag_qng' is set to the same value for every device. */ + ep->max_tag_qng = asc_dvc_varp->cfg->max_tag_qng[0]; + ep->adapter_info[0] = asc_dvc_varp->cfg->adapter_info[0]; + ep->adapter_info[1] = asc_dvc_varp->cfg->adapter_info[1]; + ep->adapter_info[2] = asc_dvc_varp->cfg->adapter_info[2]; + ep->adapter_info[3] = asc_dvc_varp->cfg->adapter_info[3]; + ep->adapter_info[4] = asc_dvc_varp->cfg->adapter_info[4]; + ep->adapter_info[5] = asc_dvc_varp->cfg->adapter_info[5]; + ep->adapter_info[6] = asc_dvc_varp->cfg->adapter_info[6]; + + /* + * Modify board configuration. + */ + ASC_DBG(2, "advansys_detect: AscInitSetConfig()\n"); + switch (ret = AscInitSetConfig(asc_dvc_varp)) { + case 0: /* No error. */ + break; + case ASC_WARN_IO_PORT_ROTATE: + ASC_PRINT1( "AscInitSetConfig: board %d: I/O port address modified\n", - boardp->id); - break; - case ASC_WARN_AUTO_CONFIG: - ASC_PRINT1( + boardp->id); + break; + case ASC_WARN_AUTO_CONFIG: + ASC_PRINT1( "AscInitSetConfig: board %d: I/O port increment switch enabled\n", - boardp->id); - break; - case ASC_WARN_EEPROM_CHKSUM: - ASC_PRINT1( + boardp->id); + break; + case ASC_WARN_EEPROM_CHKSUM: + ASC_PRINT1( "AscInitSetConfig: board %d: EEPROM checksum error\n", - boardp->id); - break; - case ASC_WARN_IRQ_MODIFIED: - ASC_PRINT1( + boardp->id); + break; + case ASC_WARN_IRQ_MODIFIED: + ASC_PRINT1( "AscInitSetConfig: board %d: IRQ modified\n", - boardp->id); - break; - case ASC_WARN_CMD_QNG_CONFLICT: - ASC_PRINT1( + boardp->id); + break; + case ASC_WARN_CMD_QNG_CONFLICT: + ASC_PRINT1( "AscInitSetConfig: board %d: tag queuing w/o disconnects\n", - boardp->id); - break; - default: - ASC_PRINT2( + boardp->id); + break; + default: + ASC_PRINT2( "AscInitSetConfig: board %d: unknown warning: %x\n", - boardp->id, ret); - break; - } - if (asc_dvc_varp->err_code != 0) { - ASC_PRINT3( + boardp->id, ret); + break; + } + if (asc_dvc_varp->err_code != 0) { + ASC_PRINT3( "AscInitSetConfig: board %d error: init_state %x, err_code %x\n", - boardp->id, asc_dvc_varp->init_state, - asc_dvc_varp->err_code); + boardp->id, asc_dvc_varp->init_state, + asc_dvc_varp->err_code); #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) - kfree(boardp->prtbuf); + kfree(boardp->prtbuf); #endif /* version >= v1.3.0 */ - scsi_unregister(shp); - asc_board_count--; - continue; - } + scsi_unregister(shp); + asc_board_count--; + continue; + } - /* - * Finish initializing the 'Scsi_Host' structure. - */ + /* + * Finish initializing the 'Scsi_Host' structure. + */ + /* AscInitSetConfig() will set the IRQ for non-PCI boards. */ + if ((asc_dvc_varp->bus_type & ASC_IS_PCI) == 0) { + shp->irq = asc_dvc_varp->irq_no; + } + } else { + + ADVEEP_CONFIG *ep; + + /* + * Save Wide EEP Configuration Information. + */ + ep = &boardp->eep_config.adv_eep; + + ep->adapter_scsi_id = adv_dvc_varp->chip_scsi_id; + ep->max_host_qng = adv_dvc_varp->max_host_qng; + ep->max_dvc_qng = adv_dvc_varp->max_dvc_qng; + ep->termination = adv_dvc_varp->cfg->termination; + ep->disc_enable = adv_dvc_varp->cfg->disc_enable; + ep->bios_ctrl = adv_dvc_varp->bios_ctrl; + ep->wdtr_able = adv_dvc_varp->wdtr_able; + ep->sdtr_able = adv_dvc_varp->sdtr_able; + ep->ultra_able = adv_dvc_varp->ultra_able; + ep->tagqng_able = adv_dvc_varp->tagqng_able; + ep->start_motor = adv_dvc_varp->start_motor; + ep->scsi_reset_delay = adv_dvc_varp->scsi_reset_wait; + ep->bios_boot_delay = adv_dvc_varp->cfg->bios_boot_wait; + ep->serial_number_word1 = adv_dvc_varp->cfg->serial1; + ep->serial_number_word2 = adv_dvc_varp->cfg->serial2; + ep->serial_number_word3 = adv_dvc_varp->cfg->serial3; + + /* + * Set the adapter's target id bit in the 'init_tidmask' field. + */ + boardp->init_tidmask |= + ADV_TID_TO_TIDMASK(adv_dvc_varp->chip_scsi_id); - /* AscInitSetConfig() will set the IRQ for non-PCI boards. */ - if ((asc_dvc_varp->bus_type & ASC_IS_PCI) == 0) { - shp->irq = asc_dvc_varp->irq_no; + /* + * Finish initializing the 'Scsi_Host' structure. + */ + shp->irq = adv_dvc_varp->irq_no; } +#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) /* - * One host supports one channel. There are two different - * hosts for each channel of a dual channel board. + * Channels are numbered beginning with 0. For AdvanSys One host + * structure supports one channel. Multi-channel boards have a + * separate host structure for each channel. */ -#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; + if (ASC_NARROW_BOARD(boardp)) { + 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; + + /* Set maximum number of queues the adapter can handle. */ + shp->can_queue = asc_dvc_varp->max_total_qng; + } else { + shp->max_id = ADV_MAX_TID + 1; + shp->max_lun = ADV_MAX_LUN + 1; + + /* + * Save the I/O Port address and length even though the + * in v1.3.0 and greater kernels the region is not used + * by a Wide board. Instead the board is accessed with + * Memory Mapped I/O. + */ + shp->io_port = iop; + shp->n_io_port = ADV_CONDOR_IOLEN; - 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; + shp->this_id = adv_dvc_varp->chip_scsi_id; - /* Maximum number of queues this adapter can handle. */ - shp->can_queue = asc_dvc_varp->max_total_qng; + /* Set maximum number of queues the adapter can handle. */ + shp->can_queue = adv_dvc_varp->max_host_qng; + } #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,89) /* - * Set a conservative 'cmd_per_lun' value to prevent memory - * allocation failures. + * In old kernels without tag queuing support and with memory + * allocation problems set a conservative 'cmd_per_lun' value. */ #ifdef MODULE shp->cmd_per_lun = 1; @@ -3401,54 +4737,54 @@ ASC_DBG1(1, "advansys_detect: cmd_per_lun: %d\n", shp->cmd_per_lun); #else /* version >= v1.3.89 */ /* - * Use the host 'select_queue_depths' function to determine - * the number of commands to queue per device. + * Following v1.3.89, 'cmd_per_lun' is no longer needed + * and should be set to zero. + * + * But because of a bug introduced in v1.3.89 if the driver is + * compiled as a module and 'cmd_per_lun' is zero, the Mid-Level + * SCSI function 'allocate_device' will panic. To allow the driver + * to work as a module in these kernels set 'cmd_per_lun' to 1. */ - shp->select_queue_depths = advansys_select_queue_depths; - #ifdef MODULE - /* - * FIXME(eric) - this is completely bogus. We need to - * figure out what exactly the real problem is and deal - * with it. - */ - /* - * Following v1.3.89, 'cmd_per_lun' is no longer needed - * and should be set to zero. But because of a bug introduced - * in v1.3.89 if the driver is compiled as a module and - * 'cmd_per_lun' is zero, the Mid-Level SCSI function - * 'scsi_allocate_device' will panic. To allow the driver to - * work as a module in these kernels set 'cmd_per_lun' to 1. - */ - shp->cmd_per_lun = 1; + shp->cmd_per_lun = 1; #else /* MODULE */ shp->cmd_per_lun = 0; #endif /* MODULE */ + /* + * Use the host 'select_queue_depths' function to determine + * the number of commands to queue per device. + */ + shp->select_queue_depths = advansys_select_queue_depths; #endif /* version >= v1.3.89 */ /* - * Set the maximum number of scatter-gather elements adapter - * can handle. + * Set the maximum number of scatter-gather elements the + * adapter can handle. */ + if (ASC_NARROW_BOARD(boardp)) { + /* + * 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; + } else { + shp->sg_tablesize = ADV_MAX_SG_LIST; + } #ifdef MODULE /* - * If the driver is compiled as a module, set a conservative + * If the driver is compiled as a module, set a limit on the * 'sg_tablesize' value to prevent memory allocation failures. * Memory allocation errors are more likely to occur at module * load time, then at driver initialization time. */ - shp->sg_tablesize = 8; -#else /* MODULE */ - /* - * 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; + if (shp->sg_tablesize > 64) { + shp->sg_tablesize = 64; + } #endif /* MODULE */ /* @@ -3465,52 +4801,96 @@ shp->sg_tablesize); /* BIOS start address. */ - shp->base = (char *) ((ulong) AscGetChipBiosAddress( + if (ASC_NARROW_BOARD(boardp)) { + shp->base = (char *) ((ulong) AscGetChipBiosAddress( asc_dvc_varp->iop_base, asc_dvc_varp->bus_type)); + } else { + /* + * Fill-in BIOS board variables. The Wide BIOS saves + * information in LRAM that is used by the driver. + */ + AdvReadWordLram(adv_dvc_varp->iop_base, BIOS_SIGNATURE, + boardp->bios_signature); + AdvReadWordLram(adv_dvc_varp->iop_base, BIOS_VERSION, + boardp->bios_version); + AdvReadWordLram(adv_dvc_varp->iop_base, BIOS_CODESEG, + boardp->bios_codeseg); + AdvReadWordLram(adv_dvc_varp->iop_base, BIOS_CODELEN, + boardp->bios_codelen); + + ASC_DBG2(1, + "advansys_detect: bios_signature %x, bios_version %x\n", + boardp->bios_signature, boardp->bios_version); + + ASC_DBG2(1, + "advansys_detect: bios_codeseg %x, bios_codelen %x\n", + boardp->bios_codeseg, boardp->bios_codelen); + + /* + * If the BIOS saved a valid signature, then fill in + * the BIOS code segment base address. + */ + if (boardp->bios_signature == 0x55AA) { + /* + * Convert x86 realmode code segment to a linear + * address by shifting left 4. + */ + shp->base = (uchar *) (boardp->bios_codeseg << 4); + } else { + shp->base = 0; + } + } /* * Register Board Resources - I/O Port, DMA, IRQ */ - /* Register I/O port range */ + /* Register I/O port range. */ ASC_DBG(2, "advansys_detect: request_region()\n"); request_region(shp->io_port, shp->n_io_port, "advansys"); - /* Register DMA channel for ISA bus. */ - if ((asc_dvc_varp->bus_type & ASC_IS_ISA) == 0) { - shp->dma_channel = NO_ISA_DMA; - } else { - shp->dma_channel = asc_dvc_varp->cfg->isa_dma_channel; - if ((ret = request_dma(shp->dma_channel, "advansys")) != 0) { - ASC_PRINT3( + /* Register DMA Channel for Narrow boards. */ + shp->dma_channel = NO_ISA_DMA; /* Default to no ISA DMA. */ + if (ASC_NARROW_BOARD(boardp)) { + /* Register DMA channel for ISA bus. */ + if (asc_dvc_varp->bus_type & ASC_IS_ISA) { + 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", - boardp->id, shp->dma_channel, ret); - release_region(shp->io_port, shp->n_io_port); + 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) - kfree(boardp->prtbuf); + kfree(boardp->prtbuf); #endif /* version >= v1.3.0 */ - scsi_unregister(shp); - asc_board_count--; - continue; + scsi_unregister(shp); + asc_board_count--; + continue; + } + AscEnableIsaDma(shp->dma_channel); } - AscEnableIsaDma(shp->dma_channel); } /* Register IRQ Number. */ ASC_DBG1(2, "advansys_detect: request_irq() %d\n", shp->irq); #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,70) if ((ret = request_irq(shp->irq, advansys_interrupt, - SA_INTERRUPT, "advansys")) != 0) { + SA_INTERRUPT, "advansys")) != 0) #else /* version >= v1.3.70 */ if ((ret = request_irq(shp->irq, advansys_interrupt, SA_INTERRUPT | (share_irq == TRUE ? SA_SHIRQ : 0), - "advansys", boardp)) != 0) { + "advansys", boardp)) != 0) #endif /* version >= v1.3.70 */ + { ASC_PRINT2( "advansys_detect: board %d: request_irq() failed %d\n", boardp->id, ret); release_region(shp->io_port, shp->n_io_port); +#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) + iounmap(boardp->ioremap_addr); +#endif /* version >= v1,3,0 */ if (shp->dma_channel != NO_ISA_DMA) { free_dma(shp->dma_channel); } @@ -3525,13 +4905,146 @@ /* * Initialize board RISC chip and enable interrupts. */ - 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", - boardp->id, asc_dvc_varp->init_state, - asc_dvc_varp->err_code); + if (ASC_NARROW_BOARD(boardp)) { + ASC_DBG(2, "advansys_detect: AscInitAsc1000Driver()\n"); + warn_code = AscInitAsc1000Driver(asc_dvc_varp); + err_code = asc_dvc_varp->err_code; + + if (warn_code || err_code) { + ASC_PRINT4( +"AscInitAsc1000Driver: board %d: error: init_state %x, warn %x error %x\n", + boardp->id, asc_dvc_varp->init_state, + warn_code, err_code); + } + } else { + int req_cnt; + adv_req_t *reqp = NULL; + int sg_cnt; + adv_sgblk_t *sgp = NULL; + +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0) + req_cnt = sizeof(adv_req_buf)/sizeof(adv_req_t); + sg_cnt = sizeof(adv_sgblk_buf)/sizeof(adv_sgblk_t); + reqp = (adv_req_t *) &adv_req_buf[0]; + sgp = (adv_sgblk_t *) &adv_sgblk_buf[0]; +#else /* version >= v1.3.0 */ + /* + * Allocate up to 'max_host_qng' request structures for + * the Wide board. + */ + for (req_cnt = adv_dvc_varp->max_host_qng; + req_cnt > 0; req_cnt--) { + + reqp = (adv_req_t *) + kmalloc(sizeof(adv_req_t) * req_cnt, GFP_ATOMIC); + + ASC_DBG3(1, + "advansys_detect: reqp %x, req_cnt %d, bytes %d\n", + (unsigned) reqp, req_cnt, sizeof(adv_req_t) * req_cnt); + + if (reqp != NULL) { + break; + } + } + + /* + * Allocate up to ADV_TOT_SG_LIST request structures for + * the Wide board. + */ + for (sg_cnt = ADV_TOT_SG_LIST; sg_cnt > 0; sg_cnt--) { + + sgp = (adv_sgblk_t *) + kmalloc(sizeof(adv_sgblk_t) * sg_cnt, GFP_ATOMIC); + + ASC_DBG3(1, + "advansys_detect: sgp %x, sg_cnt %d, bytes %d\n", + (unsigned) sgp, sg_cnt, sizeof(adv_sgblk_t) * sg_cnt); + + if (sgp != NULL) { + break; + } + } +#endif /* version >= v1.3.0 */ + + /* + * If no request structures or scatter-gather structures could + * be allocated, then return an error. Otherwise continue with + * initialization. + */ + if (reqp == NULL) { + ASC_PRINT1( +"advansys_detect: board %d: error: failed to kmalloc() adv_req_t buffer.\n", + boardp->id); + err_code = ADV_ERROR; + } else if (sgp == NULL) { + kfree(reqp); + ASC_PRINT1( +"advansys_detect: board %d: error: failed to kmalloc() adv_sgblk_t buffer.\n", + boardp->id); + err_code = ADV_ERROR; + } else { + + /* + * Save original pointer for kfree() in case the + * driver is built as a module and can be unloaded. + */ + boardp->orig_reqp = reqp; + + /* + * Point 'adv_reqp' to the request structures and + * link them together. + */ + req_cnt--; + reqp[req_cnt].next_reqp = NULL; + for (; req_cnt > 0; req_cnt--) { + reqp[req_cnt - 1].next_reqp = &reqp[req_cnt]; + } + boardp->adv_reqp = &reqp[0]; + + /* + * Save original pointer for kfree() in case the + * driver is built as a module and can be unloaded. + */ + boardp->orig_sgblkp = sgp; + + /* + * Point 'adv_sgblkp' to the request structures and + * link them together. + */ + sg_cnt--; + sgp[sg_cnt].next_sgblkp = NULL; + for (; sg_cnt > 0; sg_cnt--) { + sgp[sg_cnt - 1].next_sgblkp = &sgp[sg_cnt]; + } + boardp->adv_sgblkp = &sgp[0]; + + ASC_DBG(2, "advansys_detect: AdvInitAsc3550Driver()\n"); + warn_code = AdvInitAsc3550Driver(adv_dvc_varp); + err_code = adv_dvc_varp->err_code; + + if (warn_code || err_code) { + ASC_PRINT3( +"AdvInitAsc3550Driver: board %d: error: warn %x, error %x\n", + boardp->id, warn_code, adv_dvc_varp->err_code); + } + } + } + + if (err_code != 0) { release_region(shp->io_port, shp->n_io_port); + if (ASC_WIDE_BOARD(boardp)) { +#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) + iounmap(boardp->ioremap_addr); +#endif /* version >= v1,3,0 */ + if (boardp->orig_reqp) { + kfree(boardp->orig_reqp); + boardp->orig_reqp = boardp->adv_reqp = NULL; + } + if (boardp->orig_sgblkp) { + kfree(boardp->orig_sgblkp); + boardp->orig_sgblkp = boardp->adv_sgblkp = NULL; + } + } if (shp->dma_channel != NO_ISA_DMA) { free_dma(shp->dma_channel); } @@ -3576,6 +5089,19 @@ free_dma(shp->dma_channel); } release_region(shp->io_port, shp->n_io_port); + if (ASC_WIDE_BOARD(boardp)) { +#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) + iounmap(boardp->ioremap_addr); +#endif /* version >= v1,3,0 */ + if (boardp->orig_reqp) { + kfree(boardp->orig_reqp); + boardp->orig_reqp = boardp->adv_reqp = NULL; + } + if (boardp->orig_sgblkp) { + kfree(boardp->orig_sgblkp); + boardp->orig_sgblkp = boardp->adv_sgblkp = NULL; + } + } #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) ASC_ASSERT(boardp->prtbuf != NULL); kfree(boardp->prtbuf); @@ -3600,49 +5126,79 @@ static char info[ASC_INFO_SIZE]; asc_board_t *boardp; ASC_DVC_VAR *asc_dvc_varp; + ADV_DVC_VAR *adv_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"; + if (ASC_NARROW_BOARD(boardp)) { + asc_dvc_varp = &boardp->dvc_var.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: %s %u CDB: BIOS %X, IO %X/%X, IRQ %u, DMA %u", + ASC_VERSION, busname, asc_dvc_varp->max_total_qng, + (unsigned) shp->base, + shp->io_port, shp->n_io_port - 1, + shp->irq, shp->dma_channel); + } else if (asc_dvc_varp->bus_type & ASC_IS_PCI) { + if ((asc_dvc_varp->bus_type & ASC_IS_PCI_ULTRA) + == ASC_IS_PCI_ULTRA) { + busname = "PCI Ultra"; + } else { + busname = "PCI"; + } + sprintf(info, + "AdvanSys SCSI %s: %s %u CDB: IO %X/%X, IRQ %u", + ASC_VERSION, busname, asc_dvc_varp->max_total_qng, + shp->io_port, shp->n_io_port - 1, shp->irq); } else { - busname = "ISA"; + if (asc_dvc_varp->bus_type & ASC_IS_VL) { + busname = "VL"; + } else if (asc_dvc_varp->bus_type & ASC_IS_EISA) { + busname = "EISA"; + } else { + busname = "?"; + ASC_PRINT2( + "advansys_info: board %d: unknown bus type %d\n", + boardp->id, asc_dvc_varp->bus_type); + } + sprintf(info, + "AdvanSys SCSI %s: %s %u CDB: BIOS %X, IO %X/%X, IRQ %u", + ASC_VERSION, busname, asc_dvc_varp->max_total_qng, + (unsigned) shp->base, shp->io_port - 1, + shp->n_io_port, shp->irq); } - sprintf(info, - "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 if (asc_dvc_varp->bus_type & ASC_IS_PCI) { - if ((asc_dvc_varp->bus_type & ASC_IS_PCI_ULTRA) - == ASC_IS_PCI_ULTRA) { - busname = "PCI Ultra"; - } else { - busname = "PCI"; - } - sprintf(info, - "AdvanSys SCSI %s: %s %u CDB: IO %X-%X, IRQ %u", - ASC_VERSION, busname, boardp->asc_dvc_var.max_total_qng, - shp->io_port, shp->io_port + (shp->n_io_port - 1), shp->irq); - } else { - if (asc_dvc_varp->bus_type & ASC_IS_VL) { - busname = "VL"; - } else if (asc_dvc_varp->bus_type & ASC_IS_EISA) { - busname = "EISA"; + } else { + /* + * Wide Adapter Information + * + * Memory-mapped I/O is used instead of I/O space to access + * the adapter, but display the I/O Port range. The Memory + * I/O address is displayed through the driver /proc file. + */ + adv_dvc_varp = &boardp->dvc_var.adv_dvc_var; + if (boardp->bios_signature == 0x55AA) { + sprintf(info, +"AdvanSys SCSI %s: PCI Ultra-Wide: BIOS %X/%X, IO %X/%X, IRQ %u", + ASC_VERSION, + boardp->bios_codeseg << 4, + boardp->bios_codelen > 0 ? + (boardp->bios_codelen << 9) - 1 : 0, + (unsigned) boardp->ioport, ADV_CONDOR_IOLEN - 1, + shp->irq); } else { - busname = "?"; - ASC_PRINT2( -"advansys_info: board %d: unknown bus type %d\n", - boardp->id, asc_dvc_varp->bus_type); + sprintf(info, +"AdvanSys SCSI %s: PCI Ultra-Wide: IO %X/%X, IRQ %u", + ASC_VERSION, + (unsigned) boardp->ioport, + (ADV_CONDOR_IOLEN - 1), + shp->irq); } - sprintf(info, - "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); } ASC_ASSERT(strlen(info) < ASC_INFO_SIZE); ASC_DBG(1, "advansys_info: end\n"); @@ -3650,10 +5206,10 @@ } /* - * advansys_command() + * advansys_command() - polled I/O entrypoint. * - * Polled-I/O. Apparently host drivers shouldn't return until - * command is finished. + * Apparently host drivers shouldn't return until the command + * is finished. * * Note: This is an old interface that is no longer used by the SCSI * mid-level driver. The new interface, advansys_queuecommand(), @@ -3666,10 +5222,6 @@ ASC_STATS(scp->host, command); scp->SCp.Status = 0; /* Set to a known state */ advansys_queuecommand(scp, advansys_command_done); - /* - * XXX - Can host drivers block here instead of spinning on - * command status? - */ while (scp->SCp.Status == 0) { continue; } @@ -3678,7 +5230,7 @@ } /* - * advansys_queuecommand() + * advansys_queuecommand() - interrupt-driven I/O entrypoint. * * This function always returns 0. Command return status is saved * in the 'scp' result field. @@ -3782,6 +5334,7 @@ struct Scsi_Host *shp; asc_board_t *boardp; ASC_DVC_VAR *asc_dvc_varp; + ADV_DVC_VAR *adv_dvc_varp; int flags; int do_scsi_done; int scp_found; @@ -3842,10 +5395,10 @@ do_scsi_done = ASC_TRUE; if (asc_rmqueue(&boardp->waiting, scp) == ASC_TRUE) { /* - * If asc_rmqueue() found the command on the waiting + * 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_found = ASC_TRUE; @@ -3853,35 +5406,72 @@ ret = SCSI_ABORT_SUCCESS; } else if (asc_isqueued(&boardp->active, scp) == ASC_TRUE) { /* - * If asc_isqueued() found the command on the active + * If asc_isqueued() found the command on the active * 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); + * will be returned through the interrupt handler after + * it has been aborted. + */ - sti(); /* Enable interrupts for AscAbortSRB(). */ - ASC_DBG1(1, "advansys_abort: before AscAbortSRB(), scp %x\n", - (unsigned) scp); - switch (AscAbortSRB(asc_dvc_varp, (ulong) scp)) { - case ASC_TRUE: - /* asc_isr_callback() will be called */ - ASC_DBG(1, "advansys_abort: AscAbortSRB() TRUE\n"); - ret = SCSI_ABORT_PENDING; - break; - case ASC_FALSE: - /* Request has apparently already completed. */ - ASC_DBG(1, "advansys_abort: AscAbortSRB() FALSE\n"); - ret = SCSI_ABORT_NOT_RUNNING; - break; - case ASC_ERROR: - default: - ASC_DBG(1, "advansys_abort: AscAbortSRB() ERROR\n"); - ret = SCSI_ABORT_ERROR; - break; + if (ASC_NARROW_BOARD(boardp)) { + /* + * Narrow Board + */ + asc_dvc_varp = &boardp->dvc_var.asc_dvc_var; + scp->result = HOST_BYTE(DID_ABORT); + + sti(); /* Enable interrupts for AscAbortSRB(). */ + ASC_DBG1(1, "advansys_abort: before AscAbortSRB(), scp %x\n", + (unsigned) scp); + switch (AscAbortSRB(asc_dvc_varp, (ulong) scp)) { + case ASC_TRUE: + /* asc_isr_callback() will be called */ + ASC_DBG(1, "advansys_abort: AscAbortSRB() TRUE\n"); + ret = SCSI_ABORT_PENDING; + break; + case ASC_FALSE: + /* Request has apparently already completed. */ + ASC_DBG(1, "advansys_abort: AscAbortSRB() FALSE\n"); + ret = SCSI_ABORT_NOT_RUNNING; + break; + case ASC_ERROR: + default: + ASC_DBG(1, "advansys_abort: AscAbortSRB() ERROR\n"); + ret = SCSI_ABORT_ERROR; + break; + } + cli(); + } else { + /* + * Wide Board + */ + adv_dvc_varp = &boardp->dvc_var.adv_dvc_var; + scp->result = HOST_BYTE(DID_ABORT); + + ASC_DBG1(1, "advansys_abort: before AdvAbortSRB(), scp %x\n", + (unsigned) scp); + switch (AdvAbortSRB(adv_dvc_varp, (ulong) scp)) { + case ASC_TRUE: + /* asc_isr_callback() will be called */ + ASC_DBG(1, "advansys_abort: AdvAbortSRB() TRUE\n"); + ret = SCSI_ABORT_PENDING; + break; + case ASC_FALSE: + /* Request has apparently already completed. */ + ASC_DBG(1, "advansys_abort: AdvAbortSRB() FALSE\n"); + ret = SCSI_ABORT_NOT_RUNNING; + break; + case ASC_ERROR: + default: + ASC_DBG(1, "advansys_abort: AdvAbortSRB() ERROR\n"); + ret = SCSI_ABORT_ERROR; + break; + } + /* + * Ensure all requests completed by the microcode have + * been processed by calling AdvISR(). + */ + (void) AdvISR(adv_dvc_varp); } - cli(); /* * The request will either still be on the active queue @@ -3983,6 +5573,7 @@ struct Scsi_Host *shp; asc_board_t *boardp; ASC_DVC_VAR *asc_dvc_varp; + ADV_DVC_VAR *adv_dvc_varp; int flags; Scsi_Cmnd *done_scp = NULL, *last_scp = NULL; Scsi_Cmnd *tscp, *new_last_scp; @@ -3991,6 +5582,7 @@ int status; int target; int ret; + int device_reset = ASC_FALSE; /* Save current flags and disable interrupts. */ save_flags(flags); @@ -4056,8 +5648,6 @@ scp->result = HOST_BYTE(DID_ERROR); ret = SCSI_RESET_ERROR; } else { - int device_reset = ASC_FALSE; - do_scsi_done = ASC_TRUE; /* Set reset flag to avoid nested reset or abort requests. */ @@ -4080,83 +5670,166 @@ scp_found = ASC_FALSE; } - /* - * If the suggest reset bus flags are set, reset the bus. - * Otherwise only reset the device. - */ - asc_dvc_varp = &boardp->asc_dvc_var; -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) - if (reset_flags & - (SCSI_RESET_SUGGEST_BUS_RESET | SCSI_RESET_SUGGEST_HOST_RESET)) { -#endif /* version >= v1.3.89 */ + if (ASC_NARROW_BOARD(boardp)) { /* - * Reset the target's SCSI bus. + * Narrow Board + * + * If the suggest reset bus flags are set, then reset the bus. + * Otherwise only reset the device. */ - ASC_DBG(1, "advansys_reset: before AscResetSB()\n"); - sti(); /* Enable interrupts for AscResetSB(). */ - status = AscResetSB(asc_dvc_varp); - cli(); - switch (status) { - case ASC_TRUE: - ASC_DBG(1, "advansys_reset: AscResetSB() success\n"); - ret = SCSI_RESET_SUCCESS; - break; - case ASC_ERROR: - default: - ASC_DBG(1, "advansys_reset: AscResetSB() failed\n"); - ret = SCSI_RESET_ERROR; - break; - } - + asc_dvc_varp = &boardp->dvc_var.asc_dvc_var; #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) - } else { - /* - * Reset the specified device. If the device reset fails, - * then reset the SCSI bus. - */ - - 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(); - - /* - * If the device has been reset, try to initialize it. - */ - if (status == ASC_TRUE) { - status = asc_init_dev(asc_dvc_varp, scp); - } + if (reset_flags & + (SCSI_RESET_SUGGEST_BUS_RESET | + SCSI_RESET_SUGGEST_HOST_RESET)) { +#endif /* version >= v1.3.89 */ - 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"); + /* + * Reset the target's SCSI bus. + */ + ASC_DBG(1, "advansys_reset: before 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"); + 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; } - break; + +#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) + } else { + /* + * Reset the specified device. If the device reset fails, + * then reset the SCSI bus. + */ + + 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(); + + /* + * If the device has been reset, try to initialize it. + */ + 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 */ + } else { + /* + * Wide Board + * + * If the suggest reset bus flags are set, then reset the bus. + * Otherwise only reset the device. + */ + adv_dvc_varp = &boardp->dvc_var.adv_dvc_var; +#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) + if (reset_flags & + (SCSI_RESET_SUGGEST_BUS_RESET | + SCSI_RESET_SUGGEST_HOST_RESET)) { +#endif /* version >= v1.3.89 */ + + /* + * Reset the target's SCSI bus. + */ + ASC_DBG(1, "advansys_reset: before AdvResetSB()\n"); + switch (AdvResetSB(adv_dvc_varp)) { + case ASC_TRUE: + ASC_DBG(1, "advansys_reset: AdvResetSB() success\n"); + ret = SCSI_RESET_SUCCESS; + break; + case ASC_FALSE: + default: + ASC_DBG(1, "advansys_reset: AdvResetSB() failed\n"); + ret = SCSI_RESET_ERROR; + break; + } + /* + * Ensure all requests completed by the microcode have + * been processed by calling AdvISR(). + */ + (void) AdvISR(adv_dvc_varp); +#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) + } else { + /* + * Reset the specified device. If the device reset fails, + * then reset the SCSI bus. + */ + + ASC_DBG1(1, + "advansys_reset: before AdvResetDevice(), target %d\n", + scp->target); + + switch (AdvResetDevice(adv_dvc_varp, scp->target)) { + case ASC_TRUE: + ASC_DBG(1, "advansys_reset: AdvResetDevice() success\n"); + device_reset = ASC_TRUE; + ret = SCSI_RESET_SUCCESS; + break; + case ASC_FALSE: + default: + ASC_DBG(1, +"advansys_reset: AdvResetDevice() failed; Calling AdvResetSB()\n"); + + switch (AdvResetSB(adv_dvc_varp)) { + case ASC_TRUE: + ASC_DBG(1, "advansys_reset: AdvResetSB() TRUE\n"); + ret = SCSI_RESET_SUCCESS; + break; + case ASC_FALSE: + default: + ASC_DBG(1, "advansys_reset: AdvResetSB() ERROR\n"); + ret = SCSI_RESET_ERROR; + break; + } + break; + } + /* + * Ensure all requests completed by the microcode have + * been processed by calling AdvISR(). + */ + (void) AdvISR(adv_dvc_varp); } - } #endif /* version >= v1.3.89 */ + } /* * Because the ASC_HOST_IN_RESET flag causes both @@ -4299,15 +5972,29 @@ advansys_biosparam(Disk *dp, kdev_t dep, int ip[]) #endif /* version >= v1.3.0 */ { + asc_board_t *boardp; + ASC_DBG(1, "advansys_biosparam: begin\n"); ASC_STATS(dp->device->host, biosparam); - if ((ASC_BOARDP(dp->device->host)->asc_dvc_var.dvc_cntl & - ASC_CNTL_BIOS_GT_1GB) && dp->capacity > 0x200000) { - ip[0] = 255; - ip[1] = 63; + boardp = ASC_BOARDP(dp->device->host); + if (ASC_NARROW_BOARD(boardp)) { + if ((boardp->dvc_var.asc_dvc_var.dvc_cntl & + ASC_CNTL_BIOS_GT_1GB) && dp->capacity > 0x200000) { + ip[0] = 255; + ip[1] = 63; + } else { + ip[0] = 64; + ip[1] = 32; + } } else { - ip[0] = 64; - ip[1] = 32; + if ((boardp->dvc_var.adv_dvc_var.bios_ctrl & + BIOS_CTRL_EXTENDED_XLAT) && dp->capacity > 0x200000) { + ip[0] = 255; + ip[1] = 63; + } else { + ip[0] = 64; + ip[1] = 32; + } } ip[2] = dp->capacity / (ip[0] * ip[1]); ASC_DBG(1, "advansys_biosparam: end\n"); @@ -4328,7 +6015,7 @@ * only affects searching for ISA and VL boards. * * If ADVANSYS_DEBUG is defined the driver debug level may - * be set using the 5th (ASC_NUM_BOARD_SUPPORTED + 1) I/O Port. + * be set using the 5th (ASC_NUM_IOPORT_PROBE + 1) I/O Port. * * Examples: * 1. Eliminate I/O port scanning: @@ -4362,15 +6049,15 @@ asc_iopflag = ASC_TRUE; - if (ints[0] > ASC_NUM_BOARD_SUPPORTED) { + if (ints[0] > ASC_NUM_IOPORT_PROBE) { #ifdef ADVANSYS_DEBUG - if ((ints[0] == ASC_NUM_BOARD_SUPPORTED + 1) && - (ints[ASC_NUM_BOARD_SUPPORTED + 1] >> 4 == 0xdeb)) { - asc_dbglvl = ints[ASC_NUM_BOARD_SUPPORTED + 1] & 0xf; + if ((ints[0] == ASC_NUM_IOPORT_PROBE + 1) && + (ints[ASC_NUM_IOPORT_PROBE + 1] >> 4 == 0xdeb)) { + asc_dbglvl = ints[ASC_NUM_IOPORT_PROBE + 1] & 0xf; } else { #endif /* ADVANSYS_DEBUG */ printk("AdvanSys SCSI: only %d I/O ports accepted\n", - ASC_NUM_BOARD_SUPPORTED); + ASC_NUM_IOPORT_PROBE); #ifdef ADVANSYS_DEBUG } #endif /* ADVANSYS_DEBUG */ @@ -4384,7 +6071,7 @@ ASC_DBG(1, "\n"); #endif /* ADVANSYS_DEBUG */ - for (i = 1; i <= ints[0] && i <= ASC_NUM_BOARD_SUPPORTED; i++) { + for (i = 1; i <= ints[0] && i <= ASC_NUM_IOPORT_PROBE; i++) { asc_ioport[i-1] = ints[i]; ASC_DBG2(1, "advansys_setup: asc_ioport[%d] %x\n", i - 1, asc_ioport[i-1]); @@ -4433,17 +6120,32 @@ cli(); ASC_DBG(1, "advansys_interrupt: begin\n"); + /* * Check for interrupts on all boards. * AscISR() will call asc_isr_callback(). */ 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(&boardp->asc_dvc_var); + ASC_DBG2(2, "advansys_interrupt: i %d, boardp %lx\n", + i, (ulong) boardp) + if (ASC_NARROW_BOARD(boardp)) { + /* + * Narrow Board + */ + if (AscIsIntPending(asc_host[i]->io_port)) { + ASC_STATS(asc_host[i], interrupt); + ASC_DBG(1, "advansys_interrupt: before AscISR()\n"); + AscISR(&boardp->dvc_var.asc_dvc_var); + } + } else { + /* + * Wide Board + */ + ASC_DBG(1, "advansys_interrupt: before AdvISR()\n"); + if (AdvISR(&boardp->dvc_var.adv_dvc_var)) { + ASC_STATS(asc_host[i], interrupt); + } } /* @@ -4454,6 +6156,9 @@ * it has completed. */ if ((boardp->flags & (ASC_HOST_IN_RESET | ASC_HOST_IN_ABORT)) == 0) { + ASC_DBG2(1, "advansys_interrupt: done_scp %lx, last_scp %lx\n", + (ulong) done_scp, (ulong) last_scp); + /* Start any waiting commands for the board. */ if (!ASC_QUEUE_EMPTY(&boardp->waiting)) { ASC_DBG(1, "advansys_interrupt: before asc_execute_queue()\n"); @@ -4461,8 +6166,12 @@ } /* - * Add to the list of requests that must be completed. - */ + * Add to the list of requests that must be completed. + * + * 'done_scp' will always be NULL on the first iteration + * of this loop. 'last_scp' is set at the same time as + * 'done_scp'. + */ if (done_scp == NULL) { done_scp = asc_dequeue_list(&boardp->done, &last_scp, ASC_TID_ALL); @@ -4506,6 +6215,7 @@ asc_board_t *boardp; boardp = ASC_BOARDP(shp); + boardp->flags |= ASC_SELECT_QUEUE_DEPTHS; for (device = devicelist; device != NULL; device = device->next) { if (device->host != shp) { continue; @@ -4515,7 +6225,13 @@ * queue depth. */ boardp->device[device->id] = device; - device->queue_depth = boardp->asc_dvc_var.max_dvc_qng[device->id]; + if (ASC_NARROW_BOARD(boardp)) { + device->queue_depth = + boardp->dvc_var.asc_dvc_var.max_dvc_qng[device->id]; + } else { + device->queue_depth = + boardp->dvc_var.adv_dvc_var.max_dvc_qng; + } ASC_DBG3(1, "advansys_select_queue_depths: shp %x, id %d, depth %d\n", (unsigned) shp, device->id, device->queue_depth); } @@ -4544,7 +6260,9 @@ { Scsi_Cmnd *tscp; + ASC_DBG(2, "asc_scsi_done_list: begin\n"); while (scp != NULL) { + ASC_DBG1(3, "asc_scsi_done_list: scp %x\n", (unsigned) scp); tscp = REQPNEXT(scp); REQPNEXT(scp) = NULL; ASC_STATS(scp->host, done); @@ -4552,6 +6270,7 @@ scp->scsi_done(scp); scp = tscp; } + ASC_DBG(2, "asc_scsi_done_list: done\n"); return; } @@ -4567,28 +6286,29 @@ * target - target of device * lun - lun of device * cmd_len - length of SCSI CDB - * cmnd - buffer for SCSI 8, 10, or 12 byte CDB + * cmnd - buffer for SCSI 8, 10, or 12 byte CDB * use_sg - if non-zero indicates scatter-gather request with use_sg elements * - * if (use_sg == 0) - * request_buffer - buffer address for request - * request_bufflen - length of request buffer - * else - * request_buffer - pointer to scatterlist structure + * if (use_sg == 0) { + * request_buffer - buffer address for request + * request_bufflen - length of request buffer + * } else { + * request_buffer - pointer to scatterlist structure + * } * * sense_buffer - sense command buffer * * result (4 bytes of an int): - * Byte Meaning - * 0 SCSI Status Byte Code - * 1 SCSI One Byte Message Code - * 2 Host Error Code - * 3 Mid-Level Error Code + * Byte Meaning + * 0 SCSI Status Byte Code + * 1 SCSI One Byte Message Code + * 2 Host Error Code + * 3 Mid-Level Error Code * * host driver fields: - * SCp - Scsi_Pointer used for command processing status - * scsi_done - used to save caller's done function - * host_scribble - used for pointer to another Scsi_Cmnd + * SCp - Scsi_Pointer used for command processing status + * 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 request * has been enqueued on the board's 'done' queue and must be @@ -4602,6 +6322,8 @@ { asc_board_t *boardp; ASC_DVC_VAR *asc_dvc_varp; + ADV_DVC_VAR *adv_dvc_varp; + ADV_SCSI_REQ_Q *adv_scsiqp; Scsi_Device *device; int ret; @@ -4610,22 +6332,199 @@ (unsigned) scp, (unsigned) scp->scsi_done); boardp = ASC_BOARDP(scp->host); - asc_dvc_varp = &boardp->asc_dvc_var; device = boardp->device[scp->target]; - /* - * If this is the first command, then initialize the device. If - * no device is found set 'DID_BAD_TARGET' and return. - */ - 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); + if (ASC_NARROW_BOARD(boardp)) { + /* + * Build and execute Narrow Board request. + */ + + asc_dvc_varp = &boardp->dvc_var.asc_dvc_var; + + /* + * Narrow Board - Asc Library requires special device initialization. + * + * If this is the first command, then initialize the device. If + * no device is found set 'DID_BAD_TARGET' and return. + */ + if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->target)) == 0) { + if (asc_init_dev(asc_dvc_varp, scp) == ASC_FALSE) { + scp->result = HOST_BYTE(DID_BAD_TARGET); + asc_enqueue(&boardp->done, scp, ASC_BACK); + return ASC_ERROR; + } + boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->target); + } + + /* + * Build Asc Library request structure using the + * global structures 'asc_scsi_req' and 'asc_sg_head'. + * + * asc_build_req() can not return ASC_BUSY. + */ + if (asc_build_req(boardp, scp) == ASC_ERROR) { + ASC_STATS(scp->host, build_error); + return ASC_ERROR; + } + + /* + * Execute the command. If there is no error, add the command + * to the active queue. + */ + switch (ret = AscExeScsiQueue(asc_dvc_varp, &asc_scsi_q)) { + case ASC_NOERROR: + ASC_STATS(scp->host, exe_noerror); + /* + * Increment monotonically increasing per device successful + * request counter. Wrapping doesn't matter. + */ + boardp->reqcnt[scp->target]++; + +#if ASC_QUEUE_FLOW_CONTROL + /* + * Conditionally increment the device queue depth. + * + * If no error occurred and there have been 100 consecutive + * successful requests and the current queue depth is less + * than the maximum queue depth, then increment the current + * queue depth. + */ + if (boardp->nerrcnt[scp->target]++ > 100) { + boardp->nerrcnt[scp->target] = 0; + if (device != NULL && + (device->queue_curr_depth < device->queue_depth) && + (!(boardp->queue_full & + ADV_TID_TO_TIDMASK(scp->target)) || + (boardp->queue_full_cnt[scp->target] > + device->queue_curr_depth))) { + device->queue_curr_depth++; + } + } +#endif /* ASC_QUEUE_FLOW_CONTROL */ + asc_enqueue(&boardp->active, scp, ASC_BACK); + ASC_DBG(1, + "asc_execute_scsi_cmnd: AscExeScsiQueue(), ASC_NOERROR\n"); + break; + case ASC_BUSY: + /* Caller must enqueue request and retry later. */ + ASC_STATS(scp->host, exe_busy); +#if ASC_QUEUE_FLOW_CONTROL + /* + * Clear consecutive no error counter and if possible decrement + * queue depth. + */ + boardp->nerrcnt[scp->target] = 0; + if (device != NULL && device->queue_curr_depth > 1) { + device->queue_curr_depth--; + } +#endif /* ASC_QUEUE_FLOW_CONTROL */ + break; + case ASC_ERROR: + ASC_PRINT2( +"asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() ASC_ERROR, err_code %x\n", + boardp->id, asc_dvc_varp->err_code); + ASC_STATS(scp->host, exe_error); +#if ASC_QUEUE_FLOW_CONTROL + /* Clear consecutive no error counter. */ + boardp->nerrcnt[scp->target] = 0; +#endif /* ASC_QUEUE_FLOW_CONTROL */ + scp->result = HOST_BYTE(DID_ERROR); + asc_enqueue(&boardp->done, scp, ASC_BACK); + break; + default: + ASC_PRINT2( +"asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() unknown, err_code %x\n", + boardp->id, asc_dvc_varp->err_code); + ASC_STATS(scp->host, exe_unknown); +#if ASC_QUEUE_FLOW_CONTROL + /* Clear consecutive no error counter. */ + boardp->nerrcnt[scp->target] = 0; +#endif /* ASC_QUEUE_FLOW_CONTROL */ + scp->result = HOST_BYTE(DID_ERROR); asc_enqueue(&boardp->done, scp, ASC_BACK); + break; + } + } else { + /* + * Build and execute Wide Board request. + */ + adv_dvc_varp = &boardp->dvc_var.adv_dvc_var; + + /* + * Build and get a pointer to an Adv Library request structure. + * + * If the request is successfully built then send it below, + * otherwise return with an error. + */ + switch (adv_build_req(boardp, scp, &adv_scsiqp)) { + case ASC_NOERROR: + ASC_DBG(3, "asc_execute_scsi_cmnd: adv_build_req ASC_NOERROR\n"); + break; + case ASC_BUSY: + ASC_DBG(1, "asc_execute_scsi_cmnd: adv_build_req ASC_BUSY\n"); + return ASC_BUSY; + case ASC_ERROR: + default: + ASC_DBG(1, "asc_execute_scsi_cmnd: adv_build_req ASC_ERROR\n"); + ASC_STATS(scp->host, build_error); return ASC_ERROR; } - boardp->init_tidmask |= ASC_TIX_TO_TARGET_ID(scp->target); + + /* + * Execute the command. If there is no error, add the command + * to the active queue. + */ + switch (ret = AdvExeScsiQueue(adv_dvc_varp, adv_scsiqp)) { + case ASC_NOERROR: + ASC_STATS(scp->host, exe_noerror); + /* + * Increment monotonically increasing per device successful + * request counter. Wrapping doesn't matter. + */ + boardp->reqcnt[scp->target]++; + asc_enqueue(&boardp->active, scp, ASC_BACK); + ASC_DBG(1, + "asc_execute_scsi_cmnd: AdvExeScsiQueue(), ASC_NOERROR\n"); + break; + case ASC_BUSY: + /* Caller must enqueue request and retry later. */ + ASC_STATS(scp->host, exe_busy); + break; + case ASC_ERROR: + ASC_PRINT2( +"asc_execute_scsi_cmnd: board %d: AdvExeScsiQueue() ASC_ERROR, err_code %x\n", + boardp->id, adv_dvc_varp->err_code); + ASC_STATS(scp->host, exe_error); + scp->result = HOST_BYTE(DID_ERROR); + asc_enqueue(&boardp->done, scp, ASC_BACK); + break; + default: + ASC_PRINT2( +"asc_execute_scsi_cmnd: board %d: AdvExeScsiQueue() unknown, err_code %x\n", + boardp->id, adv_dvc_varp->err_code); + ASC_STATS(scp->host, exe_unknown); + scp->result = HOST_BYTE(DID_ERROR); + asc_enqueue(&boardp->done, scp, ASC_BACK); + break; + } } + ASC_DBG(1, "asc_execute_scsi_cmnd: end\n"); + ASC_ASSERT(interrupts_enabled() == ASC_FALSE); + return ret; +} + +/* + * Build a request structure for the Asc Library (Narrow Board). + * + * The global structures 'asc_scsi_q' and 'asc_sg_head' are + * used to build the request. + * + * If an error occurs, then return ASC_ERROR. + */ +STATIC int +asc_build_req(asc_board_t *boardp, Scsi_Cmnd *scp) +{ /* * Mutually exclusive access is required to 'asc_scsi_q' and * 'asc_sg_head' until after the request is started. @@ -4640,6 +6539,10 @@ /* * Build the ASC_SCSI_Q request. */ + ASC_ASSERT(scp->cmd_len <= ASC_MAX_CDB_LEN); + if (scp->cmd_len > ASC_MAX_CDB_LEN) { + scp->cmd_len = ASC_MAX_CDB_LEN; + } 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); @@ -4663,7 +6566,7 @@ * started request. * */ - if ((asc_dvc_varp->cur_dvc_qng[scp->target] > 0) && + if ((boardp->dvc_var.asc_dvc_var.cur_dvc_qng[scp->target] > 0) && (boardp->reqcnt[scp->target] % 255) == 0) { asc_scsi_q.q2.tag_code = M2_QTAG_MSG_ORDERED; } else { @@ -4693,12 +6596,12 @@ /* * CDB scatter-gather request list. */ - int sgcnt; - struct scatterlist *slp; + int sgcnt; + struct scatterlist *slp; if (scp->use_sg > scp->host->sg_tablesize) { ASC_PRINT3( -"asc_execute_scsi_cmnd: board %d: use_sg %d > sg_tablesize %d\n", +"asc_build_req: board %d: use_sg %d > sg_tablesize %d\n", boardp->id, scp->use_sg, scp->host->sg_tablesize); scp->result = HOST_BYTE(DID_ERROR); asc_enqueue(&boardp->done, scp, ASC_BACK); @@ -4708,8 +6611,8 @@ ASC_STATS(scp->host, sg_cnt); /* - * Allocate a ASC_SG_HEAD structure and set the ASC_SCSI_Q - * to point to it. + * Use global ASC_SG_HEAD structure and set the ASC_SCSI_Q + * structure to point to it. */ memset(&asc_sg_head, 0, sizeof(ASC_SG_HEAD)); @@ -4735,91 +6638,262 @@ } } - ASC_DBG_PRT_SCSI_Q(2, &asc_scsi_q); + ASC_DBG_PRT_ASC_SCSI_Q(2, &asc_scsi_q); ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len); + return ASC_NOERROR; +} + +/* + * Build a request structure for the Adv Library (Wide Board). + * + * If an adv_req_t can not be allocated to issue the request, + * then return ASC_BUSY. If an error occurs, then return ASC_ERROR. + */ +STATIC int +adv_build_req(asc_board_t *boardp, Scsi_Cmnd *scp, + ADV_SCSI_REQ_Q **adv_scsiqpp) +{ + adv_req_t *reqp; + ADV_SCSI_REQ_Q *scsiqp; + int i; + /* - * Execute the command. If there is no error, add the command - * to the active queue. + * Allocate an adv_req_t structure from the board to execute + * the command. */ - switch (ret = AscExeScsiQueue(asc_dvc_varp, &asc_scsi_q)) { - case ASC_NOERROR: - ASC_STATS(scp->host, asc_noerror); - /* - * Increment monotonically increasing per device successful - * request counter. Wrapping doesn't matter. - */ - boardp->reqcnt[scp->target]++; - -#if ASC_QUEUE_FLOW_CONTROL + if (boardp->adv_reqp == NULL) { + ASC_DBG(1, "adv_build_req: no free adv_req_t\n"); + ASC_STATS(scp->host, adv_build_noreq); + return ASC_BUSY; + } else { + reqp = boardp->adv_reqp; + boardp->adv_reqp = reqp->next_reqp; + reqp->next_reqp = NULL; + } + + /* + * Get 4-byte aligned ADV_SCSI_REQ_Q and ADV_SG_BLOCK pointers. + */ + scsiqp = (ADV_SCSI_REQ_Q *) ADV_DWALIGN(&reqp->scsi_req_q); + memset(scsiqp, 0, sizeof(ADV_SCSI_REQ_Q)); + + /* + * Set the ADV_SCSI_REQ_Q 'srb_ptr' to point to the adv_req_t structure. + */ + scsiqp->srb_ptr = (ulong) reqp; + + /* + * Set the adv_req_t 'cmndp' to point to the Scsi_Cmnd structure. + */ + reqp->cmndp = scp; + + /* + * Build the ADV_SCSI_REQ_Q request. + */ + + /* + * Set CDB length and copy it to the request structure. + */ + ASC_ASSERT(scp->cmd_len <= ASC_MAX_CDB_LEN); + if (scp->cmd_len > ASC_MAX_CDB_LEN) { + scp->cmd_len = ASC_MAX_CDB_LEN; + } + scsiqp->cdb_len = scp->cmd_len; + for (i = 0; i < scp->cmd_len; i++) { + scsiqp->cdb[i] = scp->cmnd[i]; + } + + scsiqp->target_id = scp->target; + scsiqp->target_lun = scp->lun; + + scsiqp->vsense_addr = (ulong) &scp->sense_buffer[0]; +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0) + scsiqp->sense_addr = (ulong) &scp->sense_buffer[0]; +#else /* version >= v2.0.0 */ + scsiqp->sense_addr = virt_to_bus(&scp->sense_buffer[0]); +#endif /* version >= v2.0.0 */ + scsiqp->sense_len = sizeof(scp->sense_buffer); + + /* + * Build ADV_SCSI_REQ_Q for a contiguous buffer or a scatter-gather + * buffer command. + */ + scsiqp->data_cnt = scp->request_bufflen; + scsiqp->vdata_addr = (ulong) scp->request_buffer; +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0) + scsiqp->data_addr = (ulong) scp->request_buffer; +#else /* version >= v2.0.0 */ + scsiqp->data_addr = virt_to_bus(scp->request_buffer); +#endif /* version >= v2.0.0 */ + + if (scp->use_sg == 0) { /* - * Conditionally increment the device queue depth. - * - * If no error occurred and there have been 100 consecutive - * successfull requests and the current queue depth is less - * than the maximum queue depth, then increment the current - * queue depth. + * CDB request of single contiguous buffer. */ - if (boardp->nerrcnt[scp->target]++ > 100) { - boardp->nerrcnt[scp->target] = 0; - if ((device->queue_curr_depth < device->queue_depth) && - (!(boardp->queue_full & ASC_TIX_TO_TARGET_ID(scp->target)) || - (boardp->queue_full_cnt[scp->target] > - device->queue_curr_depth))) { - device->queue_curr_depth++; - } + reqp->sgblkp = NULL; + scsiqp->sg_list_ptr = NULL; + ASC_STATS(scp->host, cont_cnt); + ASC_STATS_ADD(scp->host, cont_xfer, + ASC_CEILING(scp->request_bufflen, 512)); + } else { + /* + * CDB scatter-gather request list. + */ + if (scp->use_sg > ADV_MAX_SG_LIST) { + ASC_PRINT3( +"adv_build_req: board %d: use_sg %d > ADV_MAX_SG_LIST %d\n", + boardp->id, scp->use_sg, scp->host->sg_tablesize); + scp->result = HOST_BYTE(DID_ERROR); + asc_enqueue(&boardp->done, scp, ASC_BACK); + + /* + * Free the 'adv_req_t' structure by adding it back to the + * board free list. + */ + reqp->next_reqp = boardp->adv_reqp; + boardp->adv_reqp = reqp; + + return ASC_ERROR; } -#endif /* ASC_QUEUE_FLOW_CONTROL */ - asc_enqueue(&boardp->active, scp, ASC_BACK); - ASC_DBG(1, "asc_execute_scsi_cmnd: AscExeScsiQueue(), ASC_NOERROR\n"); - break; - case ASC_BUSY: - /* Caller must enqueue request and retry later. */ - ASC_STATS(scp->host, asc_busy); -#if ASC_QUEUE_FLOW_CONTROL + /* - * Clear consecutive no error counter and if possbile decrement - * queue depth. + * Allocate an 'adv_sgblk_t' structure from the board to + * execute the command. + */ + if (boardp->adv_sgblkp == NULL) { + ASC_DBG(1, "adv_build_req: no free adv_sgblk_t\n"); + ASC_STATS(scp->host, adv_build_nosg); + /* + * Free the 'adv_req_t' structure by adding it back to the + * board free list. + */ + reqp->next_reqp = boardp->adv_reqp; + boardp->adv_reqp = reqp; + return ASC_BUSY; + } else { + reqp->sgblkp = boardp->adv_sgblkp; + boardp->adv_sgblkp = reqp->sgblkp->next_sgblkp; + reqp->sgblkp->next_sgblkp = NULL; + } + + /* + * Build scatter-gather list. */ - boardp->nerrcnt[scp->target] = 0; - if (device->queue_curr_depth > 1) { - device->queue_curr_depth--; + scsiqp->sg_list_ptr = (ADV_SG_BLOCK *) + ADV_DWALIGN(&reqp->sgblkp->sg_block[0]); + + memset(scsiqp->sg_list_ptr, 0, sizeof(ADV_SG_BLOCK) * + (ADV_NUM_SG_BLOCK + ADV_NUM_PAGE_CROSSING)); + + if (adv_get_sglist(&boardp->dvc_var.adv_dvc_var, scsiqp, scp) == + ADV_ERROR) { + + /* + * Free the adv_sgblk_t structure, if any, by adding it back + * to the board free list. + */ + ASC_ASSERT(reqp->sgblkp != NULL); + reqp->sgblkp->next_sgblkp = boardp->adv_sgblkp; + boardp->adv_sgblkp = reqp->sgblkp; + + /* + * Free the adv_req_t structure by adding it back to the + * board free list. + */ + reqp->next_reqp = boardp->adv_reqp; + boardp->adv_reqp = reqp; + + return ADV_ERROR; } -#endif /* ASC_QUEUE_FLOW_CONTROL */ - break; - case ASC_ERROR: - ASC_PRINT2( -"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); -#if ASC_QUEUE_FLOW_CONTROL - /* Clear consecutive no error counter. */ - boardp->nerrcnt[scp->target] = 0; -#endif /* ASC_QUEUE_FLOW_CONTROL */ - scp->result = HOST_BYTE(DID_ERROR); - asc_enqueue(&boardp->done, scp, ASC_BACK); - break; - default: - ASC_PRINT2( -"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); -#if ASC_QUEUE_FLOW_CONTROL - /* Clear consecutive no error counter. */ - boardp->nerrcnt[scp->target] = 0; -#endif /* ASC_QUEUE_FLOW_CONTROL */ - scp->result = HOST_BYTE(DID_ERROR); - asc_enqueue(&boardp->done, scp, ASC_BACK); - break; + + ASC_STATS(scp->host, sg_cnt); + ASC_STATS_ADD(scp->host, sg_elem, scp->use_sg); } - ASC_DBG(1, "asc_execute_scsi_cmnd: end\n"); - ASC_ASSERT(interrupts_enabled() == ASC_FALSE); - return ret; + ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp); + ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len); + + *adv_scsiqpp = scsiqp; + + return ASC_NOERROR; +} + +/* + * Build scatter-gather list for Adv Library (Wide Board). + * + * Return: + * ADV_SUCCESS(1) - SG List successfully created + * ADV_ERROR(-1) - SG List creation failed + */ +STATIC int +adv_get_sglist(ADV_DVC_VAR *adv_dvc_varp, ADV_SCSI_REQ_Q *scsiqp, + Scsi_Cmnd *scp) +{ + ADV_SG_BLOCK *sg_block; /* virtual address of a SG */ + ulong sg_block_next_addr; /* block and its next */ + ulong sg_block_physical_addr; + int sg_block_index, i; /* how many SG entries */ + struct scatterlist *slp; + int sg_elem_cnt; + + slp = (struct scatterlist *) scp->request_buffer; + sg_elem_cnt = scp->use_sg; + + sg_block = scsiqp->sg_list_ptr; + sg_block_next_addr = (ulong) sg_block; /* allow math operation */ + sg_block_physical_addr = +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0) + (ulong) scsiqp->sg_list_ptr; +#else /* version >= v2.0.0 */ + virt_to_bus(scsiqp->sg_list_ptr); +#endif /* version >= v2.0.0 */ + ADV_ASSERT(ADV_DWALIGN(sg_block_physical_addr) == + sg_block_physical_addr); + scsiqp->sg_real_addr = sg_block_physical_addr; + + sg_block_index = 0; + do + { + sg_block->first_entry_no = sg_block_index; + for (i = 0; i < NO_OF_SG_PER_BLOCK; i++) + { + sg_block->sg_list[i].sg_addr = +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0) + (ulong) slp->address; +#else /* version >= v2.0.0 */ + virt_to_bus(slp->address); +#endif /* version >= v2.0.0 */ + sg_block->sg_list[i].sg_count = slp->length; + ASC_STATS_ADD(scp->host, sg_xfer, ASC_CEILING(slp->length, 512)); + + if (--sg_elem_cnt == 0) + { /* last entry, get out */ + scsiqp->sg_entry_cnt = sg_block_index + i + 1; + sg_block->last_entry_no = sg_block_index + i; + sg_block->sg_ptr = 0L; /* next link = NULL */ + return ADV_SUCCESS; + } + slp++; + } + sg_block_next_addr += sizeof(ADV_SG_BLOCK); + sg_block_physical_addr += sizeof(ADV_SG_BLOCK); + ADV_ASSERT(ADV_DWALIGN(sg_block_physical_addr) == + sg_block_physical_addr); + + sg_block_index += NO_OF_SG_PER_BLOCK; + sg_block->sg_ptr = (ADV_SG_BLOCK *) sg_block_physical_addr; + sg_block->last_entry_no = sg_block_index - 1; + sg_block = (ADV_SG_BLOCK *) sg_block_next_addr; /* virtual addr */ + } + while (1); + /* NOTREACHED */ } /* * asc_isr_callback() - Second Level Interrupt Handler called by AscISR(). + * + * Interrupt callback function for the Narrow SCSI Asc Library. */ STATIC void asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep) @@ -4827,12 +6901,13 @@ asc_board_t *boardp; Scsi_Cmnd *scp; struct Scsi_Host *shp; + int underrun = ASC_FALSE; int i; ASC_ASSERT(interrupts_enabled() == ASC_FALSE); ASC_DBG2(1, "asc_isr_callback: asc_dvc_varp %x, qdonep %x\n", (unsigned) asc_dvc_varp, (unsigned) qdonep); - ASC_DBG_PRT_QDONE_INFO(2, qdonep); + ASC_DBG_PRT_ASC_QDONE_INFO(2, qdonep); /* * Get the Scsi_Cmnd structure and Scsi_Host structure for the @@ -4840,12 +6915,12 @@ */ scp = (Scsi_Cmnd *) qdonep->d2.srb_ptr; 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; } + ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len); /* * If the request's host pointer is not valid, display a @@ -4879,6 +6954,16 @@ } /* + * Check for an underrun condition. + */ + if (scp->request_bufflen != 0 && qdonep->remain_bytes != 0 && + qdonep->remain_bytes <= scp->request_bufflen != 0) { + ASC_DBG1(1, "asc_isr_callback: underrun condition %u bytes\n", + (unsigned) qdonep->remain_bytes); + underrun = ASC_TRUE; + } + + /* * 'qdonep' contains the command's ending status. */ switch (qdonep->d3.done_stat) { @@ -4893,6 +6978,13 @@ scp->result = HOST_BYTE(DID_ERROR); break; } + /* + * If there was an underrun without any other error, + * set DID_ERROR to indicate the underrun error. + */ + if (scp->result == 0 && underrun == ASC_TRUE) { + scp->result = HOST_BYTE(DID_UNDERRUN); + } break; case QD_WITH_ERROR: @@ -4955,115 +7047,320 @@ } /* - * asc_init_dev() + * adv_isr_callback() - Second Level Interrupt Handler called by AdvISR(). * - * Perform one-time initialization of a device. + * Callback function for the Wide SCSI Adv Library. */ -STATIC int -asc_init_dev(ASC_DVC_VAR *asc_dvc_varp, Scsi_Cmnd *scp) +STATIC void +adv_isr_callback(ADV_DVC_VAR *adv_dvc_varp, ADV_SCSI_REQ_Q *scsiqp) { - asc_board_t *boardp; - ASC_SCSI_REQ_Q *scsireqq; - ASC_CAP_INFO *cap_info; - ASC_SCSI_INQUIRY *inquiry; - int found; - ASC_SCSI_BIT_ID_TYPE save_use_tagged_qng; - ASC_SCSI_BIT_ID_TYPE save_can_tagged_qng; - int ret; -#ifdef ADVANSYS_DEBUG - ASC_SCSI_BIT_ID_TYPE tidmask; /* target id bit mask: 1 - 128 */ -#endif /* ADVANSYS_DEBUG */ - - ASC_DBG1(1, "asc_init_dev: target %d\n", (unsigned) scp->target); - - /* The host's target id is set in init_tidmask during initialization. */ - ASC_ASSERT(asc_dvc_varp->cfg->chip_scsi_id != scp->target); + asc_board_t *boardp; + adv_req_t *reqp; + Scsi_Cmnd *scp; + struct Scsi_Host *shp; + int underrun = ASC_FALSE; + int i; - boardp = ASC_BOARDP(scp->host); + ASC_ASSERT(interrupts_enabled() == ASC_FALSE); + ASC_DBG2(1, "adv_isr_callback: adv_dvc_varp %x, scsiqp %x\n", + (unsigned) adv_dvc_varp, (unsigned) scsiqp); + ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp); - /* 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)); + /* + * Get the adv_req_t structure for the command that has been + * completed. The adv_req_t structure actually contains the + * completed ADV_SCSI_REQ_Q structure. + */ + reqp = (adv_req_t *) scsiqp->srb_ptr; + ASC_DBG1(1, "adv_isr_callback: reqp %x\n", (unsigned) reqp); + if (reqp == NULL) { + ASC_PRINT("adv_isr_callback: reqp is NULL\n"); + return; + } /* - * XXX - AscInitPollBegin() re-initializes these fields to - * zero. 'Or' in the new values and restore them before calling - * AscInitPollEnd(). Normally all targets are initialized within - * a call to AscInitPollBegin() and AscInitPollEnd(). + * Get the Scsi_Cmnd structure and Scsi_Host structure for the + * command that has been completed. + * + * Note: The adv_req_t request structure and adv_sgblk_t structure, + * if any, * dropped, because a board structure pointer can not be + * determined. */ - save_use_tagged_qng = asc_dvc_varp->use_tagged_qng; - save_can_tagged_qng = asc_dvc_varp->cfg->can_tagged_qng; - - ASC_DBG(2, "asc_init_dev: AscInitPollBegin()\n"); - if (AscInitPollBegin(asc_dvc_varp)) { - ASC_PRINT1("asc_init_dev: board %d: AscInitPollBegin() failed\n", - boardp->id); - return ASC_FALSE; + scp = reqp->cmndp; + ASC_DBG1(1, "adv_isr_callback: scp %x\n", (unsigned) scp); + if (scp == NULL) { + ASC_PRINT("adv_isr_callback: scp is NULL; adv_req_t dropped.\n"); + return; } + ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len); - 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); - - found = ASC_FALSE; - ASC_DBG(2, "asc_init_dev: AscInitPollTarget()\n"); - switch (ret = AscInitPollTarget(asc_dvc_varp, scsireqq, inquiry, - 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_DBG1(1, "asc_init_dev: peri_dvc_type %x\n", - 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]); - } else { - ASC_DBG(1, "asc_init_dev: command queuing disabled\n"); - } - if (asc_dvc_varp->init_sdtr & tidmask) { - ASC_DBG(1, "asc_init_dev: synchronous transfers enabled\n"); - } else { - ASC_DBG(1, "asc_init_dev: synchronous transfers disabled\n"); - } - /* Set bit means fix disabled. */ - if (asc_dvc_varp->pci_fix_asyn_xfer & tidmask) { - ASC_DBG(1, "asc_init_dev: synchronous transfer fix disabled\n"); - } else { - ASC_DBG(1, "asc_init_dev: synchronous transfer fix enabled\n"); + /* + * If the request's host pointer is not valid, display a message + * and return. + */ + shp = scp->host; + for (i = 0; i < asc_board_count; i++) { + if (asc_host[i] == shp) { + break; } -#endif /* ADVANSYS_DEBUG */ - break; - case ASC_FALSE: - 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", - boardp->id); - break; - default: - ASC_PRINT2( -"asc_init_dev: board %d: AscInitPollTarget() unknown ret %d\n", - boardp->id, ret); - break; + } + /* + * Note: If the host structure is not found, the adv_req_t request + * structure and adv_sgblk_t structure, if any, is dropped. + */ + if (i == asc_board_count) { + ASC_PRINT2("adv_isr_callback: scp %x has bad host pointer, host %x\n", + (unsigned) scp, (unsigned) shp); + return; } - /* XXX - 'Or' in original tag bits. */ - asc_dvc_varp->use_tagged_qng |= save_use_tagged_qng; - asc_dvc_varp->cfg->can_tagged_qng |= save_can_tagged_qng; - - ASC_DBG(2, "asc_init_dev: AscInitPollEnd()\n"); - AscInitPollEnd(asc_dvc_varp); + ASC_STATS(shp, callback); + ASC_DBG1(1, "adv_isr_callback: shp %x\n", (unsigned) shp); - ASC_DBG1(1, "asc_init_dev: found %d\n", found); + /* + * 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. + * + * Note: Because the structure may still be in use don't attempt + * to free the adv_req_t and adv_sgblk_t, if any, structures. + */ + boardp = ASC_BOARDP(shp); + if (asc_rmqueue(&boardp->active, scp) == ASC_FALSE) { + ASC_PRINT2("adv_isr_callback: board %d: scp %x not on active queue\n", + boardp->id, (unsigned) scp); + return; + } + + /* + * Check for an underrun condition. + */ + if (scp->request_bufflen != 0 && scsiqp->data_cnt != 0) { + ASC_DBG1(1, "adv_isr_callback: underrun condition %lu bytes\n", + scsiqp->data_cnt); + underrun = ASC_TRUE; + } + + /* + * 'done_status' contains the command's ending status. + */ + switch (scsiqp->done_status) { + case QD_NO_ERROR: + ASC_DBG(2, "adv_isr_callback: QD_NO_ERROR\n"); + switch (scsiqp->host_status) { + case QHSTA_NO_ERROR: + scp->result = 0; + break; + default: + /* QHSTA error occurred. */ + ASC_DBG1(2, "adv_isr_callback: host_status %x\n", + scsiqp->host_status); + scp->result = HOST_BYTE(DID_ERROR); + break; + } + /* + * If there was an underrun without any other error, + * set DID_ERROR to indicate the underrun error. + */ + if (scp->result == 0 && underrun == ASC_TRUE) { + scp->result = HOST_BYTE(DID_UNDERRUN); + } + break; + + case QD_WITH_ERROR: + ASC_DBG(2, "adv_isr_callback: QD_WITH_ERROR\n"); + switch (scsiqp->host_status) { + case QHSTA_NO_ERROR: + if (scsiqp->scsi_status == SS_CHK_CONDITION) { + ASC_DBG(2, "adv_isr_callback: SS_CHK_CONDITION\n"); + ASC_DBG_PRT_SENSE(2, scp->sense_buffer, + sizeof(scp->sense_buffer)); + /* + * Note: The 'status_byte()' macro used by target drivers + * defined in scsi.h shifts the status byte returned by + * host drivers right by 1 bit. This is why target drivers + * also use right shifted status byte definitions. For + * instance target drivers use CHECK_CONDITION, defined to + * 0x1, instead of the SCSI defined check condition value + * of 0x2. Host drivers are supposed to return the status + * byte as it is defined by SCSI. + */ + scp->result = DRIVER_BYTE(DRIVER_SENSE) | + STATUS_BYTE(scsiqp->scsi_status); + } else { + scp->result = STATUS_BYTE(scsiqp->scsi_status); + } + break; + + default: + /* Some other QHSTA error occurred. */ + ASC_DBG1(2, "adv_isr_callback: host_status %x\n", + scsiqp->host_status); + scp->result = HOST_BYTE(DID_BAD_TARGET); + break; + } + break; + + case QD_ABORTED_BY_HOST: + ASC_DBG(1, "adv_isr_callback: QD_ABORTED_BY_HOST\n"); + scp->result = HOST_BYTE(DID_ABORT) | STATUS_BYTE(scsiqp->scsi_status); + break; + + default: + ASC_PRINT1("adv_isr_callback: done_status %x\n", scsiqp->done_status); + scp->result = HOST_BYTE(DID_ERROR) | STATUS_BYTE(scsiqp->scsi_status); + break; + } + + /* + * If the 'init_tidmask' bit isn't already set for the target and the + * current request did not finish with a Selection Timeout, then set + * the bit for the target to indicate that a device is present. + */ + if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->target)) == 0 && + scsiqp->done_status == QD_NO_ERROR && + scsiqp->host_status == QHSTA_NO_ERROR) { + boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->target); + } + + /* + * 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(). + */ + asc_enqueue(&boardp->done, scp, ASC_BACK); + + /* + * Free the adv_sgblk_t structure, if any, by adding it back + * to the board free list. + */ + if (reqp->sgblkp != NULL) { + reqp->sgblkp->next_sgblkp = boardp->adv_sgblkp; + boardp->adv_sgblkp = reqp->sgblkp; + } + + /* + * Free the adv_req_t structure used with the command by adding + * it back to the board free list. + */ + reqp->next_reqp = boardp->adv_reqp; + boardp->adv_reqp = reqp; + + ASC_DBG(1, "adv_isr_callback: done\n"); + + return; +} + +/* + * asc_init_dev() - Narrow Board initialization function. + * + * Perform one-time initialization of a device for Asc Library + */ +STATIC int +asc_init_dev(ASC_DVC_VAR *asc_dvc_varp, Scsi_Cmnd *scp) +{ + asc_board_t *boardp; + ASC_SCSI_REQ_Q *scsireqq; + ASC_CAP_INFO *cap_info; + ASC_SCSI_INQUIRY *inquiry; + int found; + ASC_SCSI_BIT_ID_TYPE save_use_tagged_qng; + ASC_SCSI_BIT_ID_TYPE save_can_tagged_qng; + int ret; +#ifdef ADVANSYS_DEBUG + ASC_SCSI_BIT_ID_TYPE tidmask; /* target id bit mask: 1 - 128 */ +#endif /* ADVANSYS_DEBUG */ + + ASC_DBG1(1, "asc_init_dev: target %d\n", (unsigned) scp->target); + + /* 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); + + /* 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)); + + /* + * AscInitPollBegin() re-initializes these bitmask fields to zero. + * Save the current bitmask value and 'or' them back in after calling + * AscInitPollEnd() below.. + */ + save_use_tagged_qng = asc_dvc_varp->use_tagged_qng; + save_can_tagged_qng = asc_dvc_varp->cfg->can_tagged_qng; + + ASC_DBG(2, "asc_init_dev: AscInitPollBegin()\n"); + if (AscInitPollBegin(asc_dvc_varp)) { + 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); + + found = ASC_FALSE; + ASC_DBG(2, "asc_init_dev: AscInitPollTarget()\n"); + switch (ret = AscInitPollTarget(asc_dvc_varp, scsireqq, inquiry, + cap_info)) { + case ASC_TRUE: + found = ASC_TRUE; +#ifdef ADVANSYS_DEBUG + tidmask = ADV_TID_TO_TIDMASK(scp->target); + ASC_DBG2(1, "asc_init_dev: lba %lu, blk_size %lu\n", + cap_info->lba, cap_info->blk_size); + ASC_DBG1(1, "asc_init_dev: peri_dvc_type %x\n", + 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]); + } else { + ASC_DBG(1, "asc_init_dev: command queuing disabled\n"); + } + if (asc_dvc_varp->init_sdtr & tidmask) { + ASC_DBG(1, "asc_init_dev: synchronous transfers enabled\n"); + } else { + ASC_DBG(1, "asc_init_dev: synchronous transfers disabled\n"); + } + /* Set bit means fix disabled. */ + if (asc_dvc_varp->pci_fix_asyn_xfer & tidmask) { + ASC_DBG(1, "asc_init_dev: synchronous transfer fix disabled\n"); + } else { + ASC_DBG(1, "asc_init_dev: synchronous transfer fix enabled\n"); + } +#endif /* ADVANSYS_DEBUG */ + break; + case ASC_FALSE: + 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", + boardp->id); + break; + default: + ASC_PRINT2( +"asc_init_dev: board %d: AscInitPollTarget() unknown ret %d\n", + boardp->id, ret); + break; + } + + /* Restore previously set bits in the bitmask fields. */ + asc_dvc_varp->use_tagged_qng |= save_use_tagged_qng; + asc_dvc_varp->cfg->can_tagged_qng |= save_can_tagged_qng; + + ASC_DBG(2, "asc_init_dev: AscInitPollEnd()\n"); + AscInitPollEnd(asc_dvc_varp); + + ASC_DBG1(1, "asc_init_dev: found %d\n", found); return found; } @@ -5169,7 +7466,8 @@ if ((vendorid == ASC_PCI_VENDORID) && ((deviceid == ASC_PCI_DEVICE_ID_1100) || (deviceid == ASC_PCI_DEVICE_ID_1200) || - (deviceid == ASC_PCI_DEVICE_ID_1300))) { + (deviceid == ASC_PCI_DEVICE_ID_1300) || + (deviceid == ASC_PCI_DEVICE_ID_2300))) { pciDevice->slotFound = lslot; ASC_DBG(3, "asc_pci_find_dev: PCI_DEVICE_FOUND\n"); return PCI_DEVICE_FOUND; @@ -5483,13 +7781,13 @@ { int tid; - ASC_DBG3(2, "asc_enqueue: ascq %x, reqp %x, flag %d\n", + ASC_DBG3(3, "asc_enqueue: ascq %x, reqp %x, flag %d\n", (unsigned) ascq, (unsigned) reqp, flag); 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); + ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID); if (flag == ASC_FRONT) { REQPNEXT(reqp) = ascq->q_first[tid]; ascq->q_first[tid] = reqp; @@ -5509,19 +7807,19 @@ } } /* The queue has at least one entry, set its bit. */ - ascq->q_tidmask |= ASC_TIX_TO_TARGET_ID(tid); + ascq->q_tidmask |= ADV_TID_TO_TIDMASK(tid); #ifdef ADVANSYS_STATS /* Maintain request queue statistics. */ ascq->q_tot_cnt[tid]++; 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", + ASC_DBG2(2, "asc_enqueue: new q_max_cnt[%d] %d\n", tid, ascq->q_max_cnt[tid]); } REQPTIME(reqp) = REQTIMESTAMP(); #endif /* ADVANSYS_STATS */ - ASC_DBG1(1, "asc_enqueue: reqp %x\n", (unsigned) reqp); + ASC_DBG1(3, "asc_enqueue: reqp %x\n", (unsigned) reqp); return; } @@ -5537,15 +7835,15 @@ { REQP reqp; - ASC_DBG2(1, "asc_dequeue: ascq %x, tid %d\n", (unsigned) ascq, tid); + ASC_DBG2(3, "asc_dequeue: ascq %x, tid %d\n", (unsigned) ascq, tid); ASC_ASSERT(interrupts_enabled() == ASC_FALSE); - ASC_ASSERT(tid >= 0 && tid <= ASC_MAX_TID); + ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID); if ((reqp = ascq->q_first[tid]) != NULL) { - ASC_ASSERT(ascq->q_tidmask & ASC_TIX_TO_TARGET_ID(tid)); + ASC_ASSERT(ascq->q_tidmask & ADV_TID_TO_TIDMASK(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); + ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid); ASC_ASSERT(ascq->q_last[tid] == reqp); ascq->q_last[tid] = NULL; } @@ -5556,7 +7854,7 @@ REQTIMESTAT("asc_dequeue", ascq, reqp, tid); #endif /* ADVANSYS_STATS */ } - ASC_DBG1(1, "asc_dequeue: reqp %x\n", (unsigned) reqp); + ASC_DBG1(3, "asc_dequeue: reqp %x\n", (unsigned) reqp); return reqp; } @@ -5586,9 +7884,9 @@ REQP firstp, lastp; int i; - ASC_DBG2(1, "asc_dequeue_list: ascq %x, tid %d\n", (unsigned) ascq, tid); + ASC_DBG2(3, "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)); + ASC_ASSERT((tid == ASC_TID_ALL) || (tid >= 0 && tid <= ADV_MAX_TID)); /* * If 'tid' is not ASC_TID_ALL, return requests only for @@ -5597,14 +7895,14 @@ */ if (tid != ASC_TID_ALL) { /* Return all requests for the specified 'tid'. */ - if ((ascq->q_tidmask & ASC_TIX_TO_TARGET_ID(tid)) == 0) { + if ((ascq->q_tidmask & ADV_TID_TO_TIDMASK(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); + ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid); #ifdef ADVANSYS_STATS { REQP reqp; @@ -5618,8 +7916,8 @@ } 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)) { + for (i = 0; i <= ADV_MAX_TID; i++) { + if (ascq->q_tidmask & ADV_TID_TO_TIDMASK(i)) { if (firstp == NULL) { firstp = ascq->q_first[i]; lastp = ascq->q_last[i]; @@ -5629,7 +7927,7 @@ lastp = ascq->q_last[i]; } ascq->q_first[i] = ascq->q_last[i] = NULL; - ascq->q_tidmask &= ~ASC_TIX_TO_TARGET_ID(i); + ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(i); #ifdef ADVANSYS_STATS ascq->q_cur_cnt[i] = 0; #endif /* ADVANSYS_STATS */ @@ -5647,7 +7945,7 @@ if (lastpp) { *lastpp = lastp; } - ASC_DBG1(1, "asc_dequeue_list: firstp %x\n", (unsigned) firstp); + ASC_DBG1(3, "asc_dequeue_list: firstp %x\n", (unsigned) firstp); return firstp; } @@ -5668,13 +7966,13 @@ int tid; int ret = ASC_FALSE; - ASC_DBG2(1, "asc_rmqueue: ascq %x, reqp %x\n", + ASC_DBG2(3, "asc_rmqueue: ascq %x, reqp %x\n", (unsigned) ascq, (unsigned) reqp); ASC_ASSERT(interrupts_enabled() == ASC_FALSE); ASC_ASSERT(reqp != NULL); tid = REQPTID(reqp); - ASC_ASSERT(tid >= 0 && tid <= ASC_MAX_TID); + ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID); /* * Handle the common case of 'reqp' being the first @@ -5685,7 +7983,7 @@ 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); + ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid); ASC_ASSERT(ascq->q_last[tid] == reqp); ascq->q_last[tid] = NULL; } @@ -5721,7 +8019,7 @@ } ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0); #endif /* ADVANSYS_STATS */ - ASC_DBG2(1, "asc_rmqueue: reqp %x, ret %d\n", (unsigned) reqp, ret); + ASC_DBG2(3, "asc_rmqueue: reqp %x, ret %d\n", (unsigned) reqp, ret); return ret; } @@ -5736,22 +8034,22 @@ int tid; int ret = ASC_FALSE; - ASC_DBG2(1, "asc_isqueued: ascq %x, reqp %x\n", + ASC_DBG2(3, "asc_isqueued: ascq %x, reqp %x\n", (unsigned) ascq, (unsigned) reqp); ASC_ASSERT(interrupts_enabled() == ASC_FALSE); ASC_ASSERT(reqp != NULL); tid = REQPTID(reqp); - ASC_ASSERT(tid >= 0 && tid <= ASC_MAX_TID); + ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID); for (treqp = ascq->q_first[tid]; treqp; treqp = REQPNEXT(treqp)) { - ASC_ASSERT(ascq->q_tidmask & ASC_TIX_TO_TARGET_ID(tid)); + ASC_ASSERT(ascq->q_tidmask & ADV_TID_TO_TIDMASK(tid)); if (treqp == reqp) { ret = ASC_TRUE; break; } } - ASC_DBG1(1, "asc_isqueued: ret %x\n", ret); + ASC_DBG1(3, "asc_isqueued: ret %x\n", ret); return ret; } @@ -5763,9 +8061,9 @@ STATIC void asc_execute_queue(asc_queue_t *ascq) { - ASC_SCSI_BIT_ID_TYPE scan_tidmask; + ADV_SCSI_BIT_ID_TYPE scan_tidmask; REQP reqp; - int i; + int i; ASC_DBG1(1, "asc_execute_queue: ascq %x\n", (unsigned) ascq); ASC_ASSERT(interrupts_enabled() == ASC_FALSE); @@ -5775,13 +8073,13 @@ */ scan_tidmask = ascq->q_tidmask; do { - for (i = 0; i <= ASC_MAX_TID; i++) { - if (scan_tidmask & ASC_TIX_TO_TARGET_ID(i)) { + for (i = 0; i <= ADV_MAX_TID; i++) { + if (scan_tidmask & ADV_TID_TO_TIDMASK(i)) { if ((reqp = asc_dequeue(ascq, i)) == NULL) { - scan_tidmask &= ~ASC_TIX_TO_TARGET_ID(i); + scan_tidmask &= ~ADV_TID_TO_TIDMASK(i); } else if (asc_execute_scsi_cmnd((Scsi_Cmnd *) reqp) == ASC_BUSY) { - scan_tidmask &= ~ASC_TIX_TO_TARGET_ID(i); + scan_tidmask &= ~ADV_TID_TO_TIDMASK(i); /* Put the request back at front of the list. */ asc_enqueue(ascq, reqp, ASC_FRONT); } @@ -5810,6 +8108,7 @@ int leftlen; int totlen; int len; + int chip_scsi_id; int i; boardp = ASC_BOARDP(shp); @@ -5820,25 +8119,166 @@ "\nDevice Information for AdvanSys SCSI Host %d:\n", shp->host_no); ASC_PRT_NEXT(); - len = asc_prt_line(cp, leftlen, "Target Ids Detected:"); + if (ASC_NARROW_BOARD(boardp)) { + chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id; + } else { + chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id; + } + + len = asc_prt_line(cp, leftlen, "Target IDs Detected:"); ASC_PRT_NEXT(); - for (i = 0; i <= ASC_MAX_TID; i++) { - if (boardp->asc_dvc_cfg.chip_scsi_id == i) { - continue; - } else if (boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) { - len = asc_prt_line(cp, leftlen, " %d,", i); + for (i = 0; i <= ADV_MAX_TID; i++) { + if (boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) { + len = asc_prt_line(cp, leftlen, " %X,", i); ASC_PRT_NEXT(); } } - len = asc_prt_line(cp, leftlen, " (%d=Host Adapter)\n", - boardp->asc_dvc_cfg.chip_scsi_id); + len = asc_prt_line(cp, leftlen, " (%X=Host Adapter)\n", chip_scsi_id); ASC_PRT_NEXT(); - return totlen; + return totlen; +} + +/* + * Display Wide Board BIOS Information. + */ +STATIC int +asc_prt_adv_bios(struct Scsi_Host *shp, char *cp, int cplen) +{ + asc_board_t *boardp; + int leftlen; + int totlen; + int len; + int upgrade = ASC_FALSE; + ushort major, minor, letter; + + boardp = ASC_BOARDP(shp); + leftlen = cplen; + totlen = len = 0; + + len = asc_prt_line(cp, leftlen, "\nROM BIOS Version: "); + ASC_PRT_NEXT(); + + /* + * If the BIOS saved a valid signature, then fill in + * the BIOS code segment base address. + */ + if (boardp->bios_signature != 0x55AA) { + len = asc_prt_line(cp, leftlen, "Pre-3.1\n"); + ASC_PRT_NEXT(); + upgrade = ASC_TRUE; + } else { + major = (boardp->bios_version >> 12) & 0xF; + minor = (boardp->bios_version >> 8) & 0xF; + letter = (boardp->bios_version & 0xFF); + + len = asc_prt_line(cp, leftlen, "%d.%d%c\n", + major, minor, letter >= 26 ? '?' : letter + 'A'); + ASC_PRT_NEXT(); + + /* Current available ROM BIOS release is 3.1E. */ + if (major < 3 || (major <= 3 && minor < 1) || + (major <= 3 && minor <= 1 && letter < ('E'- 'A'))) { + upgrade = ASC_TRUE; + } + } + if (upgrade == ASC_TRUE) { + len = asc_prt_line(cp, leftlen, +"Newer version of ROM BIOS available: ftp://ftp.advansys.com/pub\n"); + ASC_PRT_NEXT(); + } + + return totlen; +} + +/* + * Add serial number to information bar if signature AAh + * is found in at bit 15-9 (7 bits) of word 1. + * + * Serial Number consists 12 alpha-numeric digits. + * + * 1 - Product type (A,B,C,D..) Word0: 15-13 (3 bits) + * 2 - MFG Location (A,B,C,D..) Word0: 12-10 (3 bits) + * 3-4 - Product ID (0-99) Word0: 10-0 (11 bits) + * 5 - Product revision Word0: " " + * + * Signature Word1: 15-9 (7 bits) + * 6 - Year (4-9) Word1: 8-6 (3 bits) + * 7-8 - Week of the year Word1: 5-0 (6 bits) + * + * 9-12 - Serial Number Word2: 15-0 (16 bits) + * + * Note 1: Only production cards will have a serial number. + * + * Note 2: Signature is most significant 7 bits (0xFE). + * + * Returns ASC_TRUE if serial number found, otherwise returns ASC_FALSE. + */ +STATIC int +asc_get_eeprom_string(ushort *serialnum, uchar *cp) +{ + ushort w, num; + + if ((serialnum[1] & 0xFE00) != ((ushort) 0xAA << 8)) { + return ASC_FALSE; + } else { + /* + * First word - 6 digits. + */ + w = serialnum[0]; + + /* Product type - 1st digit. */ + *cp++ = 'A' + ((w & 0xE000) >> 13); + + /* Manufacturing location - 2nd digit. */ + *cp++ = 'A' + ((w & 0x1C00) >> 10); + + /* Product ID - 3rd, 4th digits. */ + num = w & 0x3FF; + *cp++ = '0' + (num / 100); + num %= 100; + *cp++ = '0' + (num / 10); + + /* Product revision - 5th digit. */ + *cp++ = 'A' + (num % 10); + + /* + * Second word + */ + w = serialnum[1]; + + /* Year - 6th digit. */ + *cp++ = '0' + ((w & 0x1C0) >> 6); + + /* Week of year - 7th, 8th digits. */ + num = w & 0x003F; + *cp++ = '0' + num / 10; + num %= 10; + *cp++ = '0' + num; + + /* + * Third word + */ + w = serialnum[2]; + + /* Serial number - 9th digit. */ + *cp++ = 'A' + (w / 1000); + + /* 10th, 11th, 12th digits. */ + num = w % 1000; + *cp++ = '0' + num / 100; + num %= 100; + *cp++ = '0' + num / 10; + num %= 10; + *cp++ = '0' + num; + + *cp = '\0'; /* Null Terminate the string. */ + return ASC_TRUE; + } } /* - * asc_prt_board_eeprom() + * asc_prt_asc_board_eeprom() * * Print board EEPROM configuration. * @@ -5849,7 +8289,7 @@ * 'cplen' characters will be copied to 'cp'. */ STATIC int -asc_prt_board_eeprom(struct Scsi_Host *shp, char *cp, int cplen) +asc_prt_asc_board_eeprom(struct Scsi_Host *shp, char *cp, int cplen) { asc_board_t *boardp; ASC_DVC_VAR *asc_dvc_varp; @@ -5859,10 +8299,11 @@ ASCEEP_CONFIG *ep; int i; int isa_dma_speed[] = { 10, 8, 7, 6, 5, 4, 3, 2 }; + uchar serialstr[13]; boardp = ASC_BOARDP(shp); - asc_dvc_varp = &boardp->asc_dvc_var; - ep = &boardp->eep_config; + asc_dvc_varp = &boardp->dvc_var.asc_dvc_var; + ep = &boardp->eep_config.asc_eep; leftlen = cplen; totlen = len = 0; @@ -5871,17 +8312,48 @@ "\nEEPROM Settings for AdvanSys SCSI Host %d:\n", shp->host_no); ASC_PRT_NEXT(); - len = asc_prt_line(cp, leftlen, -" Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n", - ep->chip_scsi_id, ep->max_total_qng, ep->max_tag_qng); - ASC_PRT_NEXT(); - - len = asc_prt_line(cp, leftlen, -" Disconnects: "); + if (asc_get_eeprom_string((ushort *) &ep->adapter_info[0], serialstr) == + ASC_TRUE) { + len = asc_prt_line(cp, leftlen, " Serial Number: %s\n", serialstr); + ASC_PRT_NEXT(); + } else { + if (ep->adapter_info[5] == 0xBB) { + len = asc_prt_line(cp, leftlen, + " Default Settings Used for EEPROM-less Adapter.\n"); + ASC_PRT_NEXT(); + } else { + len = asc_prt_line(cp, leftlen, + " Serial Number Signature Not Present.\n"); + ASC_PRT_NEXT(); + } + } + + len = asc_prt_line(cp, leftlen, +" Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n", + ep->chip_scsi_id, ep->max_total_qng, ep->max_tag_qng); + ASC_PRT_NEXT(); + + len = asc_prt_line(cp, leftlen, +" cntl %x, no_scam %x\n", + ep->cntl, ep->no_scam); + ASC_PRT_NEXT(); + + len = asc_prt_line(cp, leftlen, +" Target ID: "); ASC_PRT_NEXT(); for (i = 0; i <= ASC_MAX_TID; i++) { - len = asc_prt_line(cp, leftlen, " %d:%c", - i, (ep->disc_enable & ASC_TIX_TO_TARGET_ID(i)) ? 'Y' : 'N'); + len = asc_prt_line(cp, leftlen, " %d", i); + ASC_PRT_NEXT(); + } + len = asc_prt_line(cp, leftlen, "\n"); + ASC_PRT_NEXT(); + + len = asc_prt_line(cp, leftlen, +" Disconnects: "); + ASC_PRT_NEXT(); + for (i = 0; i <= ASC_MAX_TID; i++) { + len = asc_prt_line(cp, leftlen, " %c", + (ep->disc_enable & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); ASC_PRT_NEXT(); } len = asc_prt_line(cp, leftlen, "\n"); @@ -5891,8 +8363,8 @@ " Command Queuing: "); ASC_PRT_NEXT(); for (i = 0; i <= ASC_MAX_TID; i++) { - len = asc_prt_line(cp, leftlen, " %d:%c", - i, (ep->use_cmd_qng & ASC_TIX_TO_TARGET_ID(i)) ? 'Y' : 'N'); + len = asc_prt_line(cp, leftlen, " %c", + (ep->use_cmd_qng & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); ASC_PRT_NEXT(); } len = asc_prt_line(cp, leftlen, "\n"); @@ -5902,8 +8374,8 @@ " Start Motor: "); ASC_PRT_NEXT(); for (i = 0; i <= ASC_MAX_TID; i++) { - len = asc_prt_line(cp, leftlen, " %d:%c", - i, (ep->start_motor & ASC_TIX_TO_TARGET_ID(i)) ? 'Y' : 'N'); + len = asc_prt_line(cp, leftlen, " %c", + (ep->start_motor & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); ASC_PRT_NEXT(); } len = asc_prt_line(cp, leftlen, "\n"); @@ -5913,8 +8385,8 @@ " Synchronous Transfer:"); ASC_PRT_NEXT(); for (i = 0; i <= ASC_MAX_TID; i++) { - len = asc_prt_line(cp, leftlen, " %d:%c", - i, (ep->init_sdtr & ASC_TIX_TO_TARGET_ID(i)) ? 'Y' : 'N'); + len = asc_prt_line(cp, leftlen, " %c", + (ep->init_sdtr & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); ASC_PRT_NEXT(); } len = asc_prt_line(cp, leftlen, "\n"); @@ -5931,6 +8403,156 @@ } /* + * asc_prt_adv_board_eeprom() + * + * Print board EEPROM configuration. + * + * 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_adv_board_eeprom(struct Scsi_Host *shp, char *cp, int cplen) +{ + asc_board_t *boardp; + ADV_DVC_VAR *adv_dvc_varp; + int leftlen; + int totlen; + int len; + int i; + char *termstr; + uchar serialstr[13]; + ADVEEP_CONFIG *ep; + + boardp = ASC_BOARDP(shp); + adv_dvc_varp = &boardp->dvc_var.adv_dvc_var; + ep = &boardp->eep_config.adv_eep; + + leftlen = cplen; + totlen = len = 0; + + len = asc_prt_line(cp, leftlen, +"\nEEPROM Settings for AdvanSys SCSI Host %d:\n", shp->host_no); + ASC_PRT_NEXT(); + + if (asc_get_eeprom_string(&ep->serial_number_word1, serialstr) == + ASC_TRUE) { + len = asc_prt_line(cp, leftlen, " Serial Number: %s\n", serialstr); + ASC_PRT_NEXT(); + } else { + len = asc_prt_line(cp, leftlen, + " Serial Number Signature Not Present.\n"); + ASC_PRT_NEXT(); + } + + len = asc_prt_line(cp, leftlen, +" Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n", + ep->adapter_scsi_id, ep->max_host_qng, ep->max_dvc_qng); + ASC_PRT_NEXT(); + + switch (ep->termination) { + case 1: + termstr = "Low Off/High Off"; + break; + case 2: + termstr = "Low Off/High On"; + break; + case 3: + termstr = "Low On/High On"; + break; + default: + case 0: + termstr = "Automatic"; + break; + } + + len = asc_prt_line(cp, leftlen, +" termination: %u (%s), bios_ctrl: %x\n", + ep->termination, termstr, ep->bios_ctrl); + ASC_PRT_NEXT(); + + len = asc_prt_line(cp, leftlen, +" Target ID: "); + ASC_PRT_NEXT(); + for (i = 0; i <= ADV_MAX_TID; i++) { + len = asc_prt_line(cp, leftlen, " %X", i); + ASC_PRT_NEXT(); + } + len = asc_prt_line(cp, leftlen, "\n"); + ASC_PRT_NEXT(); + + len = asc_prt_line(cp, leftlen, +" Disconnects: "); + ASC_PRT_NEXT(); + for (i = 0; i <= ADV_MAX_TID; i++) { + len = asc_prt_line(cp, leftlen, " %c", + (ep->disc_enable & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); + ASC_PRT_NEXT(); + } + len = asc_prt_line(cp, leftlen, "\n"); + ASC_PRT_NEXT(); + + len = asc_prt_line(cp, leftlen, +" Command Queuing: "); + ASC_PRT_NEXT(); + for (i = 0; i <= ADV_MAX_TID; i++) { + len = asc_prt_line(cp, leftlen, " %c", + (ep->tagqng_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); + ASC_PRT_NEXT(); + } + len = asc_prt_line(cp, leftlen, "\n"); + ASC_PRT_NEXT(); + + len = asc_prt_line(cp, leftlen, +" Start Motor: "); + ASC_PRT_NEXT(); + for (i = 0; i <= ADV_MAX_TID; i++) { + len = asc_prt_line(cp, leftlen, " %c", + (ep->start_motor & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); + ASC_PRT_NEXT(); + } + len = asc_prt_line(cp, leftlen, "\n"); + ASC_PRT_NEXT(); + + len = asc_prt_line(cp, leftlen, +" Synchronous Transfer:"); + ASC_PRT_NEXT(); + for (i = 0; i <= ADV_MAX_TID; i++) { + len = asc_prt_line(cp, leftlen, " %c", + (ep->sdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); + ASC_PRT_NEXT(); + } + len = asc_prt_line(cp, leftlen, "\n"); + ASC_PRT_NEXT(); + + len = asc_prt_line(cp, leftlen, +" Ultra Transfer: "); + ASC_PRT_NEXT(); + for (i = 0; i <= ADV_MAX_TID; i++) { + len = asc_prt_line(cp, leftlen, " %c", + (ep->ultra_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); + ASC_PRT_NEXT(); + } + len = asc_prt_line(cp, leftlen, "\n"); + ASC_PRT_NEXT(); + + len = asc_prt_line(cp, leftlen, +" Wide Transfer: "); + ASC_PRT_NEXT(); + for (i = 0; i <= ADV_MAX_TID; i++) { + len = asc_prt_line(cp, leftlen, " %c", + (ep->wdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); + ASC_PRT_NEXT(); + } + len = asc_prt_line(cp, leftlen, "\n"); + ASC_PRT_NEXT(); + + return totlen; +} + +/* * asc_prt_driver_conf() * * Note: no single line should be greater than ASC_PRTLINE_SIZE, @@ -5946,6 +8568,7 @@ int leftlen; int totlen; int len; + int chip_scsi_id; #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) int i; #endif /* version >= v1.3.89 */ @@ -5992,65 +8615,82 @@ #endif /* version >= v1.3.57 */ ASC_PRT_NEXT(); - len = asc_prt_line(cp, leftlen, -" flags %x, last_reset %x, jiffies %x\n", - ASC_BOARDP(shp)->flags, ASC_BOARDP(shp)->last_reset, jiffies); + len = asc_prt_line(cp, leftlen, " flags %x, last_reset %x, jiffies %x\n", + boardp->flags, boardp->last_reset, jiffies); ASC_PRT_NEXT(); + if (ASC_NARROW_BOARD(boardp)) { + chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id; + } else { + chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id; + } + #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) - len = asc_prt_line(cp, leftlen, -" queue_depth: "); - ASC_PRT_NEXT(); - for (i = 0; i <= ASC_MAX_TID; i++) { - if ((boardp->asc_dvc_cfg.chip_scsi_id == i) || - ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) == 0)) { - continue; + if (boardp->flags & ASC_SELECT_QUEUE_DEPTHS) { + len = asc_prt_line(cp, leftlen, " queue_depth:"); + ASC_PRT_NEXT(); + for (i = 0; i <= ADV_MAX_TID; i++) { + if ((chip_scsi_id == i) || + ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { + continue; + } + if (boardp->device[i] == NULL) { + continue; + } + len = asc_prt_line(cp, leftlen, " %X:%d", + i, boardp->device[i]->queue_depth); + ASC_PRT_NEXT(); } - len = asc_prt_line(cp, leftlen, " %d:%d", - i, boardp->device[i]->queue_depth); + len = asc_prt_line(cp, leftlen, "\n"); ASC_PRT_NEXT(); } - len = asc_prt_line(cp, leftlen, "\n"); - ASC_PRT_NEXT(); #endif /* version >= v1.3.89 */ #if ASC_QUEUE_FLOW_CONTROL - len = asc_prt_line(cp, leftlen, -" queue_curr_depth:"); - ASC_PRT_NEXT(); - for (i = 0; i <= ASC_MAX_TID; i++) { - if ((boardp->asc_dvc_cfg.chip_scsi_id == i) || - ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) == 0)) { - continue; + if (ASC_NARROW_BOARD(boardp)) { + len = asc_prt_line(cp, leftlen, " queue_curr_depth:"); + ASC_PRT_NEXT(); + /* Use ASC_MAX_TID for Narrow Board. */ + for (i = 0; i <= ASC_MAX_TID; i++) { + if ((boardp->asc_dvc_cfg.chip_scsi_id == i) || + ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { + continue; + } + if (boardp->device[i] == NULL) { + continue; + } + len = asc_prt_line(cp, leftlen, " %d:%d", + i, boardp->device[i]->queue_curr_depth); + ASC_PRT_NEXT(); } - len = asc_prt_line(cp, leftlen, " %d:%d", - i, boardp->device[i]->queue_curr_depth); + len = asc_prt_line(cp, leftlen, "\n"); ASC_PRT_NEXT(); - } - len = asc_prt_line(cp, leftlen, "\n"); - ASC_PRT_NEXT(); - len = asc_prt_line(cp, leftlen, -" queue_count: "); - ASC_PRT_NEXT(); - for (i = 0; i <= ASC_MAX_TID; i++) { - if ((boardp->asc_dvc_cfg.chip_scsi_id == i) || - ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) == 0)) { - continue; + len = asc_prt_line(cp, leftlen, " queue_count:"); + ASC_PRT_NEXT(); + /* Use ASC_MAX_TID for Narrow Board. */ + for (i = 0; i <= ASC_MAX_TID; i++) { + if ((boardp->asc_dvc_cfg.chip_scsi_id == i) || + ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { + continue; + } + if (boardp->device[i] == NULL) { + continue; + } + len = asc_prt_line(cp, leftlen, " %d:%d", + i, boardp->device[i]->queue_count); + ASC_PRT_NEXT(); } - len = asc_prt_line(cp, leftlen, " %d:%d", - i, boardp->device[i]->queue_count); + len = asc_prt_line(cp, leftlen, "\n"); ASC_PRT_NEXT(); } - len = asc_prt_line(cp, leftlen, "\n"); - ASC_PRT_NEXT(); #endif /* ASC_QUEUE_FLOW_CONTROL */ - return totlen; + return totlen; } /* - * asc_prt_board_info() + * asc_prt_asc_board_info() * * Print dynamic board configuration information. * @@ -6061,7 +8701,7 @@ * 'cplen' characters will be copied to 'cp'. */ STATIC int -asc_prt_board_info(struct Scsi_Host *shp, char *cp, int cplen) +asc_prt_asc_board_info(struct Scsi_Host *shp, char *cp, int cplen) { asc_board_t *boardp; int leftlen; @@ -6072,8 +8712,8 @@ int i; boardp = ASC_BOARDP(shp); - v = &boardp->asc_dvc_var; - c = &boardp->asc_dvc_cfg; + v = &boardp->dvc_var.asc_dvc_var; + c = &boardp->dvc_cfg.asc_dvc_cfg; leftlen = cplen; totlen = len = 0; @@ -6084,30 +8724,30 @@ 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 %x, lib_serial_no %u, mcode_date %x\n", c->chip_version, c->lib_version, c->lib_serial_no, c->mcode_date); ASC_PRT_NEXT(); len = asc_prt_line(cp, leftlen, -" mcode_version %u, err_code %u\n", +" mcode_version %x, err_code %u\n", c->mcode_version, v->err_code); ASC_PRT_NEXT(); /* Current number of commands waiting for the host. */ len = asc_prt_line(cp, leftlen, -" Total Command Pending: %d\n", v->cur_total_qng); +" Total Command Pending: %d\n", v->cur_total_qng); ASC_PRT_NEXT(); len = asc_prt_line(cp, leftlen, -" Command Queuing: "); +" Command Queuing:"); ASC_PRT_NEXT(); for (i = 0; i <= ASC_MAX_TID; i++) { - if ((boardp->asc_dvc_cfg.chip_scsi_id == i) || - ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) == 0)) { + if ((boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id == i) || + ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { continue; } len = asc_prt_line(cp, leftlen, " %d:%c", - i, (v->use_tagged_qng & ASC_TIX_TO_TARGET_ID(i)) ? 'Y' : 'N'); + i, (v->use_tagged_qng & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); ASC_PRT_NEXT(); } len = asc_prt_line(cp, leftlen, "\n"); @@ -6115,11 +8755,11 @@ /* Current number of commands waiting for a device. */ len = asc_prt_line(cp, leftlen, -" Command Queue Pending: "); +" Command Queue Pending:"); ASC_PRT_NEXT(); for (i = 0; i <= ASC_MAX_TID; i++) { - if ((boardp->asc_dvc_cfg.chip_scsi_id == i) || - ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) == 0)) { + if ((boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id == i) || + ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { continue; } len = asc_prt_line(cp, leftlen, " %d:%u", i, v->cur_dvc_qng[i]); @@ -6130,11 +8770,11 @@ /* Current limit on number of commands that can be sent to a device. */ len = asc_prt_line(cp, leftlen, -" Command Queue Limit: "); +" Command Queue Limit:"); ASC_PRT_NEXT(); for (i = 0; i <= ASC_MAX_TID; i++) { - if ((boardp->asc_dvc_cfg.chip_scsi_id == i) || - ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) == 0)) { + if ((boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id == i) || + ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { continue; } len = asc_prt_line(cp, leftlen, " %d:%u", i, v->max_dvc_qng[i]); @@ -6145,14 +8785,14 @@ /* Indicate whether the device has returned queue full status. */ len = asc_prt_line(cp, leftlen, -" Command Queue Full: "); +" Command Queue Full:"); ASC_PRT_NEXT(); for (i = 0; i <= ASC_MAX_TID; i++) { - if ((boardp->asc_dvc_cfg.chip_scsi_id == i) || - ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) == 0)) { + if ((boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id == i) || + ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { continue; } - if (boardp->queue_full & ASC_TIX_TO_TARGET_ID(i)) { + if (boardp->queue_full & ADV_TID_TO_TIDMASK(i)) { len = asc_prt_line(cp, leftlen, " %d:Y-%d", i, boardp->queue_full_cnt[i]); } else { @@ -6164,15 +8804,15 @@ ASC_PRT_NEXT(); len = asc_prt_line(cp, leftlen, -" Synchronous Transfer: "); +" Synchronous Transfer:"); ASC_PRT_NEXT(); for (i = 0; i <= ASC_MAX_TID; i++) { - if ((boardp->asc_dvc_cfg.chip_scsi_id == i) || - ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) == 0)) { + if ((boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id == i) || + ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { continue; } len = asc_prt_line(cp, leftlen, " %d:%c", - i, (v->sdtr_done & ASC_TIX_TO_TARGET_ID(i)) ? 'Y' : 'N'); + i, (v->sdtr_done & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); ASC_PRT_NEXT(); } len = asc_prt_line(cp, leftlen, "\n"); @@ -6181,15 +8821,15 @@ for (i = 0; i <= ASC_MAX_TID; i++) { uchar syn_period_ix; - if ((boardp->asc_dvc_cfg.chip_scsi_id == i) || - ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) == 0)) { + if ((boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id == i) || + ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { continue; } - if ((v->sdtr_done & ASC_TIX_TO_TARGET_ID(i)) == 0) { + if ((v->sdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) { continue; } syn_period_ix = (boardp->sdtr_data[i] >> 4) & (v->max_sdtr_index - 1); - len = asc_prt_line(cp, leftlen, " %d:", i); + len = asc_prt_line(cp, leftlen, " %d:", i); ASC_PRT_NEXT(); len = asc_prt_line(cp, leftlen, @@ -6204,78 +8844,265 @@ ASC_PRT_NEXT(); } - return totlen; -} - -/* - * asc_proc_copy() - * - * Copy proc information to a read buffer taking into account the current - * read offset in the file and the remaining space in the read buffer. - */ -STATIC int -asc_proc_copy(off_t advoffset, off_t offset, char *curbuf, int leftlen, - char *cp, int cplen) -{ - int cnt = 0; - - ASC_DBG3(2, "asc_proc_copy: offset %d, advoffset %d, cplen %d\n", - (unsigned) offset, (unsigned) advoffset, cplen); - if (offset <= advoffset) { - /* Read offset below current offset, copy everything. */ - cnt = ASC_MIN(cplen, leftlen); - ASC_DBG3(2, "asc_proc_copy: curbuf %x, cp %x, cnt %d\n", - (unsigned) curbuf, (unsigned) cp, cnt); - memcpy(curbuf, cp, cnt); - } else if (offset < advoffset + cplen) { - /* Read offset within current range, partial copy. */ - cnt = (advoffset + cplen) - offset; - cp = (cp + cplen) - cnt; - cnt = ASC_MIN(cnt, leftlen); - ASC_DBG3(2, "asc_proc_copy: curbuf %x, cp %x, cnt %d\n", - (unsigned) curbuf, (unsigned) cp, cnt); - memcpy(curbuf, cp, cnt); - } - return cnt; + return totlen; } /* - * asc_prt_line() + * asc_prt_adv_board_info() * - * If 'cp' is NULL print to the console, otherwise print to a buffer. + * Print dynamic board configuration information. * - * Return 0 if printing to the console, otherwise return the number of - * bytes written to the buffer. + * Note: no single line should be greater than ASC_PRTLINE_SIZE, + * cf. asc_prt_line(). * - * Note: If any single line is greater than ASC_PRTLINE_SIZE bytes the stack - * will be corrupted. 's[]' is defined to be ASC_PRTLINE_SIZE bytes. + * Return the number of characters copied into 'cp'. No more than + * 'cplen' characters will be copied to 'cp'. */ STATIC int -asc_prt_line(char *buf, int buflen, char *fmt, ...) +asc_prt_adv_board_info(struct Scsi_Host *shp, char *cp, int cplen) { - va_list args; - int ret; - char s[ASC_PRTLINE_SIZE]; + asc_board_t *boardp; + int leftlen; + int totlen; + int len; + int i; + ADV_DVC_VAR *v; + ADV_DVC_CFG *c; + AdvPortAddr iop_base; + ushort chip_scsi_id; + ushort lramword; + uchar lrambyte; + ushort sdtr_able; + ushort period; - va_start(args, fmt); - ret = vsprintf(s, fmt, args); - ASC_ASSERT(ret < ASC_PRTLINE_SIZE); - if (buf == NULL) { - (void) printk(s); - ret = 0; - } else { - ret = ASC_MIN(buflen, ret); - memcpy(buf, s, ret); - } - va_end(args); - return ret; -} -#endif /* version >= v1.3.0 */ + boardp = ASC_BOARDP(shp); + v = &boardp->dvc_var.adv_dvc_var; + c = &boardp->dvc_cfg.adv_dvc_cfg; + iop_base = v->iop_base; + chip_scsi_id = v->chip_scsi_id; + leftlen = cplen; + totlen = len = 0; -/* - * --- Functions Required by the Asc Library - */ + len = asc_prt_line(cp, leftlen, +"\nAdv Library Configuration and Statistics for AdvanSys SCSI Host %d:\n", + shp->host_no); + ASC_PRT_NEXT(); + + len = asc_prt_line(cp, leftlen, +" iop_base %lx, cable_detect: %X, err_code %u, idle_cmd_done %u\n", + v->iop_base, + AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1) & CABLE_DETECT, + v->err_code, v->idle_cmd_done); + ASC_PRT_NEXT(); + + len = asc_prt_line(cp, leftlen, +" chip_version %u, lib_version %x, mcode_date %x, mcode_version %x\n", + c->chip_version, c->lib_version, c->mcode_date, c->mcode_version); + ASC_PRT_NEXT(); + + AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, lramword); + len = asc_prt_line(cp, leftlen, +" Queuing Enabled:"); + ASC_PRT_NEXT(); + for (i = 0; i <= ADV_MAX_TID; i++) { + if ((chip_scsi_id == i) || + ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { + continue; + } + + len = asc_prt_line(cp, leftlen, " %X:%c", + i, (lramword & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); + ASC_PRT_NEXT(); + } + len = asc_prt_line(cp, leftlen, "\n"); + ASC_PRT_NEXT(); + + len = asc_prt_line(cp, leftlen, +" Queue Limit:"); + ASC_PRT_NEXT(); + for (i = 0; i <= ADV_MAX_TID; i++) { + if ((chip_scsi_id == i) || + ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { + continue; + } + + AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + i, lrambyte); + + len = asc_prt_line(cp, leftlen, " %X:%d", i, lrambyte); + ASC_PRT_NEXT(); + } + len = asc_prt_line(cp, leftlen, "\n"); + ASC_PRT_NEXT(); + + len = asc_prt_line(cp, leftlen, +" Command Pending:"); + ASC_PRT_NEXT(); + for (i = 0; i <= ADV_MAX_TID; i++) { + if ((chip_scsi_id == i) || + ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { + continue; + } + + AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_QUEUED_CMD + i, lrambyte); + + len = asc_prt_line(cp, leftlen, " %X:%d", i, lrambyte); + ASC_PRT_NEXT(); + } + len = asc_prt_line(cp, leftlen, "\n"); + ASC_PRT_NEXT(); + + AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, lramword); + len = asc_prt_line(cp, leftlen, +" Wide Enabled:"); + ASC_PRT_NEXT(); + for (i = 0; i <= ADV_MAX_TID; i++) { + if ((chip_scsi_id == i) || + ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { + continue; + } + + len = asc_prt_line(cp, leftlen, " %X:%c", + i, (lramword & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); + ASC_PRT_NEXT(); + } + len = asc_prt_line(cp, leftlen, "\n"); + ASC_PRT_NEXT(); + + len = asc_prt_line(cp, leftlen, +" Transfer Bit Width:"); + ASC_PRT_NEXT(); + for (i = 0; i <= ADV_MAX_TID; i++) { + if ((chip_scsi_id == i) || + ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { + continue; + } + + AdvReadWordLram(iop_base, ASC_MC_DEVICE_HSHK_CFG_TABLE + (2 * i), + lramword); + len = asc_prt_line(cp, leftlen, " %X:%d", + i, (lramword & 0x8000) ? 16 : 8); + ASC_PRT_NEXT(); + } + len = asc_prt_line(cp, leftlen, "\n"); + ASC_PRT_NEXT(); + + AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able); + len = asc_prt_line(cp, leftlen, +" Synchronous Enabled:"); + ASC_PRT_NEXT(); + for (i = 0; i <= ADV_MAX_TID; i++) { + if ((chip_scsi_id == i) || + ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { + continue; + } + + len = asc_prt_line(cp, leftlen, " %X:%c", + i, (sdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); + ASC_PRT_NEXT(); + } + len = asc_prt_line(cp, leftlen, "\n"); + ASC_PRT_NEXT(); + + for (i = 0; i <= ADV_MAX_TID; i++) { + + AdvReadWordLram(iop_base, ASC_MC_DEVICE_HSHK_CFG_TABLE + (2 * i), + lramword); + lramword &= ~0x8000; + + if ((chip_scsi_id == i) || + ((sdtr_able & ADV_TID_TO_TIDMASK(i)) == 0) || + (lramword == 0)) { + continue; + } + + len = asc_prt_line(cp, leftlen, " %X:", i); + ASC_PRT_NEXT(); + + period = (((lramword >> 8) * 25) + 50)/4; + + len = asc_prt_line(cp, leftlen, + " Transfer Period Factor: %d (%d.%d Mhz),", + period, 250/period, ASC_TENTHS(250, period)); + ASC_PRT_NEXT(); + + len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d\n", + lramword & 0x1F); + ASC_PRT_NEXT(); + } + + return totlen; +} + +/* + * asc_proc_copy() + * + * Copy proc information to a read buffer taking into account the current + * read offset in the file and the remaining space in the read buffer. + */ +STATIC int +asc_proc_copy(off_t advoffset, off_t offset, char *curbuf, int leftlen, + char *cp, int cplen) +{ + int cnt = 0; + + ASC_DBG3(2, "asc_proc_copy: offset %d, advoffset %d, cplen %d\n", + (unsigned) offset, (unsigned) advoffset, cplen); + if (offset <= advoffset) { + /* Read offset below current offset, copy everything. */ + cnt = ASC_MIN(cplen, leftlen); + ASC_DBG3(2, "asc_proc_copy: curbuf %x, cp %x, cnt %d\n", + (unsigned) curbuf, (unsigned) cp, cnt); + memcpy(curbuf, cp, cnt); + } else if (offset < advoffset + cplen) { + /* Read offset within current range, partial copy. */ + cnt = (advoffset + cplen) - offset; + cp = (cp + cplen) - cnt; + cnt = ASC_MIN(cnt, leftlen); + ASC_DBG3(2, "asc_proc_copy: curbuf %x, cp %x, cnt %d\n", + (unsigned) curbuf, (unsigned) cp, cnt); + memcpy(curbuf, cp, cnt); + } + return cnt; +} + +/* + * asc_prt_line() + * + * If 'cp' is NULL print to the console, otherwise print to a buffer. + * + * Return 0 if printing to the console, otherwise return the number of + * bytes written to the buffer. + * + * Note: If any single line is greater than ASC_PRTLINE_SIZE bytes the stack + * will be corrupted. 's[]' is defined to be ASC_PRTLINE_SIZE bytes. + */ +STATIC int +asc_prt_line(char *buf, int buflen, char *fmt, ...) +{ + va_list args; + int ret; + char s[ASC_PRTLINE_SIZE]; + + va_start(args, fmt); + ret = vsprintf(s, fmt, args); + ASC_ASSERT(ret < ASC_PRTLINE_SIZE); + if (buf == NULL) { + (void) printk(s); + ret = 0; + } else { + ret = ASC_MIN(buflen, ret); + memcpy(buf, s, ret); + } + va_end(args); + return ret; +} +#endif /* version >= v1.3.0 */ + + +/* + * --- Functions Required by the Asc Library + */ /* * Delay for 'n' milliseconds. Don't use the 'jiffies' @@ -6413,7 +9240,6 @@ *inbuf = inpw(iop_base); } - /* * void DvcOutPortDWords(PortAddr port, ulong *pdw, int dwords) * @@ -6531,6 +9357,81 @@ /* + * --- Functions Required by the Adv Library + */ + +/* + * DvcGetPhyAddr() + * + * Return the physical address of 'vaddr' and set '*lenp' to the + * number of physically contiguous bytes that follow 'vaddr'. + * 'flag' indicates the type of structure whose physical address + * is being translated. + * + * Note: Because Linux currently doesn't page the kernel and all + * kernel buffers are physically contiguous, leave '*lenp' unchanged. + */ +ulong +DvcGetPhyAddr(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq, + uchar *vaddr, long *lenp, int flag) +{ + ulong paddr; + +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0) + paddr = (ulong) vaddr; +#else /* version >= v2.0.0 */ + paddr = virt_to_bus(vaddr); +#endif /* version >= v2.0.0 */ + + ASC_DBG4(4, + "DvcGetPhyAddr: vaddr 0x%lx, lenp 0x%lx *lenp %lu, paddr 0x%lx\n", + (ulong) vaddr, (ulong) lenp, (ulong) *((ulong *) lenp), paddr); + + return paddr; +} + +/* + * Read a PCI configuration byte. + */ +ASC_INITFUNC( +STATIC uchar +DvcAdvReadPCIConfigByte( + ADV_DVC_VAR *asc_dvc, + ushort offset) +) +{ + PCI_DATA pciData; + + pciData.bus = ASC_PCI_ID2BUS(asc_dvc->cfg->pci_slot_info); + pciData.slot = ASC_PCI_ID2DEV(asc_dvc->cfg->pci_slot_info); + pciData.func = ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info); + pciData.offset = offset; + pciData.type = pci_scan_method; + return asc_get_cfg_byte(&pciData); +} + +/* + * Write a PCI configuration byte. + */ +ASC_INITFUNC( +STATIC void +DvcAdvWritePCIConfigByte( + ADV_DVC_VAR *asc_dvc, + ushort offset, + uchar byte_data) +) +{ + PCI_DATA pciData; + + pciData.bus = ASC_PCI_ID2BUS(asc_dvc->cfg->pci_slot_info); + pciData.slot = ASC_PCI_ID2DEV(asc_dvc->cfg->pci_slot_info); + pciData.func = ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info); + pciData.offset = offset; + pciData.type = pci_scan_method; + asc_put_cfg_byte(&pciData, byte_data); +} + +/* * --- Tracing and Debugging Functions */ @@ -6550,15 +9451,19 @@ int leftlen; int totlen; int len; - struct asc_stats *s; + struct asc_stats *s; int i; + ushort chip_scsi_id; + asc_board_t *boardp; asc_queue_t *active; asc_queue_t *waiting; leftlen = cplen; totlen = len = 0; - s = &ASC_BOARDP(shp)->asc_stats; + boardp = ASC_BOARDP(shp); + s = &boardp->asc_stats; + len = asc_prt_line(cp, leftlen, "\nLinux Driver Statistics for AdvanSys SCSI Host %d:\n", shp->host_no); ASC_PRT_NEXT(); @@ -6569,13 +9474,24 @@ ASC_PRT_NEXT(); len = asc_prt_line(cp, leftlen, -" check_interrupt %lu, interrupt %lu, callback %lu, done %lu\n", - s->check_interrupt, s->interrupt, s->callback, s->done); +" interrupt %lu, callback %lu, done %lu\n", + s->interrupt, s->callback, s->done); ASC_PRT_NEXT(); len = asc_prt_line(cp, leftlen, -" asc_noerror %lu, asc_busy %lu, asc_error %lu, asc_unknown %lu\n", - s->asc_noerror, s->asc_busy, s->asc_error, s->asc_unknown); +" exe_noerror %lu, exe_busy %lu, exe_error %lu, exe_unknown %lu\n", + s->exe_noerror, s->exe_busy, s->exe_error, s->exe_unknown); + ASC_PRT_NEXT(); + + if (ASC_NARROW_BOARD(boardp)) { + len = asc_prt_line(cp, leftlen, +" build_error %lu\n", + s->build_error); + } else { + len = asc_prt_line(cp, leftlen, +" build_error %lu, build_noreq %lu, build_nosg %lu\n", + s->build_error, s->adv_build_noreq, s->adv_build_nosg); + } ASC_PRT_NEXT(); /* @@ -6629,12 +9545,25 @@ * Display request queuing statistics. */ len = asc_prt_line(cp, leftlen, -" Active and Waiting Request Queues (time unit: %d HZ):\n", HZ); +" Active and Waiting Request Queues (Time Unit: %d HZ):\n", HZ); ASC_PRT_NEXT(); active = &ASC_BOARDP(shp)->active; waiting = &ASC_BOARDP(shp)->waiting; - for (i = 0; i < ASC_MAX_TID + 1; i++) { + + if (ASC_NARROW_BOARD(boardp)) { + chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id; + } else { + chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id; + } + + for (i = 0; i <= ADV_MAX_TID; i++) { + + if ((chip_scsi_id == i) || + ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { + continue; + } + if (active->q_tot_cnt[i] > 0 || waiting->q_tot_cnt[i] > 0) { len = asc_prt_line(cp, leftlen, " target %d\n", i); ASC_PRT_NEXT(); @@ -6674,22 +9603,20 @@ STATIC void asc_prt_scsi_host(struct Scsi_Host *s) { + asc_board_t *boardp; + + boardp = ASC_BOARDP(s); + printk("Scsi_Host at addr %x\n", (unsigned) s); printk( " next %x, extra_bytes %u, host_busy %u, host_no %d, last_reset %d,\n", (unsigned) s->next, s->extra_bytes, s->host_busy, s->host_no, (unsigned) s->last_reset); -#ifdef ERIC_neverdef /* { */ - /* - * This information is private to the mid-layer scsi and the - * the low-level drivers shouldn't even be aware that it is there. - */ printk( " host_wait %x, host_queue %x, hostt %x, block %x,\n", (unsigned) s->host_wait, (unsigned) s->host_queue, (unsigned) s->hostt, (unsigned) s->block); -#endif /* ERIC_neverdef */ /* } */ printk( " wish_block %d, base %x, io_port %d, n_io_port %d, irq %d, dma_channel %d,\n", @@ -6704,8 +9631,13 @@ s->cmd_per_lun, s->sg_tablesize, s->unchecked_isa_dma, s->loaded_as_module); - asc_prt_dvc_var(&ASC_BOARDP(s)->asc_dvc_var); - asc_prt_dvc_cfg(&ASC_BOARDP(s)->asc_dvc_cfg); + if (ASC_NARROW_BOARD(boardp)) { + asc_prt_asc_dvc_var(&ASC_BOARDP(s)->dvc_var.asc_dvc_var); + asc_prt_asc_dvc_cfg(&ASC_BOARDP(s)->dvc_cfg.asc_dvc_cfg); + } else { + asc_prt_adv_dvc_var(&ASC_BOARDP(s)->dvc_var.adv_dvc_var); + asc_prt_adv_dvc_cfg(&ASC_BOARDP(s)->dvc_cfg.adv_dvc_cfg); + } } /* @@ -6763,10 +9695,10 @@ } /* - * asc_prt_dvc_var() + * asc_prt_asc_dvc_var() */ STATIC void -asc_prt_dvc_var(ASC_DVC_VAR *h) +asc_prt_asc_dvc_var(ASC_DVC_VAR *h) { printk("ASC_DVC_VAR at addr %x\n", (unsigned) h); @@ -6805,10 +9737,10 @@ } /* - * asc_prt_dvc_cfg() + * asc_prt_asc_dvc_cfg() */ STATIC void -asc_prt_dvc_cfg(ASC_DVC_CFG *h) +asc_prt_asc_dvc_cfg(ASC_DVC_CFG *h) { printk("ASC_DVC_CFG at addr %x\n", (unsigned) h); @@ -6822,7 +9754,7 @@ h->chip_version); printk( -" pci_device_id %d, lib_serial_no %d, lib_version %d, mcode_date %d,\n", +" pci_device_id %d, lib_serial_no %x, lib_version %x, mcode_date %x,\n", h->pci_device_id, h->lib_serial_no, h->lib_version, h->mcode_date); printk( @@ -6831,10 +9763,10 @@ } /* - * asc_prt_scsi_q() + * asc_prt_asc_scsi_q() */ STATIC void -asc_prt_scsi_q(ASC_SCSI_Q *q) +asc_prt_asc_scsi_q(ASC_SCSI_Q *q) { ASC_SG_HEAD *sgp; int i; @@ -6869,10 +9801,10 @@ } /* - * asc_prt_qdone_info() + * asc_prt_asc_qdone_info() */ STATIC void -asc_prt_qdone_info(ASC_QDONE_INFO *q) +asc_prt_asc_qdone_info(ASC_QDONE_INFO *q) { printk("ASC_QDONE_INFO at addr %x\n", (unsigned) q); printk( @@ -6885,33 +9817,185 @@ } /* - * asc_prt_hex() + * asc_prt_adv_dvc_var() * - * Print hexadecimal output in 4 byte groupings 32 bytes - * or 8 double-words per line. + * Display an ADV_DVC_VAR structure. */ STATIC void -asc_prt_hex(char *f, uchar *s, int l) +asc_prt_adv_dvc_var(ADV_DVC_VAR *h) { - int i; - int j; - int k; - int m; + printk(" ADV_DVC_VAR at addr 0x%lx\n", (ulong) h); - printk("%s: (%d bytes)\n", f, l); + printk( +" iop_base 0x%lx, err_code 0x%x, ultra_able 0x%x\n", + (ulong) h->iop_base, h->err_code, (unsigned) h->ultra_able); - for (i = 0; i < l; i += 32) { - - /* Display a maximum of 8 double-words per line. */ - if ((k = (l - i) / 4) >= 8) { - k = 8; - m = 0; - } else { - m = (l - i) % 4 ; - } + printk( +" isr_callback 0x%x, sdtr_able 0x%x, wdtr_able 0x%x\n", + (unsigned) h->isr_callback, (unsigned) h->wdtr_able, + (unsigned) h->sdtr_able); - for (j = 0; j < k; j++) { - printk(" %2.2X%2.2X%2.2X%2.2X", + printk( +" start_motor 0x%x, scsi_reset_wait 0x%x, irq_no 0x%x,\n", + (unsigned) h->start_motor, + (unsigned) h->scsi_reset_wait, (unsigned) h->irq_no); + + printk( +" max_host_qng 0x%x, cur_host_qng 0x%x, max_dvc_qng 0x%x\n", + (unsigned) h->max_host_qng, (unsigned) h->cur_host_qng, + (unsigned) h->max_dvc_qng); + + printk( +" no_scam 0x%x, tagqng_able 0x%x, chip_scsi_id 0x%x, cfg 0x%lx\n", + (unsigned) h->no_scam, (unsigned) h->tagqng_able, + (unsigned) h->chip_scsi_id, (ulong) h->cfg); + +} + +/* + * asc_prt_adv_dvc_cfg() + * + * Display an ADV_DVC_CFG structure. + */ +STATIC void +asc_prt_adv_dvc_cfg(ADV_DVC_CFG *h) +{ + printk(" ADV_DVC_CFG at addr 0x%lx\n", (ulong) h); + + printk( +" disc_enable 0x%x, termination 0x%x\n", + h->disc_enable, h->termination); + + printk( +" chip_version 0x%x, mcode_date 0x%x\n", + h->chip_version, h->mcode_date); + + printk( +" mcode_version 0x%x, pci_device_id 0x%x, lib_version 0x%x\n", + h->mcode_version, h->pci_device_id, h->lib_version); + + printk( +" control_flag 0x%x, pci_slot_info 0x%x\n", + h->control_flag, h->pci_slot_info); +} + +/* + * asc_prt_adv_scsi_req_q() + * + * Display an ADV_SCSI_REQ_Q structure. + */ +STATIC void +asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *q) +{ + int i; + struct asc_sg_block *sg_ptr; + + printk("ADV_SCSI_REQ_Q at addr %x\n", (unsigned) q); + + printk( +" target_id %u, target_lun %u, srb_ptr 0x%lx, a_flag 0x%x\n", + q->target_id, q->target_lun, q->srb_ptr, q->a_flag); + + printk(" cntl 0x%x, data_addr 0x%lx, vdata_addr 0x%lx\n", + q->cntl, q->data_addr, q->vdata_addr); + + printk( +" data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n", + q->data_cnt, q->sense_addr, q->sense_len); + + printk( +" cdb_len %u, done_status 0x%x, host_status 0x%x, scsi_status 0x%x\n", + q->cdb_len, q->done_status, q->host_status, q->scsi_status); + + printk( +" vsense_addr 0x%lx, scsiq_ptr 0x%lx, ux_wk_data_cnt %lu\n", + (ulong) q->vsense_addr, (ulong) q->scsiq_ptr, + (ulong) q->ux_wk_data_cnt); + + printk( +" sg_list_ptr 0x%lx, sg_real_addr 0x%lx, sg_entry_cnt %u\n", + (ulong) q->sg_list_ptr, (ulong) q->sg_real_addr, q->sg_entry_cnt); + + printk( +" ux_sg_ix %u, orig_sense_len %u\n", + q->ux_sg_ix, q->orig_sense_len); + + /* Display the request's ADV_SG_BLOCK structures. */ + for (sg_ptr = q->sg_list_ptr, i = 0; sg_ptr != NULL; + sg_ptr = sg_ptr->sg_ptr, i++) { + /* + * 'sg_ptr' is a physical address. Convert it to a virtual + * address by indexing 'i' into the virtual address array + * 'sg_list_ptr'. + * + * At the end of the each iteration of the loop 'sg_ptr' is + * converted back into a physical address by setting 'sg_ptr' + * to the next pointer 'sg_ptr->sg_ptr'. + */ + sg_ptr = &(((ADV_SG_BLOCK *) (q->sg_list_ptr))[i]); + asc_prt_adv_sgblock(i, sg_ptr); + } +} + +/* + * asc_prt_adv_sgblock() + * + * Display an ADV_SG_BLOCK structure. + */ +STATIC void +asc_prt_adv_sgblock(int sgblockno, ADV_SG_BLOCK *b) +{ + int i, s; + + /* Calculate starting entry number for the current block. */ + s = sgblockno * NO_OF_SG_PER_BLOCK; + + printk(" ADV_SG_BLOCK at addr 0x%lx (sgblockno %lu)\n", + (ulong) b, (ulong) sgblockno); + printk( +" first_entry_no %lu, last_entry_no %lu, sg_ptr 0x%lx\n", + (ulong) b->first_entry_no, (ulong) b->last_entry_no, (ulong) b->sg_ptr); + ASC_ASSERT(b->first_entry_no - s >= 0); + ASC_ASSERT(b->last_entry_no - s >= 0); + ASC_ASSERT(b->last_entry_no - s <= NO_OF_SG_PER_BLOCK); + ASC_ASSERT(b->first_entry_no - s <= NO_OF_SG_PER_BLOCK); + ASC_ASSERT(b->first_entry_no - s <= NO_OF_SG_PER_BLOCK); + ASC_ASSERT(b->first_entry_no - s <= b->last_entry_no - s); + for (i = b->first_entry_no - s; i <= b->last_entry_no - s; i++) { + printk(" [%lu]: sg_addr 0x%lx, sg_count 0x%lx\n", + (ulong) i, (ulong) b->sg_list[i].sg_addr, + (ulong) b->sg_list[i].sg_count); + } +} + +/* + * asc_prt_hex() + * + * Print hexadecimal output in 4 byte groupings 32 bytes + * or 8 double-words per line. + */ +STATIC void +asc_prt_hex(char *f, uchar *s, int l) +{ + int i; + int j; + int k; + int m; + + printk("%s: (%d bytes)\n", f, l); + + for (i = 0; i < l; i += 32) { + + /* Display a maximum of 8 double-words per line. */ + if ((k = (l - i) / 4) >= 8) { + k = 8; + m = 0; + } else { + m = (l - i) % 4 ; + } + + for (j = 0; j < k; j++) { + printk(" %2.2X%2.2X%2.2X%2.2X", (unsigned) s[i+(j*4)], (unsigned) s[i+(j*4)+1], (unsigned) s[i+(j*4)+2], (unsigned) s[i+(j*4)+3]); } @@ -6975,6 +10059,7 @@ ) { PortAddr eisa_cfg_iop; + eisa_cfg_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) | (PortAddr) (ASC_EISA_CFG_IOP_MASK); return (inpw(eisa_cfg_iop)); @@ -6989,6 +10074,7 @@ ) { ushort cfg_lsw; + if (AscGetChipScsiID(iop_base) == new_host_id) { return (new_host_id); } @@ -7007,6 +10093,7 @@ ) { uchar sc; + AscSetBank(iop_base, 1); sc = inp(iop_base + IOP_REG_SC); AscSetBank(iop_base, 0); @@ -7040,6 +10127,7 @@ ) { ushort chip_ver; + chip_ver = AscGetChipVerNo(iop_base); if ( (chip_ver >= ASC_CHIP_MIN_VER_VL) @@ -7079,6 +10167,7 @@ ulong chksum; ushort mcode_word_size; ushort mcode_chksum; + mcode_word_size = (ushort) (mcode_size >> 1); AscMemWordSetLram(iop_base, s_addr, 0, mcode_word_size); AscMemWordCopyToLram(iop_base, s_addr, mcode_buf, mcode_word_size); @@ -7099,6 +10188,7 @@ ) { ushort sig_word; + if (AscGetChipSignatureByte(iop_base) == (uchar) ASC_1000_ID1B) { sig_word = AscGetChipSignatureWord(iop_base); if ((sig_word == (ushort) ASC_1000_ID0W) || @@ -7162,6 +10252,7 @@ { int i; PortAddr iop_base; + for (i = 0; i < ASC_IOADR_TABLE_MAX_IX; i++) { if (_asc_def_iop_base[i] > s_addr) { break; @@ -7216,6 +10307,7 @@ { ushort cfg_lsw; uchar chip_irq; + if ((bus_type & ASC_IS_EISA) != 0) { cfg_lsw = AscGetEisaChipCfg(iop_base); chip_irq = (uchar) (((cfg_lsw >> 8) & 0x07) + 10); @@ -7232,11 +10324,6 @@ (chip_irq == 7)) { return (0); } -#if CC_PLEXTOR_VL - if (chip_irq == 5) { - return (9); - } -#endif return ((uchar) (chip_irq + (ASC_MIN_IRQ_NO - 1))); } cfg_lsw = AscGetChipCfgLsw(iop_base); @@ -7256,13 +10343,9 @@ ) { ushort cfg_lsw; + if ((bus_type & ASC_IS_VL) != 0) { if (irq_no != 0) { -#if CC_PLEXTOR_VL - if (irq_no == 9) { - irq_no = 14; - } -#endif if ((irq_no < ASC_MIN_IRQ_NO) || (irq_no > ASC_MAX_IRQ_NO)) { irq_no = 0; } else { @@ -7473,7 +10556,6 @@ q_cntl |= QC_REQ_SENSE; -#if CC_CHK_COND_REDO_SDTR if ((asc_dvc->init_sdtr & target_id) != 0) { asc_dvc->sdtr_done &= ~target_id; @@ -7485,7 +10567,6 @@ (uchar) (asc_dvc->max_sdtr_index - 1)], (uchar) (sdtr_data & (uchar) ASC_SYN_MAX_OFFSET)); } -#endif AscWriteLramByte(iop_base, (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_CNTL), @@ -7577,7 +10658,8 @@ boardp->queue_full |= target_id; boardp->queue_full_cnt[tid_no] = cur_dvc_qng; #if ASC_QUEUE_FLOW_CONTROL - if (boardp->device[tid_no]->queue_curr_depth > + if (boardp->device[tid_no] != NULL && + boardp->device[tid_no]->queue_curr_depth > cur_dvc_qng) { boardp->device[tid_no]->queue_curr_depth = cur_dvc_qng; @@ -7602,13 +10684,11 @@ { ushort _val; uchar sg_queue_cnt; + DvcGetQinfo(iop_base, (ushort) (q_addr + (ushort) ASC_SCSIQ_DONE_INFO_BEG), (ushort *) scsiq, (ushort) ((sizeof (ASC_SCSIQ_2) + sizeof (ASC_SCSIQ_3)) / 2)); -#if !CC_LITTLE_ENDIAN_HOST - AscAdjEndianQDoneInfo(scsiq); -#endif _val = AscReadLramWord(iop_base, (ushort) (q_addr + (ushort) ASC_SCSIQ_B_STATUS)); scsiq->q_status = (uchar) _val; @@ -7649,6 +10729,7 @@ REG ASC_QDONE_INFO *scsiq; int false_overrun; ASC_ISR_CALLBACK asc_isr_callback; + iop_base = asc_dvc->iop_base; asc_isr_callback = (ASC_ISR_CALLBACK) asc_dvc->isr_callback; n_q_used = 1; @@ -7731,18 +10812,13 @@ AscStopChip(iop_base); AscSetChipControl(iop_base, (uchar) (CC_SCSI_RESET | CC_HALT)); - DvcDelayNanoSecond(asc_dvc, 30000); + DvcDelayNanoSecond(asc_dvc, 60000); AscSetChipControl(iop_base, CC_HALT); AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT); AscSetChipStatus(iop_base, 0); AscSetChipControl(iop_base, 0); } } -#if CC_CLEAR_LRAM_SRB_PTR - AscWriteLramDWord(iop_base, - (ushort) (q_addr + (ushort) ASC_SCSIQ_D_SRBPTR), - asc_dvc->int_count); -#endif if ((scsiq->cntl & QC_NO_CALLBACK) == 0) { (*asc_isr_callback) (asc_dvc, scsiq); } else { @@ -7781,6 +10857,7 @@ int int_pending; int status; uchar host_flag; + iop_base = asc_dvc->iop_base; int_pending = FALSE; if (((asc_dvc->init_state & ASC_INIT_STATE_END_LOAD_MC) == 0) @@ -7819,12 +10896,10 @@ ASCV_HOST_FLAG_B) & (uchar) (~ASC_HOST_FLAG_IN_ISR); AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, (uchar) (host_flag | (uchar) ASC_HOST_FLAG_IN_ISR)); -#if CC_ASCISR_CHECK_INT_PENDING if ((chipstat & CSW_INT_PENDING) || (int_pending) ) { AscAckInterrupt(iop_base); -#endif int_pending = TRUE; if ((chipstat & CSW_HALTED) && (ctrl_reg & CC_SINGLE_STEP)) { @@ -7848,9 +10923,7 @@ if ((status & 0x80) != 0) int_pending = ERR; } -#if CC_ASCISR_CHECK_INT_PENDING } -#endif AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag); AscSetChipLramAddr(iop_base, saved_ram_addr); AscSetChipControl(iop_base, saved_ctrl_reg); @@ -7867,6 +10940,7 @@ ) { ulong phy_addr; + scsiq->r1.cntl = 0; scsiq->r1.sg_queue_cnt = 0; scsiq->r1.q_no = 0; @@ -7901,155 +10975,156 @@ return (0); } -STATIC uchar _mcode_buf[] ASC_INITDATA = +STATIC uchar _asc_mcode_buf[] ASC_INITDATA = { - 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, 0x79, 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, 0x22, 0x00, 0x00, 0x00, 0x07, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCC, 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, - 0x08, 0x98, 0x50, 0x00, 0xF5, 0x00, 0x32, 0x98, 0xDF, 0x23, 0x36, 0x60, 0xB6, 0x00, 0x92, 0x80, - 0x4F, 0x00, 0xF5, 0x00, 0x32, 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, 0x90, 0x97, 0x7F, 0x23, 0x04, 0x61, 0x84, 0x01, 0xD8, 0x84, 0xD2, 0xC1, - 0x80, 0x73, 0xCD, 0x04, 0x4D, 0x00, 0x00, 0xA3, 0xE2, 0x01, 0x90, 0x97, 0xCE, 0x81, 0x00, 0x33, - 0x02, 0x00, 0xAA, 0x88, 0x80, 0x73, 0x80, 0x77, 0x00, 0x01, 0x01, 0xA1, 0x02, 0x01, 0x4F, 0x00, - 0x6E, 0x97, 0x07, 0xA6, 0x0C, 0x01, 0x00, 0x33, 0x03, 0x00, 0xAA, 0x88, 0x03, 0x03, 0x03, 0xDE, - 0x00, 0x33, 0x05, 0x00, 0xAA, 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, 0xAA, 0x88, 0x03, 0x07, 0x02, 0x01, - 0x04, 0xCA, 0x0D, 0x23, 0x52, 0x98, 0x4D, 0x04, 0xF6, 0x84, 0x05, 0xD8, 0x0D, 0x23, 0x52, 0x98, - 0xCD, 0x04, 0x15, 0x23, 0xE0, 0x88, 0xFB, 0x23, 0x02, 0x61, 0x82, 0x01, 0x80, 0x63, 0x02, 0x03, - 0x06, 0xA3, 0x6A, 0x01, 0x00, 0x33, 0x0A, 0x00, 0xAA, 0x88, 0x4E, 0x00, 0x07, 0xA3, 0x76, 0x01, - 0x00, 0x33, 0x0B, 0x00, 0xAA, 0x88, 0xCD, 0x04, 0x36, 0x2D, 0x00, 0x33, 0x1A, 0x00, 0xAA, 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, 0x30, 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, 0xAA, 0x88, 0x06, 0x23, 0x52, 0x98, 0xCD, 0x04, 0xD8, 0x84, 0x06, 0x01, - 0x00, 0xA2, 0xDC, 0x01, 0x57, 0x60, 0x00, 0xA0, 0xE2, 0x01, 0xD8, 0x84, 0x80, 0x23, 0xA0, 0x01, - 0xD8, 0x84, 0x80, 0x73, 0x4B, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x08, 0x02, 0x04, 0x01, 0x0C, 0xDE, - 0x02, 0x01, 0x03, 0xCC, 0x4F, 0x00, 0x6E, 0x97, 0x04, 0x82, 0x08, 0x23, 0x02, 0x41, 0x82, 0x01, - 0x4F, 0x00, 0x4C, 0x97, 0x48, 0x04, 0x84, 0x80, 0xDA, 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, 0xE0, 0x88, 0xEE, 0x97, 0xF4, 0x80, 0x80, 0x73, 0x80, 0x77, 0x06, 0xA6, 0x36, 0x02, - 0x00, 0x33, 0x31, 0x00, 0xAA, 0x88, 0x04, 0x01, 0x03, 0xD8, 0x9C, 0x98, 0x44, 0x96, 0x48, 0x82, - 0xD4, 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, 0xAA, 0x88, - 0x6E, 0x95, 0x4A, 0x82, 0x3A, 0x96, 0x4A, 0x82, 0x04, 0x23, 0xA0, 0x01, 0x14, 0x23, 0xA1, 0x01, - 0x2E, 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, 0xB0, 0x02, 0x07, 0xA6, 0x60, 0x02, 0x06, 0xA6, 0x64, 0x02, 0x03, 0xA6, - 0x12, 0x04, 0x01, 0xA6, 0xBA, 0x02, 0x00, 0xA6, 0xBA, 0x02, 0x00, 0x33, 0x12, 0x00, 0xAA, 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, 0xF0, 0x82, 0x18, 0x23, 0x04, 0x61, 0x18, 0xA0, 0xE8, 0x02, 0x04, 0x01, - 0x98, 0xC8, 0x00, 0x33, 0x1F, 0x00, 0xAA, 0x88, 0x08, 0x31, 0x0A, 0x35, 0x0C, 0x39, 0x0E, 0x3D, - 0x68, 0x98, 0xB6, 0x2D, 0x01, 0xA6, 0x1A, 0x03, 0x00, 0xA6, 0x1A, 0x03, 0x07, 0xA6, 0x12, 0x03, - 0x06, 0xA6, 0x16, 0x03, 0x03, 0xA6, 0x12, 0x04, 0x02, 0xA6, 0x72, 0x02, 0x00, 0x33, 0x33, 0x00, - 0xAA, 0x88, 0x6E, 0x95, 0xF4, 0x82, 0x3A, 0x96, 0xF4, 0x82, 0x6C, 0x98, 0x80, 0x42, 0x68, 0x98, - 0x60, 0xE4, 0x04, 0x01, 0x29, 0xC8, 0x31, 0x05, 0x07, 0x01, 0x00, 0xA2, 0x5A, 0x03, 0x00, 0x43, - 0x87, 0x01, 0x05, 0x05, 0x70, 0x98, 0x68, 0x98, 0x00, 0xA6, 0x1C, 0x03, 0x07, 0xA6, 0x52, 0x03, - 0x03, 0xA6, 0x2E, 0x04, 0x06, 0xA6, 0x56, 0x03, 0x01, 0xA6, 0x1C, 0x03, 0x00, 0x33, 0x25, 0x00, - 0xAA, 0x88, 0x6E, 0x95, 0x38, 0x83, 0x3A, 0x96, 0x38, 0x83, 0x04, 0x01, 0x0C, 0xCE, 0x03, 0xC8, - 0x00, 0x33, 0x42, 0x00, 0xAA, 0x88, 0x00, 0x01, 0x05, 0x05, 0xFF, 0xA2, 0x78, 0x03, 0xB1, 0x01, - 0x08, 0x23, 0xB2, 0x01, 0x34, 0x83, 0x05, 0x05, 0x15, 0x01, 0x00, 0xA2, 0x98, 0x03, 0xEC, 0x00, - 0x6E, 0x00, 0x95, 0x01, 0x6C, 0x38, 0x00, 0x3F, 0x00, 0x00, 0x01, 0xA6, 0x94, 0x03, 0x00, 0xA6, - 0x94, 0x03, 0x08, 0x84, 0x80, 0x42, 0x68, 0x98, 0x01, 0xA6, 0xA2, 0x03, 0x00, 0xA6, 0xBA, 0x03, - 0x08, 0x84, 0x90, 0x98, 0x80, 0x42, 0x01, 0xA6, 0xA2, 0x03, 0x07, 0xA6, 0xB0, 0x03, 0xD2, 0x83, - 0x6E, 0x95, 0xA6, 0x83, 0x00, 0x33, 0x2F, 0x00, 0xAA, 0x88, 0x90, 0x98, 0x80, 0x42, 0x00, 0xA6, - 0xBA, 0x03, 0x07, 0xA6, 0xC8, 0x03, 0xD2, 0x83, 0x6E, 0x95, 0xBE, 0x83, 0x00, 0x33, 0x26, 0x00, - 0xAA, 0x88, 0x38, 0x2B, 0x80, 0x32, 0x80, 0x36, 0x04, 0x23, 0xA0, 0x01, 0x12, 0x23, 0xA1, 0x01, - 0x08, 0x84, 0x04, 0xF0, 0x80, 0x6B, 0x00, 0x33, 0x20, 0x00, 0xAA, 0x88, 0x03, 0xA6, 0x06, 0x04, - 0x07, 0xA6, 0xFE, 0x03, 0x06, 0xA6, 0x02, 0x04, 0x00, 0x33, 0x17, 0x00, 0xAA, 0x88, 0x6E, 0x95, - 0xEC, 0x83, 0x3A, 0x96, 0xEC, 0x83, 0x12, 0x84, 0x04, 0xF0, 0x80, 0x6B, 0x00, 0x33, 0x20, 0x00, - 0xAA, 0x88, 0xB6, 0x2D, 0x03, 0xA6, 0x2E, 0x04, 0x07, 0xA6, 0x26, 0x04, 0x06, 0xA6, 0x2A, 0x04, - 0x00, 0x33, 0x30, 0x00, 0xAA, 0x88, 0x6E, 0x95, 0x12, 0x84, 0x3A, 0x96, 0x12, 0x84, 0x1D, 0x01, - 0x06, 0xCC, 0x00, 0x33, 0x00, 0x84, 0xC0, 0x20, 0x00, 0x23, 0xEA, 0x00, 0x81, 0x62, 0xA2, 0x0D, - 0x80, 0x63, 0x07, 0xA6, 0x4C, 0x04, 0x00, 0x33, 0x18, 0x00, 0xAA, 0x88, 0x03, 0x03, 0x80, 0x63, - 0xA3, 0x01, 0x07, 0xA4, 0x56, 0x04, 0x23, 0x01, 0x00, 0xA2, 0x78, 0x04, 0x0A, 0xA0, 0x68, 0x04, - 0xE0, 0x00, 0x00, 0x33, 0x1D, 0x00, 0xAA, 0x88, 0x0B, 0xA0, 0x74, 0x04, 0xE0, 0x00, 0x00, 0x33, - 0x1E, 0x00, 0xAA, 0x88, 0x42, 0x23, 0xE0, 0x88, 0x00, 0x23, 0x22, 0xA3, 0xD8, 0x04, 0x08, 0x23, - 0x22, 0xA3, 0x94, 0x04, 0x28, 0x23, 0x22, 0xA3, 0xA0, 0x04, 0x02, 0x23, 0x22, 0xA3, 0xB6, 0x04, - 0x42, 0x23, 0xE0, 0x88, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA0, 0xA0, 0x04, 0x45, 0x23, 0xE0, 0x88, - 0xEE, 0x97, 0x00, 0xA2, 0xB2, 0x04, 0x9C, 0x98, 0x00, 0x33, 0x00, 0x82, 0xC0, 0x20, 0x81, 0x62, - 0xF0, 0x81, 0x47, 0x23, 0xE0, 0x88, 0x04, 0x01, 0x0B, 0xDE, 0xEE, 0x97, 0x9C, 0x98, 0x00, 0x33, - 0x00, 0x81, 0xC0, 0x20, 0x81, 0x62, 0x14, 0x01, 0x00, 0xA0, 0x08, 0x02, 0x43, 0x23, 0xE0, 0x88, - 0x04, 0x23, 0xA0, 0x01, 0x44, 0x23, 0xA1, 0x01, 0x80, 0x73, 0x4D, 0x00, 0x03, 0xA3, 0xE6, 0x04, - 0x00, 0x33, 0x27, 0x00, 0xAA, 0x88, 0x04, 0x01, 0x04, 0xDC, 0x02, 0x23, 0xA2, 0x01, 0x04, 0x23, - 0xA0, 0x01, 0xEE, 0x97, 0x18, 0x95, 0x4B, 0x00, 0xF6, 0x00, 0x4F, 0x04, 0x4F, 0x00, 0x00, 0xA3, - 0x14, 0x05, 0x00, 0x05, 0x76, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x0E, 0x05, 0xFC, 0x84, 0x30, 0x97, - 0xCD, 0x04, 0x16, 0x85, 0x48, 0x04, 0x84, 0x80, 0x02, 0x01, 0x03, 0xDA, 0x80, 0x23, 0x82, 0x01, - 0x26, 0x85, 0x02, 0x23, 0xA0, 0x01, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x32, 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, 0x52, 0x05, 0x77, 0x04, 0x01, 0x23, - 0xEA, 0x00, 0x5D, 0x00, 0xFE, 0xC7, 0x00, 0x62, 0x00, 0x23, 0xEA, 0x00, 0x00, 0x63, 0x07, 0xA4, - 0xD2, 0x05, 0x03, 0x03, 0x02, 0xA0, 0x80, 0x05, 0xCE, 0x85, 0x00, 0x33, 0x2D, 0x00, 0xAA, 0x88, - 0x04, 0xA0, 0xA6, 0x05, 0x80, 0x63, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x92, 0x05, 0x1D, 0x01, - 0x06, 0xD6, 0x02, 0x23, 0x02, 0x41, 0x82, 0x01, 0x50, 0x00, 0x4C, 0x97, 0xF6, 0x84, 0x04, 0x23, - 0x02, 0x41, 0x82, 0x01, 0xF6, 0x84, 0x08, 0xA0, 0xAC, 0x05, 0xCE, 0x85, 0x03, 0xA0, 0xB2, 0x05, - 0xCE, 0x85, 0x01, 0xA0, 0xBC, 0x05, 0x88, 0x00, 0x80, 0x63, 0xAA, 0x86, 0x07, 0xA0, 0xC8, 0x05, - 0x06, 0x23, 0x52, 0x98, 0x48, 0x23, 0xE0, 0x88, 0x07, 0x23, 0x80, 0x00, 0xF0, 0x86, 0x80, 0x63, - 0x6E, 0x85, 0x00, 0x63, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x10, 0x06, 0x1D, 0x01, 0x18, 0xD4, - 0xC0, 0x23, 0x07, 0x41, 0x83, 0x03, 0x80, 0x63, 0x06, 0xA6, 0xF2, 0x05, 0x00, 0x33, 0x37, 0x00, - 0xAA, 0x88, 0x1D, 0x01, 0x02, 0xD6, 0x46, 0x23, 0xE0, 0x88, 0x63, 0x60, 0x83, 0x03, 0x80, 0x63, - 0x06, 0xA6, 0x0A, 0x06, 0x00, 0x33, 0x38, 0x00, 0xAA, 0x88, 0xEF, 0x04, 0x6F, 0x00, 0x00, 0x63, - 0x4B, 0x00, 0x06, 0x41, 0xCB, 0x00, 0x52, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x28, 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, 0x56, 0x06, 0x07, 0xA6, 0x6E, 0x05, 0x02, 0xA6, 0xE4, 0x06, - 0x00, 0x33, 0x39, 0x00, 0xAA, 0x88, 0x00, 0x00, 0x01, 0xA0, 0xFE, 0x06, 0xD4, 0x95, 0x83, 0x03, - 0x80, 0x63, 0x06, 0xA6, 0x6A, 0x06, 0x07, 0xA6, 0x6E, 0x05, 0x00, 0x00, 0x01, 0xA0, 0xFE, 0x06, - 0x00, 0x2B, 0x40, 0x0E, 0x80, 0x63, 0x01, 0x00, 0x06, 0xA6, 0x86, 0x06, 0x07, 0xA6, 0x6E, 0x05, - 0x00, 0x33, 0x3A, 0x00, 0xAA, 0x88, 0x40, 0x0E, 0x80, 0x63, 0x00, 0x43, 0x00, 0xA0, 0x78, 0x06, - 0x06, 0xA6, 0x9E, 0x06, 0x07, 0xA6, 0x6E, 0x05, 0x00, 0x33, 0x3B, 0x00, 0xAA, 0x88, 0x80, 0x67, - 0x40, 0x0E, 0x80, 0x63, 0x07, 0xA6, 0x6E, 0x05, 0x00, 0x63, 0x07, 0xA6, 0xB4, 0x06, 0x00, 0x33, - 0x2A, 0x00, 0xAA, 0x88, 0x03, 0x03, 0x80, 0x63, 0x89, 0x00, 0x0A, 0x2B, 0x07, 0xA6, 0xC6, 0x06, - 0x00, 0x33, 0x29, 0x00, 0xAA, 0x88, 0x00, 0x43, 0x00, 0xA2, 0xD2, 0x06, 0xC0, 0x0E, 0x80, 0x63, - 0xBC, 0x86, 0xC0, 0x0E, 0x00, 0x33, 0x00, 0x80, 0xC0, 0x20, 0x81, 0x62, 0x04, 0x01, 0x08, 0xDA, - 0x80, 0x63, 0x6E, 0x85, 0x80, 0x67, 0x00, 0x33, 0x00, 0x40, 0xC0, 0x20, 0x81, 0x62, 0x00, 0x63, - 0x80, 0x7B, 0x80, 0x63, 0x06, 0xA6, 0x62, 0x06, 0x00, 0x33, 0x2C, 0x00, 0xAA, 0x88, 0x0C, 0xA2, - 0x18, 0x07, 0xD4, 0x95, 0x83, 0x03, 0x80, 0x63, 0x06, 0xA6, 0x16, 0x07, 0x07, 0xA6, 0x6E, 0x05, - 0x00, 0x33, 0x3D, 0x00, 0xAA, 0x88, 0x00, 0x00, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0x0C, 0xA0, - 0x2E, 0x07, 0x07, 0xA6, 0x6E, 0x05, 0xBF, 0x23, 0x04, 0x61, 0x84, 0x01, 0xD8, 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, 0xAE, 0x07, 0x00, 0x33, 0x07, 0x00, 0xAA, 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, 0xCE, 0x07, 0x00, 0x05, 0xC4, 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, 0xFE, 0x07, 0x00, 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, 0x2E, 0x08, 0x74, 0x04, 0x02, 0x01, 0xF7, 0xC9, - 0xF6, 0xD9, 0x00, 0x01, 0x01, 0xA1, 0x0E, 0x08, 0xEE, 0x97, 0x18, 0x95, 0x0E, 0x88, 0x73, 0x04, - 0x00, 0x63, 0xF3, 0x04, 0x75, 0x04, 0x44, 0x88, 0x02, 0x01, 0x04, 0xD8, 0x30, 0x97, 0xEE, 0x97, - 0x18, 0x95, 0x34, 0x88, 0x75, 0x00, 0x00, 0xA3, 0x4E, 0x08, 0x00, 0x05, 0x38, 0x88, 0x73, 0x04, - 0x00, 0x63, 0x80, 0x7B, 0x80, 0x63, 0x06, 0xA6, 0x60, 0x08, 0x00, 0x33, 0x3E, 0x00, 0xAA, 0x88, - 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0x00, 0x63, 0x38, 0x2B, 0x86, 0x88, 0x38, 0x2B, 0x7C, 0x88, - 0x32, 0x09, 0x31, 0x05, 0x7C, 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, 0x9C, 0x08, 0x5D, 0x00, 0xFE, 0xC3, 0x00, 0x63, 0x80, 0x73, 0xE6, 0x20, 0x02, 0x23, - 0xE8, 0x00, 0x82, 0x73, 0xFF, 0xFD, 0x80, 0x73, 0x13, 0x23, 0xE0, 0x88, 0x66, 0x20, 0xC0, 0x20, - 0x04, 0x23, 0xA0, 0x01, 0xA1, 0x23, 0xA1, 0x01, 0x81, 0x62, 0xCA, 0x88, 0x80, 0x73, 0x80, 0x77, - 0x68, 0x00, 0x00, 0xA2, 0x80, 0x00, 0x03, 0xC2, 0xF1, 0xC7, 0x41, 0x23, 0xE0, 0x88, 0x11, 0x23, - 0xA1, 0x01, 0x04, 0x23, 0xA0, 0x01, 0xD8, 0x84, + 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, 0xDB, 0x0C, 0x0A, 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, 0x23, 0x00, 0x00, 0x00, 0x07, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD4, 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, + 0x10, 0x98, 0x50, 0x00, 0xF5, 0x00, 0x3A, 0x98, 0xDF, 0x23, 0x36, 0x60, 0xB6, 0x00, 0x92, 0x80, + 0x4F, 0x00, 0xF5, 0x00, 0x3A, 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, 0x98, 0x97, 0x7F, 0x23, 0x04, 0x61, 0x84, 0x01, 0xE0, 0x84, 0xD2, 0xC1, + 0x80, 0x73, 0xCD, 0x04, 0x4D, 0x00, 0x00, 0xA3, 0xE2, 0x01, 0x98, 0x97, 0xCE, 0x81, 0x00, 0x33, + 0x02, 0x00, 0xB2, 0x88, 0x80, 0x73, 0x80, 0x77, 0x00, 0x01, 0x01, 0xA1, 0x02, 0x01, 0x4F, 0x00, + 0x76, 0x97, 0x07, 0xA6, 0x0C, 0x01, 0x00, 0x33, 0x03, 0x00, 0xB2, 0x88, 0x03, 0x03, 0x03, 0xDE, + 0x00, 0x33, 0x05, 0x00, 0xB2, 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, 0xB2, 0x88, 0x03, 0x07, 0x02, 0x01, + 0x04, 0xCA, 0x0D, 0x23, 0x5A, 0x98, 0x4D, 0x04, 0xFE, 0x84, 0x05, 0xD8, 0x0D, 0x23, 0x5A, 0x98, + 0xCD, 0x04, 0x15, 0x23, 0xE8, 0x88, 0xFB, 0x23, 0x02, 0x61, 0x82, 0x01, 0x80, 0x63, 0x02, 0x03, + 0x06, 0xA3, 0x6A, 0x01, 0x00, 0x33, 0x0A, 0x00, 0xB2, 0x88, 0x4E, 0x00, 0x07, 0xA3, 0x76, 0x01, + 0x00, 0x33, 0x0B, 0x00, 0xB2, 0x88, 0xCD, 0x04, 0x36, 0x2D, 0x00, 0x33, 0x1A, 0x00, 0xB2, 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, 0x38, 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, 0xB2, 0x88, 0x06, 0x23, 0x5A, 0x98, 0xCD, 0x04, 0xE0, 0x84, 0x06, 0x01, + 0x00, 0xA2, 0xDC, 0x01, 0x57, 0x60, 0x00, 0xA0, 0xE2, 0x01, 0xE0, 0x84, 0x80, 0x23, 0xA0, 0x01, + 0xE0, 0x84, 0x80, 0x73, 0x4B, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x08, 0x02, 0x04, 0x01, 0x0C, 0xDE, + 0x02, 0x01, 0x03, 0xCC, 0x4F, 0x00, 0x76, 0x97, 0x04, 0x82, 0x08, 0x23, 0x02, 0x41, 0x82, 0x01, + 0x4F, 0x00, 0x54, 0x97, 0x48, 0x04, 0x84, 0x80, 0xE2, 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, 0xE8, 0x88, 0xF6, 0x97, 0xF4, 0x80, 0x80, 0x73, 0x80, 0x77, 0x06, 0xA6, 0x36, 0x02, + 0x00, 0x33, 0x31, 0x00, 0xB2, 0x88, 0x04, 0x01, 0x03, 0xD8, 0xA4, 0x98, 0x4C, 0x96, 0x48, 0x82, + 0xDC, 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, 0xB2, 0x88, + 0x76, 0x95, 0x4A, 0x82, 0x42, 0x96, 0x4A, 0x82, 0x04, 0x23, 0xA0, 0x01, 0x14, 0x23, 0xA1, 0x01, + 0x36, 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, 0xB0, 0x02, 0x07, 0xA6, 0x60, 0x02, 0x06, 0xA6, 0x64, 0x02, 0x03, 0xA6, + 0x1A, 0x04, 0x01, 0xA6, 0xBA, 0x02, 0x00, 0xA6, 0xBA, 0x02, 0x00, 0x33, 0x12, 0x00, 0xB2, 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, 0xF0, 0x82, 0x18, 0x23, 0x04, 0x61, 0x18, 0xA0, 0xE8, 0x02, 0x04, 0x01, + 0x9C, 0xC8, 0x00, 0x33, 0x1F, 0x00, 0xB2, 0x88, 0x08, 0x31, 0x0A, 0x35, 0x0C, 0x39, 0x0E, 0x3D, + 0x70, 0x98, 0xB6, 0x2D, 0x01, 0xA6, 0x1A, 0x03, 0x00, 0xA6, 0x1A, 0x03, 0x07, 0xA6, 0x12, 0x03, + 0x06, 0xA6, 0x16, 0x03, 0x03, 0xA6, 0x1A, 0x04, 0x02, 0xA6, 0x72, 0x02, 0x00, 0x33, 0x33, 0x00, + 0xB2, 0x88, 0x76, 0x95, 0xF4, 0x82, 0x42, 0x96, 0xF4, 0x82, 0x74, 0x98, 0x80, 0x42, 0x70, 0x98, + 0x60, 0xE4, 0x04, 0x01, 0x29, 0xC8, 0x31, 0x05, 0x07, 0x01, 0x00, 0xA2, 0x5A, 0x03, 0x00, 0x43, + 0x87, 0x01, 0x05, 0x05, 0x78, 0x98, 0x70, 0x98, 0x00, 0xA6, 0x1C, 0x03, 0x07, 0xA6, 0x52, 0x03, + 0x03, 0xA6, 0x36, 0x04, 0x06, 0xA6, 0x56, 0x03, 0x01, 0xA6, 0x1C, 0x03, 0x00, 0x33, 0x25, 0x00, + 0xB2, 0x88, 0x76, 0x95, 0x38, 0x83, 0x42, 0x96, 0x38, 0x83, 0x04, 0x01, 0x0C, 0xCE, 0x03, 0xC8, + 0x00, 0x33, 0x42, 0x00, 0xB2, 0x88, 0x00, 0x01, 0x05, 0x05, 0xFF, 0xA2, 0x78, 0x03, 0xB1, 0x01, + 0x08, 0x23, 0xB2, 0x01, 0x34, 0x83, 0x05, 0x05, 0x15, 0x01, 0x00, 0xA2, 0x98, 0x03, 0xEC, 0x00, + 0x6E, 0x00, 0x95, 0x01, 0x6C, 0x38, 0x00, 0x3F, 0x00, 0x00, 0x01, 0xA6, 0x94, 0x03, 0x00, 0xA6, + 0x94, 0x03, 0x0C, 0x84, 0x80, 0x42, 0x70, 0x98, 0x01, 0xA6, 0xA2, 0x03, 0x00, 0xA6, 0xBA, 0x03, + 0x0C, 0x84, 0x98, 0x98, 0x80, 0x42, 0x01, 0xA6, 0xA2, 0x03, 0x07, 0xA6, 0xB0, 0x03, 0xD2, 0x83, + 0x76, 0x95, 0xA6, 0x83, 0x00, 0x33, 0x2F, 0x00, 0xB2, 0x88, 0x98, 0x98, 0x80, 0x42, 0x00, 0xA6, + 0xBA, 0x03, 0x07, 0xA6, 0xC8, 0x03, 0xD2, 0x83, 0x76, 0x95, 0xBE, 0x83, 0x00, 0x33, 0x26, 0x00, + 0xB2, 0x88, 0x38, 0x2B, 0x80, 0x32, 0x80, 0x36, 0x04, 0x23, 0xA0, 0x01, 0x12, 0x23, 0xA1, 0x01, + 0x0C, 0x84, 0x06, 0xF0, 0x06, 0xA4, 0xF0, 0x03, 0x80, 0x6B, 0x05, 0x23, 0x83, 0x03, 0x80, 0x63, + 0x03, 0xA6, 0x0A, 0x04, 0x07, 0xA6, 0x02, 0x04, 0x06, 0xA6, 0x06, 0x04, 0x00, 0x33, 0x17, 0x00, + 0xB2, 0x88, 0x76, 0x95, 0xF0, 0x83, 0x42, 0x96, 0xF0, 0x83, 0x1A, 0x84, 0x06, 0xF0, 0x06, 0xA4, + 0x1A, 0x04, 0x80, 0x6B, 0x05, 0x23, 0x83, 0x03, 0x80, 0x63, 0xB6, 0x2D, 0x03, 0xA6, 0x36, 0x04, + 0x07, 0xA6, 0x2E, 0x04, 0x06, 0xA6, 0x32, 0x04, 0x00, 0x33, 0x30, 0x00, 0xB2, 0x88, 0x76, 0x95, + 0x1A, 0x84, 0x42, 0x96, 0x1A, 0x84, 0x1D, 0x01, 0x06, 0xCC, 0x00, 0x33, 0x00, 0x84, 0xC0, 0x20, + 0x00, 0x23, 0xEA, 0x00, 0x81, 0x62, 0xA2, 0x0D, 0x80, 0x63, 0x07, 0xA6, 0x54, 0x04, 0x00, 0x33, + 0x18, 0x00, 0xB2, 0x88, 0x03, 0x03, 0x80, 0x63, 0xA3, 0x01, 0x07, 0xA4, 0x5E, 0x04, 0x23, 0x01, + 0x00, 0xA2, 0x80, 0x04, 0x0A, 0xA0, 0x70, 0x04, 0xE0, 0x00, 0x00, 0x33, 0x1D, 0x00, 0xB2, 0x88, + 0x0B, 0xA0, 0x7C, 0x04, 0xE0, 0x00, 0x00, 0x33, 0x1E, 0x00, 0xB2, 0x88, 0x42, 0x23, 0xE8, 0x88, + 0x00, 0x23, 0x22, 0xA3, 0xE0, 0x04, 0x08, 0x23, 0x22, 0xA3, 0x9C, 0x04, 0x28, 0x23, 0x22, 0xA3, + 0xA8, 0x04, 0x02, 0x23, 0x22, 0xA3, 0xBE, 0x04, 0x42, 0x23, 0xE8, 0x88, 0x4A, 0x00, 0x06, 0x61, + 0x00, 0xA0, 0xA8, 0x04, 0x45, 0x23, 0xE8, 0x88, 0xF6, 0x97, 0x00, 0xA2, 0xBA, 0x04, 0xA4, 0x98, + 0x00, 0x33, 0x00, 0x82, 0xC0, 0x20, 0x81, 0x62, 0xF0, 0x81, 0x47, 0x23, 0xE8, 0x88, 0x04, 0x01, + 0x0B, 0xDE, 0xF6, 0x97, 0xA4, 0x98, 0x00, 0x33, 0x00, 0x81, 0xC0, 0x20, 0x81, 0x62, 0x14, 0x01, + 0x00, 0xA0, 0x08, 0x02, 0x43, 0x23, 0xE8, 0x88, 0x04, 0x23, 0xA0, 0x01, 0x44, 0x23, 0xA1, 0x01, + 0x80, 0x73, 0x4D, 0x00, 0x03, 0xA3, 0xEE, 0x04, 0x00, 0x33, 0x27, 0x00, 0xB2, 0x88, 0x04, 0x01, + 0x04, 0xDC, 0x02, 0x23, 0xA2, 0x01, 0x04, 0x23, 0xA0, 0x01, 0xF6, 0x97, 0x20, 0x95, 0x4B, 0x00, + 0xF6, 0x00, 0x4F, 0x04, 0x4F, 0x00, 0x00, 0xA3, 0x1C, 0x05, 0x00, 0x05, 0x76, 0x00, 0x06, 0x61, + 0x00, 0xA2, 0x16, 0x05, 0x04, 0x85, 0x38, 0x97, 0xCD, 0x04, 0x1E, 0x85, 0x48, 0x04, 0x84, 0x80, + 0x02, 0x01, 0x03, 0xDA, 0x80, 0x23, 0x82, 0x01, 0x2E, 0x85, 0x02, 0x23, 0xA0, 0x01, 0x4A, 0x00, + 0x06, 0x61, 0x00, 0xA2, 0x3A, 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, 0x5A, 0x05, 0x77, 0x04, 0x01, 0x23, 0xEA, 0x00, 0x5D, 0x00, 0xFE, 0xC7, 0x00, 0x62, + 0x00, 0x23, 0xEA, 0x00, 0x00, 0x63, 0x07, 0xA4, 0xDA, 0x05, 0x03, 0x03, 0x02, 0xA0, 0x88, 0x05, + 0xD6, 0x85, 0x00, 0x33, 0x2D, 0x00, 0xB2, 0x88, 0x04, 0xA0, 0xAE, 0x05, 0x80, 0x63, 0x4A, 0x00, + 0x06, 0x61, 0x00, 0xA2, 0x9A, 0x05, 0x1D, 0x01, 0x06, 0xD6, 0x02, 0x23, 0x02, 0x41, 0x82, 0x01, + 0x50, 0x00, 0x54, 0x97, 0xFE, 0x84, 0x04, 0x23, 0x02, 0x41, 0x82, 0x01, 0xFE, 0x84, 0x08, 0xA0, + 0xB4, 0x05, 0xD6, 0x85, 0x03, 0xA0, 0xBA, 0x05, 0xD6, 0x85, 0x01, 0xA0, 0xC4, 0x05, 0x88, 0x00, + 0x80, 0x63, 0xB2, 0x86, 0x07, 0xA0, 0xD0, 0x05, 0x06, 0x23, 0x5A, 0x98, 0x48, 0x23, 0xE8, 0x88, + 0x07, 0x23, 0x80, 0x00, 0xF8, 0x86, 0x80, 0x63, 0x76, 0x85, 0x00, 0x63, 0x4A, 0x00, 0x06, 0x61, + 0x00, 0xA2, 0x18, 0x06, 0x1D, 0x01, 0x18, 0xD4, 0xC0, 0x23, 0x07, 0x41, 0x83, 0x03, 0x80, 0x63, + 0x06, 0xA6, 0xFA, 0x05, 0x00, 0x33, 0x37, 0x00, 0xB2, 0x88, 0x1D, 0x01, 0x02, 0xD6, 0x46, 0x23, + 0xE8, 0x88, 0x63, 0x60, 0x83, 0x03, 0x80, 0x63, 0x06, 0xA6, 0x12, 0x06, 0x00, 0x33, 0x38, 0x00, + 0xB2, 0x88, 0xEF, 0x04, 0x6F, 0x00, 0x00, 0x63, 0x4B, 0x00, 0x06, 0x41, 0xCB, 0x00, 0x52, 0x00, + 0x06, 0x61, 0x00, 0xA2, 0x30, 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, 0x5E, 0x06, + 0x07, 0xA6, 0x76, 0x05, 0x02, 0xA6, 0xEC, 0x06, 0x00, 0x33, 0x39, 0x00, 0xB2, 0x88, 0x00, 0x00, + 0x01, 0xA0, 0x06, 0x07, 0xDC, 0x95, 0x83, 0x03, 0x80, 0x63, 0x06, 0xA6, 0x72, 0x06, 0x07, 0xA6, + 0x76, 0x05, 0x00, 0x00, 0x01, 0xA0, 0x06, 0x07, 0x00, 0x2B, 0x40, 0x0E, 0x80, 0x63, 0x01, 0x00, + 0x06, 0xA6, 0x8E, 0x06, 0x07, 0xA6, 0x76, 0x05, 0x00, 0x33, 0x3A, 0x00, 0xB2, 0x88, 0x40, 0x0E, + 0x80, 0x63, 0x00, 0x43, 0x00, 0xA0, 0x80, 0x06, 0x06, 0xA6, 0xA6, 0x06, 0x07, 0xA6, 0x76, 0x05, + 0x00, 0x33, 0x3B, 0x00, 0xB2, 0x88, 0x80, 0x67, 0x40, 0x0E, 0x80, 0x63, 0x07, 0xA6, 0x76, 0x05, + 0x00, 0x63, 0x07, 0xA6, 0xBC, 0x06, 0x00, 0x33, 0x2A, 0x00, 0xB2, 0x88, 0x03, 0x03, 0x80, 0x63, + 0x89, 0x00, 0x0A, 0x2B, 0x07, 0xA6, 0xCE, 0x06, 0x00, 0x33, 0x29, 0x00, 0xB2, 0x88, 0x00, 0x43, + 0x00, 0xA2, 0xDA, 0x06, 0xC0, 0x0E, 0x80, 0x63, 0xC4, 0x86, 0xC0, 0x0E, 0x00, 0x33, 0x00, 0x80, + 0xC0, 0x20, 0x81, 0x62, 0x04, 0x01, 0x08, 0xDA, 0x80, 0x63, 0x76, 0x85, 0x80, 0x67, 0x00, 0x33, + 0x00, 0x40, 0xC0, 0x20, 0x81, 0x62, 0x00, 0x63, 0x80, 0x7B, 0x80, 0x63, 0x06, 0xA6, 0x6A, 0x06, + 0x00, 0x33, 0x2C, 0x00, 0xB2, 0x88, 0x0C, 0xA2, 0x20, 0x07, 0xDC, 0x95, 0x83, 0x03, 0x80, 0x63, + 0x06, 0xA6, 0x1E, 0x07, 0x07, 0xA6, 0x76, 0x05, 0x00, 0x33, 0x3D, 0x00, 0xB2, 0x88, 0x00, 0x00, + 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0x0C, 0xA0, 0x36, 0x07, 0x07, 0xA6, 0x76, 0x05, 0xBF, 0x23, + 0x04, 0x61, 0x84, 0x01, 0xE0, 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, 0xB6, 0x07, + 0x00, 0x33, 0x07, 0x00, 0xB2, 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, + 0xD6, 0x07, 0x00, 0x05, 0xCC, 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, 0x06, 0x08, 0x08, 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, + 0x36, 0x08, 0x74, 0x04, 0x02, 0x01, 0xF7, 0xC9, 0xF6, 0xD9, 0x00, 0x01, 0x01, 0xA1, 0x16, 0x08, + 0xF6, 0x97, 0x20, 0x95, 0x16, 0x88, 0x73, 0x04, 0x00, 0x63, 0xF3, 0x04, 0x75, 0x04, 0x4C, 0x88, + 0x02, 0x01, 0x04, 0xD8, 0x38, 0x97, 0xF6, 0x97, 0x20, 0x95, 0x3C, 0x88, 0x75, 0x00, 0x00, 0xA3, + 0x56, 0x08, 0x00, 0x05, 0x40, 0x88, 0x73, 0x04, 0x00, 0x63, 0x80, 0x7B, 0x80, 0x63, 0x06, 0xA6, + 0x68, 0x08, 0x00, 0x33, 0x3E, 0x00, 0xB2, 0x88, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0x00, 0x63, + 0x38, 0x2B, 0x8E, 0x88, 0x38, 0x2B, 0x84, 0x88, 0x32, 0x09, 0x31, 0x05, 0x84, 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, 0xA4, 0x08, 0x5D, 0x00, 0xFE, 0xC3, + 0x00, 0x63, 0x80, 0x73, 0xE6, 0x20, 0x02, 0x23, 0xE8, 0x00, 0x82, 0x73, 0xFF, 0xFD, 0x80, 0x73, + 0x13, 0x23, 0xE8, 0x88, 0x66, 0x20, 0xC0, 0x20, 0x04, 0x23, 0xA0, 0x01, 0xA1, 0x23, 0xA1, 0x01, + 0x81, 0x62, 0xD2, 0x88, 0x80, 0x73, 0x80, 0x77, 0x68, 0x00, 0x00, 0xA2, 0x80, 0x00, 0x03, 0xC2, + 0xF1, 0xC7, 0x41, 0x23, 0xE8, 0x88, 0x11, 0x23, 0xA1, 0x01, 0x04, 0x23, 0xA0, 0x01, 0xE0, 0x84, + }; -STATIC ushort _mcode_size ASC_INITDATA = sizeof(_mcode_buf); -STATIC ulong _mcode_chksum ASC_INITDATA = 0x01297F32UL; +STATIC ushort _asc_mcode_size ASC_INITDATA = sizeof(_asc_mcode_buf); +STATIC ulong _asc_mcode_chksum ASC_INITDATA = 0x012A727FUL ; #define ASC_SYN_OFFSET_ONE_DISABLE_LIST 16 STATIC uchar _syn_offset_one_disable_cmd[ASC_SYN_OFFSET_ONE_DISABLE_LIST] = @@ -8096,6 +11171,7 @@ uchar disable_cmd; ASC_SG_HEAD *sg_head; ulong data_cnt; + iop_base = asc_dvc->iop_base; sg_head = scsiq->sg_head; asc_exe_callback = (ASC_EXE_CALLBACK) asc_dvc->exe_callback; @@ -8146,19 +11222,6 @@ scsiq->q1.cntl &= ~(QC_SG_HEAD | QC_SG_SWAP_QUEUE); } sg_entry_cnt_minus_one = sg_entry_cnt - 1; -#if CC_DEBUG_SG_LIST - if (asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL | ASC_IS_EISA)) { - for (i = 0; i < sg_entry_cnt_minus_one; i++) { - addr = sg_head->sg_list[i].addr + sg_head->sg_list[i].bytes; - if (((ushort) addr & 0x0003) != 0) { - asc_dvc->in_critical_cnt--; - DvcLeaveCritical(last_int_level); - AscSetLibErrorCode(asc_dvc, ASCQ_ERR_SG_LIST_ODD_ADDRESS); - return (ERR); - } - } - } -#endif } scsi_cmd = scsiq->cdbptr[0]; disable_syn_offset_one_fix = FALSE; @@ -8280,6 +11343,7 @@ uchar tid_no; uchar target_ix; int sta; + iop_base = asc_dvc->iop_base; target_ix = scsiq->q2.target_ix; tid_no = ASC_TIX_TO_TID(target_ix); @@ -8294,9 +11358,6 @@ scsiq->q1.q_no = free_q_head; if ((sta = AscPutReadySgListQueue(asc_dvc, scsiq, free_q_head)) == 1) { -#if CC_WRITE_IO_COUNT - asc_dvc->req_count++; -#endif AscPutVarFreeQHead(iop_base, next_qp); asc_dvc->cur_total_qng += (uchar) (n_q_required); asc_dvc->cur_dvc_qng[tid_no]++; @@ -8309,9 +11370,6 @@ scsiq->q1.q_no = free_q_head; if ((sta = AscPutReadyQueue(asc_dvc, scsiq, free_q_head)) == 1) { -#if CC_WRITE_IO_COUNT - asc_dvc->req_count++; -#endif AscPutVarFreeQHead(iop_base, next_qp); asc_dvc->cur_total_qng++; asc_dvc->cur_dvc_qng[tid_no]++; @@ -8328,6 +11386,7 @@ ) { int n_sg_list_qs; + n_sg_list_qs = ((sg_list - 1) / ASC_SG_LIST_PER_Q); if (((sg_list - 1) % ASC_SG_LIST_PER_Q) != 0) n_sg_list_qs++; @@ -8346,6 +11405,7 @@ uint cur_free_qs; ASC_SCSI_BIT_ID_TYPE target_id; uchar tid_no; + target_id = ASC_TIX_TO_TARGET_ID(target_ix); tid_no = ASC_TIX_TO_TID(target_ix); if ((asc_dvc->unit_not_ready & target_id) || @@ -8389,6 +11449,7 @@ uchar syn_period_ix; uchar syn_offset; PortAddr iop_base; + iop_base = asc_dvc->iop_base; if (((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) && ((asc_dvc->sdtr_done & scsiq->q1.target_id) == 0)) { @@ -8410,43 +11471,10 @@ (ushort) (q_addr + (ushort) ASC_SCSIQ_CDB_BEG), (ushort *) scsiq->cdbptr, (ushort) ((ushort) scsiq->q2.cdb_len >> 1)); -#if !CC_LITTLE_ENDIAN_HOST - AscAdjEndianScsiQ(scsiq); -#endif DvcPutScsiQ(iop_base, (ushort) (q_addr + (ushort) ASC_SCSIQ_CPY_BEG), (ushort *) & scsiq->q1.cntl, (ushort) ((((sizeof (ASC_SCSIQ_1) + sizeof (ASC_SCSIQ_2)) / 2) - 1))); -#if CC_WRITE_IO_COUNT - AscWriteLramWord(iop_base, - (ushort) (q_addr + (ushort) ASC_SCSIQ_W_REQ_COUNT), - (ushort) asc_dvc->req_count); -#endif -#if CC_VERIFY_LRAM_COPY - if ((asc_dvc->dvc_cntl & ASC_CNTL_NO_VERIFY_COPY) == 0) { - if (AscMemWordCmpToLram(iop_base, - (ushort) (q_addr + (ushort) ASC_SCSIQ_CDB_BEG), - (ushort *) scsiq->cdbptr, - (ushort) (scsiq->q2.cdb_len >> 1)) != 0) { - AscSetLibErrorCode(asc_dvc, ASCQ_ERR_LOCAL_MEM); - return (ERR); - } - if (AscMemWordCmpToLram(iop_base, - (ushort) (q_addr + (ushort) ASC_SCSIQ_CPY_BEG), - (ushort *) & scsiq->q1.cntl, - (ushort) (((sizeof (ASC_SCSIQ_1) + sizeof (ASC_SCSIQ_2)) / 2) - 1)) - != 0) { - AscSetLibErrorCode(asc_dvc, ASCQ_ERR_LOCAL_MEM); - return (ERR); - } - } -#endif -#if CC_CLEAR_DMA_REMAIN - AscWriteLramDWord(iop_base, - (ushort) (q_addr + (ushort) ASC_SCSIQ_DW_REMAIN_XFER_ADDR), 0UL); - AscWriteLramDWord(iop_base, - (ushort) (q_addr + (ushort) ASC_SCSIQ_DW_REMAIN_XFER_CNT), 0UL); -#endif AscWriteLramWord(iop_base, (ushort) (q_addr + (ushort) ASC_SCSIQ_B_STATUS), (ushort) (((ushort) scsiq->q1.q_no << 8) | (ushort) QS_READY)); @@ -8472,6 +11500,7 @@ ushort sg_entry_cnt; ushort q_addr; uchar next_qp; + iop_base = asc_dvc->iop_base; sg_head = scsiq->sg_head; saved_data_addr = scsiq->q1.data_addr; @@ -8542,6 +11571,7 @@ int sta; ASC_SCSI_BIT_ID_TYPE saved_unit_not_ready; PortAddr iop_base; + iop_base = asc_dvc->iop_base; sta = ERR; saved_unit_not_ready = asc_dvc->unit_not_ready; @@ -8571,6 +11601,7 @@ PortAddr iop_base; int sta; uchar tid_no; + ASC_SCSI_BIT_ID_TYPE target_id; int i; ASC_SCSI_REQ_Q scsiq_buf; @@ -8642,13 +11673,14 @@ int sta; int i; PortAddr iop_base; + iop_base = asc_dvc->iop_base; asc_dvc->unit_not_ready = 0xFF; sta = TRUE; AscWaitISRDone(asc_dvc); AscStopQueueExe(iop_base); asc_dvc->sdtr_done = 0; - AscResetChipAndScsiBus(iop_base); + AscResetChipAndScsiBus(asc_dvc); DvcSleepMilliSecond((ulong) ((ushort) asc_dvc->scsi_reset_wait * 1000)); AscReInitLram(asc_dvc); for (i = 0; i <= ASC_MAX_TID; i++) { @@ -8679,6 +11711,7 @@ ) { int sta = FALSE; + if (AscHostReqRiscHalt(iop_base)) { sta = AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data); AscStartChip(iop_base); @@ -8696,8 +11729,8 @@ { ASC_SCSI_BIT_ID_TYPE org_id; int i; - int sta; - sta = TRUE; + int sta = TRUE; + AscSetBank(iop_base, 1); org_id = AscReadChipDvcID(iop_base); for (i = 0; i <= ASC_MAX_TID; i++) { @@ -8740,6 +11773,7 @@ ushort s_addr; PortAddr iop_base; ushort warn_code; + iop_base = asc_dvc->iop_base; warn_code = 0; AscMemWordSetLram(iop_base, ASC_QADR_BEG, 0, @@ -8791,6 +11825,7 @@ PortAddr iop_base; int i; ushort lram_addr; + iop_base = asc_dvc->iop_base; AscPutRiscVarFreeQHead(iop_base, 1); AscPutRiscVarDoneQTail(iop_base, asc_dvc->max_total_qng); @@ -8840,6 +11875,7 @@ ushort q_addr; uchar q_status; int count = 0; + while (scsiq->q1.q_no == 0) ; q_addr = ASC_QNO_TO_QADDR(scsiq->q1.q_no); do { @@ -8899,6 +11935,7 @@ { uchar byte; uchar sdtr_period_ix; + sdtr_period_ix = AscGetSynPeriodIndex(asc_dvc, sdtr_period); if ( (sdtr_period_ix > asc_dvc->max_sdtr_index) @@ -8931,6 +11968,7 @@ int max_index; int min_index; int i; + period_table = asc_dvc->sdtr_period_tbl; max_index = (int) asc_dvc->max_sdtr_index; min_index = (int)asc_dvc->host_init_sdtr_index ; @@ -8955,6 +11993,7 @@ ushort q_addr; uchar next_qp; uchar q_status; + q_addr = ASC_QNO_TO_QADDR(free_q_head); q_status = (uchar) AscReadLramByte(iop_base, (ushort) (q_addr + ASC_SCSIQ_B_STATUS)); @@ -8974,6 +12013,7 @@ ) { uchar i; + for (i = 0; i < n_free_q; i++) { if ((free_q_head = AscAllocFreeQueue(iop_base, free_q_head)) == ASC_QLINK_END) { @@ -8996,6 +12036,7 @@ ASC_QDONE_INFO *scsiq; ASC_ISR_CALLBACK asc_isr_callback; int last_int_level; + iop_base = asc_dvc->iop_base; asc_isr_callback = (ASC_ISR_CALLBACK) asc_dvc->isr_callback; last_int_level = DvcEnterCritical(); @@ -9041,6 +12082,7 @@ ASC_QDONE_INFO *scsiq; ASC_ISR_CALLBACK asc_isr_callback; int last_int_level; + iop_base = asc_dvc->iop_base; asc_isr_callback = (ASC_ISR_CALLBACK) asc_dvc->isr_callback; last_int_level = DvcEnterCritical(); @@ -9078,6 +12120,7 @@ int count = 0; int sta = 0; uchar saved_stop_code; + if (AscIsChipHalted(iop_base)) return (1); saved_stop_code = AscReadLramByte(iop_base, ASCV_STOP_CODE_B); @@ -9100,8 +12143,8 @@ PortAddr iop_base ) { - int count; - count = 0; + int count = 0; + if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) == 0) { AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, ASC_STOP_REQ_RISC_STOP); @@ -9135,6 +12178,7 @@ { int count; uchar stop_code; + count = 0; if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) != 0) { AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, @@ -9157,6 +12201,7 @@ { int count; uchar stop_code; + count = 0; if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) != 0) { AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, @@ -9180,12 +12225,14 @@ { uchar cur_req; uchar tid_no; + int i = 0; + tid_no = ASC_TIX_TO_TID(target_ix); - while (TRUE) { + while (i++ < 10) { if ((cur_req = asc_dvc->cur_dvc_qng[tid_no]) == 0) { break; } - DvcSleepMilliSecond(1000L); + DvcSleepMilliSecond(100L); if (asc_dvc->cur_dvc_qng[tid_no] == cur_req) { break; } @@ -9199,6 +12246,7 @@ ) { int tid; + for (tid = 0; tid <= ASC_MAX_TID; tid++) { AscWaitTixISRDone(asc_dvc, ASC_TID_TO_TIX(tid)); } @@ -9213,6 +12261,7 @@ ) { ASC_MIN_SG_HEAD sg_head; + sg_head.entry_cnt = ASC_MIN_SG_LIST; if (DvcGetSGList(asc_dvc, (uchar *) buf_addr, buf_size, (ASC_SG_HEAD *) & sg_head) != buf_size) { @@ -9225,20 +12274,15 @@ } STATIC void -DvcDelayNanoSecond( - ASC_DVC_VAR asc_ptr_type * asc_dvc, - ulong nano_sec -) +DvcDelayMicroSecond(ADV_DVC_VAR *asc_dvc, ushort micro_sec) { - ulong loop; - PortAddr iop_base; - iop_base = asc_dvc->iop_base; - loop = nano_sec / 90; - loop++; - while (loop-- != 0) { - inp(iop_base); - } - return; + udelay(micro_sec); +} + +STATIC void +DvcDelayNanoSecond(ASC_DVC_VAR asc_ptr_type * asc_dvc, ulong nano_sec) +{ + udelay((nano_sec + 999)/1000); } ASC_INITFUNC( @@ -9251,6 +12295,7 @@ PortAddr eisa_iop; ushort product_id_high, product_id_low; ulong product_id; + eisa_iop = ASC_GET_EISA_SLOT(iop_base) | ASC_EISA_PID_IOP_MASK; product_id_low = inpw(eisa_iop); product_id_high = inpw(eisa_iop + 2); @@ -9266,6 +12311,7 @@ ) { ulong eisa_product_id; + if (iop_base == 0) { iop_base = ASC_EISA_MIN_IOP_ADDR; } else { @@ -9315,6 +12361,7 @@ ) { uchar cc_val; + cc_val = AscGetChipControl(iop_base) & (~(CC_SINGLE_STEP | CC_TEST | CC_DIAG)); AscSetChipControl(iop_base, (uchar) (cc_val | CC_HALT)); AscSetChipIH(iop_base, INS_HALT); @@ -9358,6 +12405,7 @@ uchar host_flag; uchar risc_flag; ushort loop; + loop = 0; do { risc_flag = AscReadLramByte(iop_base, ASCV_RISC_FLAG_B); @@ -9386,6 +12434,7 @@ ) { ushort cfg; + cfg = AscGetChipCfgLsw(iop_base); AscSetChipCfgLsw(iop_base, cfg & (~ASC_CFG0_HOST_INT_ON)); return; @@ -9397,6 +12446,7 @@ ) { ushort cfg; + cfg = AscGetChipCfgLsw(iop_base); AscSetChipCfgLsw(iop_base, cfg | ASC_CFG0_HOST_INT_ON); return; @@ -9411,6 +12461,7 @@ ) { uchar val; + val = AscGetChipControl(iop_base) & (~(CC_SINGLE_STEP | CC_TEST | CC_DIAG | CC_SCSI_RESET | CC_CHIP_RESET)); if (bank == 1) { @@ -9424,17 +12475,18 @@ return; } - - STATIC int AscResetChipAndScsiBus( - PortAddr iop_base + ASC_DVC_VAR *asc_dvc ) { + PortAddr iop_base; + + iop_base = asc_dvc->iop_base; while (AscGetChipStatus(iop_base) & CSW_SCSI_RESET_ACTIVE) ; AscStopChip(iop_base); AscSetChipControl(iop_base, CC_CHIP_RESET | CC_SCSI_RESET | CC_HALT); - DvcSleepMilliSecond(200); + DvcDelayNanoSecond(asc_dvc, 60000); AscSetChipIH(iop_base, INS_RFLAG_WTM); AscSetChipIH(iop_base, INS_HALT); AscSetChipControl(iop_base, CC_CHIP_RESET | CC_HALT); @@ -9467,6 +12519,7 @@ ) { ushort channel; + channel = AscGetChipCfgLsw(iop_base) & 0x0003; if (channel == 0x03) return (0); @@ -9485,6 +12538,7 @@ { ushort cfg_lsw; uchar value; + if ((dma_channel >= 5) && (dma_channel <= 7)) { if (dma_channel == 7) value = 0x00; @@ -9521,6 +12575,7 @@ ) { uchar speed_value; + AscSetBank(iop_base, 1); speed_value = AscReadChipDmaSpeed(iop_base); speed_value &= 0x07; @@ -9634,8 +12689,8 @@ ) ) { - ushort warn_code; - warn_code = 0; + ushort warn_code = 0; + asc_dvc->init_state |= ASC_INIT_STATE_BEG_SET_CFG; if (asc_dvc->err_code != 0) return (UW_ERR); @@ -9659,6 +12714,7 @@ ushort cfg_msw; ushort warn_code; ushort pci_device_id; + iop_base = asc_dvc->iop_base; pci_device_id = asc_dvc->cfg->pci_device_id; warn_code = 0; @@ -9683,10 +12739,8 @@ } } if (asc_dvc->bus_type & ASC_IS_PCI) { -#if CC_DISABLE_PCI_PARITY_INT cfg_msw &= 0xFFC0; AscSetChipCfgMsw(iop_base, cfg_msw); -#endif if ((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) { } else { if ((pci_device_id == ASC_PCI_DEVICE_ID_REV_A) || @@ -9721,14 +12775,15 @@ { ushort warn_code; PortAddr iop_base; - extern ushort _mcode_size; - extern ulong _mcode_chksum; - extern uchar _mcode_buf[]; + extern ushort _asc_mcode_size; + extern ulong _asc_mcode_chksum; + extern uchar _asc_mcode_buf[]; + iop_base = asc_dvc->iop_base; warn_code = 0; if ((asc_dvc->dvc_cntl & ASC_CNTL_RESET_SCSI) && !(asc_dvc->init_state & ASC_INIT_RESET_SCSI_DONE)) { - AscResetChipAndScsiBus(iop_base); + AscResetChipAndScsiBus(asc_dvc); DvcSleepMilliSecond((ulong) ((ushort) asc_dvc->scsi_reset_wait * 1000)); } asc_dvc->init_state |= ASC_INIT_STATE_BEG_LOAD_MC; @@ -9742,8 +12797,8 @@ warn_code |= AscInitLram(asc_dvc); if (asc_dvc->err_code != 0) return (UW_ERR); - if (AscLoadMicroCode(iop_base, 0, (ushort *) _mcode_buf, - _mcode_size) != _mcode_chksum) { + if (AscLoadMicroCode(iop_base, 0, (ushort *) _asc_mcode_buf, + _asc_mcode_size) != _asc_mcode_chksum) { asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM; return (warn_code); } @@ -9764,6 +12819,7 @@ PortAddr iop_base; ushort warn_code; uchar chip_version; + iop_base = asc_dvc->iop_base; warn_code = 0; asc_dvc->err_code = 0; @@ -9866,7 +12922,6 @@ return (warn_code); } -#if CC_INCLUDE_EEP_CONFIG ASC_INITFUNC( STATIC ushort AscInitFromEEP( @@ -9875,12 +12930,14 @@ ) { ASCEEP_CONFIG eep_config_buf; - ASCEEP_CONFIG *eep_config; + ASCEEP_CONFIG *eep_config; PortAddr iop_base; ushort chksum; ushort warn_code; ushort cfg_msw, cfg_lsw; int i; + int write_eep = 0; + iop_base = asc_dvc->iop_base; warn_code = 0; AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0x00FE); @@ -9888,7 +12945,7 @@ if ((AscStopChip(iop_base) == FALSE) || (AscGetChipScsiCtrl(iop_base) != 0)) { asc_dvc->init_state |= ASC_INIT_RESET_SCSI_DONE; - AscResetChipAndScsiBus(iop_base); + AscResetChipAndScsiBus(asc_dvc); DvcSleepMilliSecond((ulong) ((ushort) asc_dvc->scsi_reset_wait * 1000)); } if (AscIsChipHalted(iop_base) == FALSE) { @@ -9909,7 +12966,9 @@ AscSetChipCfgMsw(iop_base, cfg_msw); } chksum = AscGetEEPConfig(iop_base, eep_config, asc_dvc->bus_type); - eep_config->cfg_msw &= (~(ASC_CFG_MSW_CLR_MASK)); + if (chksum == 0) { + chksum = 0xaa55; + } if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) { warn_code |= ASC_WARN_AUTO_CONFIG; if (asc_dvc->cfg->chip_version == 3) { @@ -9923,9 +12982,32 @@ } } } + eep_config->cfg_msw &= ~ASC_CFG_MSW_CLR_MASK; eep_config->cfg_lsw |= ASC_CFG0_HOST_INT_ON; if (chksum != eep_config->chksum) { - warn_code |= ASC_WARN_EEPROM_CHKSUM; + if (AscGetChipVersion(iop_base, asc_dvc->bus_type) == + ASC_CHIP_VER_PCI_ULTRA_3050 ) + { + eep_config->init_sdtr = 0xFF; + eep_config->disc_enable = 0xFF; + eep_config->start_motor = 0xFF; + eep_config->use_cmd_qng = 0; + eep_config->max_total_qng = 0xF0; + eep_config->max_tag_qng = 0x20; + eep_config->cntl = 0xBFFF; + eep_config->chip_scsi_id = 7; + eep_config->no_scam = 0; + eep_config->adapter_info[0] = 0; + eep_config->adapter_info[1] = 0; + eep_config->adapter_info[2] = 0; + eep_config->adapter_info[3] = 0; + eep_config->adapter_info[4] = 0; + /* Indicate EEPROM-less board. */ + eep_config->adapter_info[5] = 0xBB; + } else { + write_eep = 1 ; + warn_code |= ASC_WARN_EEPROM_CHKSUM ; + } } asc_dvc->init_sdtr = eep_config->init_sdtr; asc_dvc->cfg->disc_enable = eep_config->disc_enable; @@ -9934,6 +13016,12 @@ asc_dvc->start_motor = eep_config->start_motor; asc_dvc->dvc_cntl = eep_config->cntl; asc_dvc->no_scam = eep_config->no_scam; + asc_dvc->cfg->adapter_info[0] = eep_config->adapter_info[0]; + asc_dvc->cfg->adapter_info[1] = eep_config->adapter_info[1]; + asc_dvc->cfg->adapter_info[2] = eep_config->adapter_info[2]; + asc_dvc->cfg->adapter_info[3] = eep_config->adapter_info[3]; + asc_dvc->cfg->adapter_info[4] = eep_config->adapter_info[4]; + asc_dvc->cfg->adapter_info[5] = eep_config->adapter_info[5]; if (!AscTestExternalLram(asc_dvc)) { if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA)) { eep_config->max_total_qng = ASC_MAX_PCI_ULTRA_INRAM_TOTAL_QNG; @@ -9976,9 +13064,6 @@ } 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] = @@ -9986,14 +13071,11 @@ (asc_dvc->host_init_sdtr_index << 4)); } eep_config->cfg_msw = AscGetChipCfgMsw(iop_base); -#if CC_CHK_FIX_EEP_CONTENT - if (AscSetEEPConfig(iop_base, eep_config, asc_dvc->bus_type) != 0) { - asc_dvc->err_code |= ASC_IERR_WRITE_EEPROM; + if (write_eep) { + (void) AscSetEEPConfig(iop_base, eep_config, asc_dvc->bus_type); } -#endif return (warn_code); } -#endif ASC_INITFUNC( STATIC ushort @@ -10006,6 +13088,7 @@ ushort warn_code; PortAddr iop_base; ulong phy_addr; + iop_base = asc_dvc->iop_base; warn_code = 0; for (i = 0; i <= ASC_MAX_TID; i++) { @@ -10054,6 +13137,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 *) scsi_done_q->d2.srb_ptr; @@ -10095,6 +13179,7 @@ ushort q_addr; ushort saved_word; int sta; + iop_base = asc_dvc->iop_base; sta = 0; q_addr = ASC_QNO_TO_QADDR(241); @@ -10110,7 +13195,6 @@ return (sta); } -#if CC_INCLUDE_EEP_CONFIG ASC_INITFUNC( STATIC int AscWriteEEPCmdReg( @@ -10121,6 +13205,7 @@ { uchar read_back; int retry; + retry = 0; while (TRUE) { AscSetChipEEPCmd(iop_base, cmd_reg); @@ -10145,6 +13230,7 @@ { ushort read_back; int retry; + retry = 0; while (TRUE) { AscSetChipEEPData(iop_base, data_reg); @@ -10191,6 +13277,7 @@ { ushort read_wval; uchar cmd_reg; + AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE); AscWaitEEPRead(); cmd_reg = addr | ASC_EEP_CMD_READ; @@ -10211,6 +13298,7 @@ ) { ushort read_wval; + read_wval = AscReadEEPWord(iop_base, addr); if (read_wval != word_val) { AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_ABLE); @@ -10242,6 +13330,7 @@ int cfg_end; int s_addr; int isa_pnp_wsize; + wbuf = (ushort *) cfg_buf; sum = 0; isa_pnp_wsize = 0; @@ -10267,7 +13356,6 @@ return (sum); } -#if CC_CHK_FIX_EEP_CONTENT ASC_INITFUNC( STATIC int AscSetEEPConfigOnce( @@ -10282,6 +13370,7 @@ int s_addr; int cfg_beg; int cfg_end; + wbuf = (ushort *) cfg_buf; n_error = 0; sum = 0; @@ -10347,8 +13436,6 @@ } return (n_error); } -#endif -#endif STATIC int AscInitPollBegin( @@ -10356,6 +13443,7 @@ ) { PortAddr iop_base; + iop_base = asc_dvc->iop_base; AscDisableInterrupt(iop_base); asc_dvc->init_state |= ASC_INIT_STATE_BEG_INQUIRY; @@ -10374,6 +13462,7 @@ { PortAddr iop_base; rint i; + iop_base = asc_dvc->iop_base; asc_dvc->isr_callback = (Ptr2Func) asc_dvc->saved_ptr2func; AscWriteLramByte(iop_base, ASCV_DISC_ENABLE_B, @@ -10393,8 +13482,6 @@ return (0); } -STATIC int _asc_wait_slow_device_ = FALSE; - STATIC int AscInitPollTarget( REG ASC_DVC_VAR asc_ptr_type * asc_dvc, @@ -10425,9 +13512,9 @@ if (PollScsiInquiry(asc_dvc, scsiq, (uchar *) inq, sizeof (ASC_SCSI_INQUIRY)) == 1) { dvc_found = 1; - support_read_cap = TRUE; dvc_type = inq->byte0.peri_dvc_type; if (dvc_type != SCSI_TYPE_UNKNOWN) { + support_read_cap = TRUE; if ((dvc_type != SCSI_TYPE_DASD) && (dvc_type != SCSI_TYPE_WORM) && (dvc_type != SCSI_TYPE_CDROM) @@ -10435,12 +13522,6 @@ asc_dvc->start_motor &= ~tid_bits; support_read_cap = FALSE; } - if ((dvc_type != SCSI_TYPE_DASD) || inq->byte1.rmb) { - if (!_asc_wait_slow_device_) { - DvcSleepMilliSecond(3000 - ((int) tid_no * 250)); - _asc_wait_slow_device_ = TRUE; - } - } if (lun == 0) { if ((inq->byte3.rsp_data_fmt >= 2) || (inq->byte2.ansi_apr_ver >= 2)) { @@ -10494,6 +13575,14 @@ (uchar *)"CD-ROM DRIVE ", 16) == 0)) { asc_dvc->pci_fix_asyn_xfer &= ~tid_bits ; } + if ((dvc_type == SCSI_TYPE_CDROM) && + (AscCompareString((uchar *) inq->vendor_id, + (uchar *) "YAMAHA", 6) == 0) && + (AscCompareString((uchar *) inq->product_id, + (uchar *) "CDR400", 6) == 0)) + { + asc_dvc->pci_fix_asyn_xfer &= ~tid_bits ; + } if (asc_dvc->pci_fix_asyn_xfer & tid_bits) { AscSetRunChipSynRegAtID(asc_dvc->iop_base, tid_no, @@ -10553,7 +13642,7 @@ scsiq->r3.host_stat = 0; scsiq->r3.scsi_stat = 0; scsiq->r3.scsi_msg = 0; - DvcSleepMilliSecond(2000); + DvcSleepMilliSecond(1000); continue; } scsiq->r3.done_stat = 0; @@ -10611,19 +13700,15 @@ { ASC_CAP_INFO scsi_cap_info; int status; + if (AscScsiReadCapacity(asc_dvc, scsiq, (uchar *) & scsi_cap_info) == ERR) { return (scsiq->r3.done_stat = QD_WITH_ERROR); } status = PollQueueDone(asc_dvc, (ASC_SCSI_REQ_Q *) scsiq, 8); if (status == 1) { -#if CC_LITTLE_ENDIAN_HOST cap_info->lba = (ulong) * swapfarbuf4((uchar *) & scsi_cap_info.lba); cap_info->blk_size = (ulong) * swapfarbuf4((uchar *) & scsi_cap_info.blk_size); -#else - cap_info->lba = scsi_cap_info.lba; - cap_info->blk_size = scsi_cap_info.blk_size; -#endif return (scsiq->r3.done_stat); } return (scsiq->r3.done_stat = QD_WITH_ERROR); @@ -10668,6 +13753,7 @@ ASC_SCSI_BIT_ID_TYPE tid_bits; int retry; ASC_REQ_SENSE *sen; + retry = 0; tid_bits = scsiq->r1.target_id; while (retry++ < 4) { @@ -10675,26 +13761,28 @@ if (scsiq->r3.done_stat == 0x01) { return (1); } else if (scsiq->r3.done_stat == QD_WITH_ERROR) { - DvcSleepMilliSecond(200); sen = (ASC_REQ_SENSE *) scsiq->sense_ptr; if ((scsiq->r3.scsi_stat == SS_CHK_CONDITION) && ((sen->err_code & 0x70) != 0)) { if (sen->sense_key == SCSI_SENKEY_NOT_READY) { + if (sen->asc == SCSI_ASC_NOMEDIA) + { + break; + } if (asc_dvc->start_motor & tid_bits) { if (PollScsiStartUnit(asc_dvc, scsiq) == 1) { - retry = 0; + DvcSleepMilliSecond(250); continue; } else { asc_dvc->start_motor &= ~tid_bits; break; } } else { - DvcSleepMilliSecond(5000); + DvcSleepMilliSecond(250); } } else if (sen->sense_key == SCSI_SENKEY_ATTENTION) { - DvcSleepMilliSecond((ulong)(500L*retry)) ; + DvcSleepMilliSecond(250); } else { - DvcSleepMilliSecond(500) ; break; } } else { @@ -10719,6 +13807,7 @@ int loop, loop_end; int sta; PortAddr iop_base; + iop_base = asc_dvc->iop_base; loop = 0; loop_end = timeout_sec * 100; @@ -10745,17 +13834,11 @@ } if (AscIsChipHalted(iop_base)) { ASC_DBG(1, "AscPollQDone: AscIsChipHalted()\n"); -#if !CC_ASCISR_CHECK_INT_PENDING - AscAckInterrupt(iop_base); -#endif AscISR(asc_dvc); loop = 0; } else { if (AscIsIntPending(iop_base)) { ASC_DBG(1, "AscPollQDone: AscIsIntPending()\n"); -#if !CC_ASCISR_CHECK_INT_PENDING - AscAckInterrupt(iop_base); -#endif AscISR(asc_dvc); } } @@ -10772,6 +13855,7 @@ { int i; int diff; + for (i = 0; i < len; i++) { diff = (int) (str1[i] - str2[i]); if (diff != 0) @@ -10788,6 +13872,7 @@ { uchar byte_data; ushort word_data; + if (isodd_word(addr)) { AscSetChipLramAddr(iop_base, addr - 1); word_data = AscGetChipLramData(iop_base); @@ -10807,6 +13892,7 @@ ) { ushort word_data; + AscSetChipLramAddr(iop_base, addr); word_data = AscGetChipLramData(iop_base); return (word_data); @@ -10820,6 +13906,7 @@ { ushort val_low, val_high; ulong dword_data; + AscSetChipLramAddr(iop_base, addr); val_low = AscGetChipLramData(iop_base); val_high = AscGetChipLramData(iop_base); @@ -10847,6 +13934,7 @@ ) { ushort word_val; + AscSetChipLramAddr(iop_base, addr); word_val = (ushort) dword_val; AscSetChipLramData(iop_base, word_val); @@ -10863,6 +13951,7 @@ ) { ushort word_data; + if (isodd_word(addr)) { addr--; word_data = AscReadLramWord(iop_base, addr); @@ -10925,6 +14014,7 @@ { ulong sum; int i; + sum = 0L; for (i = 0; i < words; i++, s_addr += 2) { sum += AscReadLramWord(iop_base, s_addr); @@ -10941,6 +14031,7 @@ ) { rint i; + AscSetChipLramAddr(iop_base, s_addr); for (i = 0; i < words; i++) { AscSetChipLramData(iop_base, set_wval); @@ -11035,4 +14126,1728 @@ scsiq->cdb[5] = 0; scsiq->r2.cdb_len = 6; return (0); +} + + +/* + * --- Adv Library Functions + */ + +/* a_qswap.h */ +STATIC unsigned char _adv_mcode_buf[] ASC_INITDATA = { + 0x9C, 0xF0, 0x80, 0x01, 0x00, 0xF0, 0x40, 0x0A, 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, 0x72, 0x01, 0xD2, 0x11, 0x00, 0x00, 0x70, 0x01, + 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x0F, 0x22, 0x03, 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, 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, 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, + 0x48, 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, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 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, 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, 0x78, 0x56, 0x34, 0x12, + 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, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0xF7, 0x70, 0x01, 0x0C, 0x1C, 0x06, 0xF7, 0x02, 0x00, 0x00, 0xF2, 0xD2, 0x0A, + 0x04, 0xF7, 0x70, 0x01, 0x06, 0xF7, 0x02, 0x00, 0x3E, 0x57, 0x3C, 0x56, 0x0C, 0x1C, 0x00, 0xFC, + 0xA6, 0x00, 0x01, 0x58, 0xAA, 0x13, 0x20, 0xF0, 0x9A, 0x03, 0x06, 0xEC, 0xB9, 0x00, 0x0E, 0x47, + 0x03, 0xE6, 0x10, 0x00, 0xCE, 0x45, 0x02, 0x13, 0x3E, 0x57, 0x06, 0xEA, 0xB9, 0x00, 0x47, 0x4B, + 0x03, 0xF6, 0xE0, 0x00, 0x00, 0xF2, 0x64, 0x0A, 0x01, 0x48, 0x4E, 0x12, 0x03, 0xF6, 0xC0, 0x00, + 0x00, 0xF2, 0x64, 0x0A, 0x41, 0x58, 0x03, 0xF6, 0xD0, 0x00, 0x00, 0xF2, 0x64, 0x0A, 0x49, 0x44, + 0x59, 0xF0, 0x0A, 0x02, 0x03, 0xF6, 0xE0, 0x00, 0x00, 0xF2, 0x64, 0x0A, 0x44, 0x58, 0x00, 0xF2, + 0xDE, 0x0D, 0x02, 0xCC, 0x4A, 0xE4, 0x01, 0x00, 0x55, 0xF0, 0x08, 0x03, 0x45, 0xF4, 0x02, 0x00, + 0x83, 0x5A, 0x04, 0xCC, 0x01, 0x4A, 0x12, 0x12, 0x00, 0xF2, 0xDE, 0x0D, 0x00, 0xCD, 0x48, 0xE4, + 0x01, 0x00, 0xE9, 0x13, 0x00, 0xF2, 0xC2, 0x0F, 0xFA, 0x10, 0x0E, 0x47, 0x03, 0xE6, 0x10, 0x00, + 0xCE, 0x45, 0x02, 0x13, 0x3E, 0x57, 0xCE, 0x47, 0x97, 0x13, 0x04, 0xEC, 0xB4, 0x00, 0x00, 0xF2, + 0xDE, 0x0D, 0x00, 0xCD, 0x48, 0xE4, 0x00, 0x00, 0x12, 0x12, 0x3E, 0x57, 0x06, 0xCC, 0x45, 0xF4, + 0x02, 0x00, 0x83, 0x5A, 0x00, 0xCC, 0x00, 0xEA, 0xB4, 0x00, 0x92, 0x10, 0x00, 0xF0, 0x8C, 0x01, + 0x43, 0xF0, 0x5C, 0x02, 0x44, 0xF0, 0x60, 0x02, 0x45, 0xF0, 0x64, 0x02, 0x46, 0xF0, 0x68, 0x02, + 0x47, 0xF0, 0x6E, 0x02, 0x48, 0xF0, 0x9E, 0x02, 0xB9, 0x54, 0x62, 0x10, 0x00, 0x1C, 0x5A, 0x10, + 0x02, 0x1C, 0x56, 0x10, 0x1E, 0x1C, 0x52, 0x10, 0x00, 0xF2, 0x1A, 0x11, 0x50, 0x10, 0x06, 0xFC, + 0xA8, 0x00, 0x03, 0xF6, 0xBE, 0x00, 0x00, 0xF2, 0x4A, 0x0A, 0x8C, 0x10, 0x01, 0xF6, 0x01, 0x00, + 0x01, 0xFA, 0xA8, 0x00, 0x00, 0xF2, 0x28, 0x0B, 0x06, 0x10, 0xB9, 0x54, 0x01, 0xFA, 0xA8, 0x00, + 0x03, 0xF6, 0xBE, 0x00, 0x00, 0xF2, 0x54, 0x0A, 0x01, 0xFC, 0xA8, 0x00, 0x20, 0x10, 0x58, 0x1C, + 0x00, 0xF2, 0x18, 0x0B, 0x5A, 0x1C, 0x01, 0xF6, 0x01, 0x00, 0x38, 0x54, 0x00, 0xFA, 0xA6, 0x00, + 0x01, 0xFA, 0xA8, 0x00, 0x20, 0x1C, 0x00, 0xF0, 0x72, 0x01, 0x01, 0xF6, 0x01, 0x00, 0x38, 0x54, + 0x00, 0xFA, 0xA6, 0x00, 0x01, 0xFA, 0xA8, 0x00, 0x20, 0x1C, 0x00, 0xF0, 0x80, 0x01, 0x03, 0xF6, + 0xE0, 0x00, 0x00, 0xF2, 0x64, 0x0A, 0x01, 0x48, 0x0A, 0x13, 0x00, 0xF2, 0x34, 0x10, 0x00, 0xF2, + 0x50, 0x0F, 0x24, 0x10, 0x03, 0xF6, 0xC0, 0x00, 0x00, 0xF2, 0x64, 0x0A, 0x02, 0xF6, 0xD0, 0x00, + 0x02, 0x57, 0x03, 0x59, 0x01, 0xCC, 0x49, 0x44, 0x5B, 0xF0, 0x04, 0x03, 0x00, 0xF2, 0x98, 0x0F, + 0x00, 0xF0, 0x80, 0x01, 0x00, 0xF2, 0x10, 0x10, 0x0C, 0x1C, 0x02, 0x4B, 0xBF, 0x57, 0x9E, 0x43, + 0x77, 0x57, 0x07, 0x4B, 0x20, 0xF0, 0x9A, 0x03, 0x40, 0x1C, 0x1E, 0xF0, 0x30, 0x03, 0x26, 0xF0, + 0x2C, 0x03, 0xA0, 0xF0, 0x1A, 0x03, 0x11, 0xF0, 0x9A, 0x03, 0x12, 0x10, 0x9F, 0xF0, 0x3E, 0x03, + 0x46, 0x1C, 0x82, 0xE7, 0x05, 0x00, 0x9E, 0xE7, 0x11, 0x00, 0x00, 0xF0, 0x02, 0x0A, 0x0C, 0x1C, + 0x48, 0x1C, 0x46, 0x1C, 0x38, 0x54, 0x00, 0xEC, 0xBA, 0x00, 0x08, 0x44, 0x00, 0xEA, 0xBA, 0x00, + 0x03, 0xF6, 0xC0, 0x00, 0x00, 0xF2, 0x64, 0x0A, 0x08, 0x44, 0x00, 0x4C, 0x82, 0xE7, 0x02, 0x00, + 0x00, 0xF2, 0x0E, 0x11, 0x00, 0xF2, 0x0E, 0x11, 0x06, 0xF0, 0x74, 0x03, 0x1E, 0xF0, 0xF8, 0x09, + 0x00, 0xF0, 0xFE, 0x09, 0x00, 0xFC, 0xBE, 0x00, 0x98, 0x57, 0x55, 0xF0, 0xA0, 0x04, 0x01, 0xE6, + 0x0C, 0x00, 0x00, 0xF2, 0x4A, 0x0D, 0x00, 0xF2, 0x0E, 0x11, 0x00, 0xF2, 0xB8, 0x11, 0x00, 0xF2, + 0xC4, 0x11, 0x01, 0xF0, 0x7C, 0x02, 0x00, 0xF0, 0x8A, 0x02, 0x46, 0x1C, 0x0C, 0x1C, 0x67, 0x1B, + 0xBF, 0x57, 0x77, 0x57, 0x02, 0x4B, 0x48, 0x1C, 0x32, 0x1C, 0x00, 0xF2, 0x8E, 0x0D, 0x30, 0x1C, + 0x96, 0xF0, 0xB0, 0x03, 0xB1, 0xF0, 0xB4, 0x03, 0x1E, 0xF0, 0xF8, 0x09, 0x85, 0xF0, 0xFE, 0x09, + 0x00, 0xFC, 0xBE, 0x00, 0x98, 0x57, 0x14, 0x12, 0x01, 0xE6, 0x0C, 0x00, 0x00, 0xF2, 0x4A, 0x0D, + 0x00, 0xF2, 0x0E, 0x11, 0x01, 0xF0, 0x7C, 0x02, 0x00, 0xF0, 0x8A, 0x02, 0x03, 0xF6, 0xE0, 0x00, + 0x00, 0xF2, 0x64, 0x0A, 0x01, 0x48, 0x55, 0xF0, 0x8C, 0x04, 0x03, 0x82, 0x03, 0xFC, 0xA0, 0x00, + 0x9B, 0x57, 0x40, 0x12, 0x69, 0x18, 0x00, 0xF2, 0x0E, 0x11, 0x85, 0xF0, 0x36, 0x04, 0x69, 0x08, + 0x00, 0xF2, 0x0E, 0x11, 0x85, 0xF0, 0xFE, 0x09, 0x68, 0x08, 0x4C, 0x44, 0x28, 0x12, 0x44, 0x48, + 0x03, 0xF6, 0xE0, 0x00, 0x00, 0xF2, 0x64, 0x0A, 0x45, 0x58, 0x00, 0xF2, 0xF2, 0x0D, 0x00, 0xCC, + 0x01, 0x48, 0x55, 0xF0, 0x8C, 0x04, 0x4C, 0x44, 0xEF, 0x13, 0x00, 0xF2, 0xC2, 0x0F, 0x00, 0xF2, + 0x10, 0x10, 0x08, 0x10, 0x68, 0x18, 0x45, 0x5A, 0x00, 0xF2, 0xF2, 0x0D, 0x04, 0x80, 0x18, 0xE4, + 0x10, 0x00, 0x28, 0x12, 0x01, 0xE6, 0x06, 0x00, 0x04, 0x80, 0x18, 0xE4, 0x01, 0x00, 0x04, 0x12, + 0x01, 0xE6, 0x0D, 0x00, 0x00, 0xF2, 0x4A, 0x0D, 0x00, 0xF2, 0x0E, 0x11, 0x04, 0xE6, 0x02, 0x00, + 0x9E, 0xE7, 0x15, 0x00, 0x01, 0xF0, 0x18, 0x0A, 0x00, 0xF0, 0xFE, 0x09, 0x69, 0x08, 0x05, 0x80, + 0x48, 0xE4, 0x00, 0x00, 0x0C, 0x12, 0x00, 0xE6, 0x11, 0x00, 0x00, 0xEA, 0xB8, 0x00, 0x00, 0xF2, + 0xB2, 0x10, 0x82, 0xE7, 0x02, 0x00, 0x1C, 0x90, 0x40, 0x5C, 0x00, 0x16, 0x01, 0xE6, 0x06, 0x00, + 0x00, 0xF2, 0x4A, 0x0D, 0x01, 0xF0, 0x80, 0x01, 0x1E, 0xF0, 0x80, 0x01, 0x00, 0xF0, 0x94, 0x04, + 0x42, 0x5B, 0x06, 0xF7, 0x03, 0x00, 0x46, 0x59, 0xBF, 0x57, 0x77, 0x57, 0x01, 0xE6, 0x80, 0x00, + 0x07, 0x80, 0x31, 0x44, 0x04, 0x80, 0x18, 0xE4, 0x20, 0x00, 0x5E, 0x13, 0x20, 0x80, 0x48, 0xE4, + 0x03, 0x00, 0x56, 0x12, 0x04, 0x80, 0x18, 0xE4, 0x02, 0x00, 0x4C, 0x13, 0x00, 0xFC, 0xA2, 0x00, + 0x98, 0x57, 0x55, 0xF0, 0x18, 0x05, 0x31, 0xE4, 0x40, 0x00, 0x00, 0xFC, 0xA0, 0x00, 0x98, 0x57, + 0x36, 0x12, 0x4C, 0x1C, 0x00, 0xF2, 0x0E, 0x11, 0x89, 0x48, 0x00, 0xF2, 0x0E, 0x11, 0x86, 0xF0, + 0x2A, 0x05, 0x82, 0xE7, 0x06, 0x00, 0x1B, 0x80, 0x48, 0xE4, 0x22, 0x00, 0x5B, 0xF0, 0x08, 0x05, + 0x48, 0xE4, 0x20, 0x00, 0x59, 0xF0, 0x0C, 0x05, 0x00, 0xE6, 0x20, 0x00, 0x09, 0x48, 0x00, 0xF2, + 0x0E, 0x11, 0x86, 0xF0, 0x2A, 0x05, 0x83, 0x80, 0x04, 0x10, 0x00, 0xF2, 0x9E, 0x0D, 0x00, 0xE6, + 0x01, 0x00, 0x00, 0xEA, 0x26, 0x01, 0x01, 0xEA, 0x27, 0x01, 0x04, 0x80, 0x18, 0xE4, 0x10, 0x00, + 0x36, 0x12, 0xB9, 0x54, 0x00, 0xF2, 0xF2, 0x0E, 0x01, 0xE6, 0x06, 0x00, 0x04, 0x80, 0x18, 0xE4, + 0x01, 0x00, 0x04, 0x12, 0x01, 0xE6, 0x0D, 0x00, 0x00, 0xF2, 0x4A, 0x0D, 0x00, 0xF2, 0x0E, 0x11, + 0x00, 0xF2, 0xB8, 0x11, 0x00, 0xF2, 0xC4, 0x11, 0x04, 0xE6, 0x02, 0x00, 0x9E, 0xE7, 0x15, 0x00, + 0x01, 0xF0, 0x18, 0x0A, 0x00, 0xF0, 0xFE, 0x09, 0x00, 0xFC, 0x20, 0x01, 0x98, 0x57, 0x34, 0x12, + 0x00, 0xFC, 0x24, 0x01, 0x98, 0x57, 0x2C, 0x13, 0xB9, 0x54, 0x00, 0xF2, 0xF2, 0x0E, 0x86, 0xF0, + 0xA4, 0x05, 0x03, 0xF6, 0x01, 0x00, 0x00, 0xF2, 0x88, 0x0E, 0x85, 0xF0, 0x9A, 0x05, 0x82, 0xE7, + 0x03, 0x00, 0x00, 0xF2, 0x5C, 0x0B, 0x82, 0xE7, 0x02, 0x00, 0x00, 0xFC, 0x24, 0x01, 0xB0, 0x57, + 0x00, 0xFA, 0x24, 0x01, 0x00, 0xFC, 0x9E, 0x00, 0x98, 0x57, 0x5A, 0x12, 0x00, 0xFC, 0xB6, 0x00, + 0x98, 0x57, 0x52, 0x13, 0x03, 0xE6, 0x0C, 0x00, 0x00, 0xFC, 0x9C, 0x00, 0x98, 0x57, 0x04, 0x13, + 0x03, 0xE6, 0x19, 0x00, 0x05, 0xE6, 0x08, 0x00, 0x00, 0xF6, 0x00, 0x01, 0x00, 0x57, 0x00, 0x57, + 0x03, 0x58, 0x00, 0xDC, 0x18, 0xF4, 0x00, 0x80, 0x04, 0x13, 0x05, 0xE6, 0x0F, 0x00, 0xB9, 0x54, + 0x00, 0xF2, 0xF2, 0x0E, 0x86, 0xF0, 0x06, 0x06, 0x00, 0xF2, 0xB6, 0x0E, 0x85, 0xF0, 0xFC, 0x05, + 0x82, 0xE7, 0x03, 0x00, 0x00, 0xF2, 0x5C, 0x0B, 0x82, 0xE7, 0x02, 0x00, 0x00, 0xFC, 0xB6, 0x00, + 0xB0, 0x57, 0x00, 0xFA, 0xB6, 0x00, 0x01, 0xF6, 0x01, 0x00, 0x00, 0xF2, 0xF2, 0x0E, 0x9C, 0x32, + 0x4E, 0x1C, 0x32, 0x1C, 0x00, 0xF2, 0x8E, 0x0D, 0x30, 0x1C, 0x82, 0xE7, 0x04, 0x00, 0xB1, 0xF0, + 0x1E, 0x06, 0x0A, 0xF0, 0x3A, 0x06, 0x05, 0xF0, 0xD2, 0x06, 0x06, 0xF0, 0xD8, 0x06, 0x09, 0xF0, + 0x20, 0x09, 0x1E, 0xF0, 0xF8, 0x09, 0x00, 0xF0, 0xFE, 0x09, 0x04, 0x80, 0x18, 0xE4, 0x20, 0x00, + 0x30, 0x12, 0x09, 0xE7, 0x03, 0x00, 0x00, 0xF2, 0x0E, 0x11, 0x21, 0x80, 0x18, 0xE4, 0xE0, 0x00, + 0x09, 0x48, 0x00, 0xF2, 0x0E, 0x11, 0x09, 0xE7, 0x00, 0x00, 0x00, 0xF2, 0x0E, 0x11, 0x09, 0xE7, + 0x00, 0x00, 0x00, 0xF2, 0x0E, 0x11, 0x99, 0xA4, 0x00, 0xF2, 0x0E, 0x11, 0x09, 0xE7, 0x00, 0x00, + 0x9A, 0x10, 0x04, 0x80, 0x18, 0xE4, 0x02, 0x00, 0x34, 0x12, 0x09, 0xE7, 0x1B, 0x00, 0x00, 0xF2, + 0x0E, 0x11, 0x21, 0x80, 0x18, 0xE4, 0xE0, 0x00, 0x09, 0x48, 0x00, 0xF2, 0x0E, 0x11, 0x09, 0xE7, + 0x00, 0x00, 0x00, 0xF2, 0x0E, 0x11, 0x09, 0xE7, 0x00, 0x00, 0x00, 0xF2, 0x0E, 0x11, 0x09, 0xE7, + 0x01, 0x00, 0x00, 0xF2, 0x0E, 0x11, 0x09, 0xE7, 0x00, 0x00, 0x00, 0xF0, 0x08, 0x09, 0xBB, 0x55, + 0x9A, 0x81, 0x03, 0xF7, 0x20, 0x00, 0x09, 0x6F, 0x93, 0x45, 0x55, 0xF0, 0xDE, 0x06, 0xB1, 0xF0, + 0xBE, 0x06, 0x0A, 0xF0, 0xB6, 0x06, 0x09, 0xF0, 0x20, 0x09, 0x1E, 0xF0, 0xF8, 0x09, 0x00, 0xF0, + 0xFE, 0x09, 0x00, 0xF2, 0x5C, 0x0B, 0x47, 0x10, 0x09, 0xE7, 0x08, 0x00, 0x41, 0x10, 0x05, 0x80, + 0x48, 0xE4, 0x00, 0x00, 0x1E, 0x12, 0x00, 0xE6, 0x11, 0x00, 0x00, 0xEA, 0xB8, 0x00, 0x00, 0xF2, + 0xB2, 0x10, 0x2C, 0x90, 0xAE, 0x90, 0x08, 0x50, 0x8A, 0x50, 0x38, 0x54, 0x1F, 0x40, 0x00, 0xF2, + 0xB0, 0x0D, 0x08, 0x10, 0x08, 0x90, 0x8A, 0x90, 0x30, 0x50, 0xB2, 0x50, 0x9C, 0x32, 0x0C, 0x92, + 0x8E, 0x92, 0x38, 0x54, 0x04, 0x80, 0x30, 0xE4, 0x08, 0x00, 0x04, 0x40, 0x0C, 0x1C, 0x00, 0xF6, + 0x03, 0x00, 0xB1, 0xF0, 0x22, 0x07, 0x9E, 0xF0, 0x36, 0x07, 0x01, 0x48, 0x55, 0xF0, 0xF8, 0x09, + 0x0C, 0x1C, 0x10, 0x44, 0xED, 0x10, 0x0B, 0xF0, 0x5A, 0x07, 0x0C, 0xF0, 0x5E, 0x07, 0x05, 0xF0, + 0x4E, 0x07, 0x06, 0xF0, 0x54, 0x07, 0x09, 0xF0, 0x20, 0x09, 0x00, 0xF0, 0xFE, 0x09, 0x00, 0xF2, + 0x5C, 0x0B, 0xCF, 0x10, 0x09, 0xE7, 0x08, 0x00, 0xC9, 0x10, 0x2E, 0x1C, 0x02, 0x10, 0x2C, 0x1C, + 0xAA, 0xF0, 0x60, 0x07, 0xAC, 0xF0, 0x6E, 0x07, 0x40, 0x10, 0x34, 0x1C, 0xF3, 0x10, 0xAD, 0xF0, + 0x78, 0x07, 0xC8, 0x10, 0x36, 0x1C, 0xE9, 0x10, 0x2B, 0xF0, 0x7E, 0x08, 0x6B, 0x18, 0x18, 0xF4, + 0x00, 0xFE, 0x20, 0x12, 0x01, 0x58, 0xD2, 0xF0, 0x7E, 0x08, 0x76, 0x18, 0x18, 0xF4, 0x03, 0x00, + 0xEC, 0x12, 0x00, 0xFC, 0x22, 0x01, 0x18, 0xF4, 0x01, 0x00, 0xE2, 0x12, 0x0B, 0xF0, 0x60, 0x07, + 0x0C, 0xF0, 0x60, 0x07, 0x36, 0x1C, 0x34, 0x1C, 0xB7, 0x10, 0x38, 0x54, 0xB9, 0x54, 0x84, 0x80, + 0x19, 0xE4, 0x20, 0x00, 0xB2, 0x13, 0x85, 0x80, 0x81, 0x48, 0x66, 0x12, 0x04, 0x80, 0x18, 0xE4, + 0x08, 0x00, 0x58, 0x13, 0x1F, 0x80, 0x08, 0x44, 0xC8, 0x44, 0x9F, 0x12, 0x1F, 0x40, 0x34, 0x91, + 0xB6, 0x91, 0x44, 0x55, 0xE5, 0x55, 0x02, 0xEC, 0xB8, 0x00, 0x02, 0x49, 0xBB, 0x55, 0x82, 0x81, + 0xC0, 0x55, 0x48, 0xF4, 0x0F, 0x00, 0x5A, 0xF0, 0x16, 0x08, 0x4A, 0xE4, 0x17, 0x00, 0xD5, 0xF0, + 0xF6, 0x07, 0x02, 0xF6, 0x0F, 0x00, 0x02, 0xF4, 0x02, 0x00, 0x02, 0xEA, 0xB8, 0x00, 0x04, 0x91, + 0x86, 0x91, 0x02, 0x4B, 0x2C, 0x90, 0x08, 0x50, 0x2E, 0x90, 0x0A, 0x50, 0x2C, 0x51, 0xAE, 0x51, + 0x00, 0xF2, 0xB2, 0x10, 0x38, 0x54, 0x00, 0xF2, 0xB0, 0x0D, 0x56, 0x10, 0x34, 0x91, 0xB6, 0x91, + 0x0C, 0x10, 0x04, 0x80, 0x18, 0xE4, 0x08, 0x00, 0x41, 0x12, 0x0C, 0x91, 0x8E, 0x91, 0x04, 0x80, + 0x18, 0xE4, 0xF7, 0x00, 0x04, 0x40, 0x30, 0x90, 0xB2, 0x90, 0x36, 0x10, 0x02, 0x80, 0x48, 0xE4, + 0x10, 0x00, 0x31, 0x12, 0x82, 0xE7, 0x10, 0x00, 0x84, 0x80, 0x19, 0xE4, 0x20, 0x00, 0x10, 0x13, + 0x0C, 0x90, 0x8E, 0x90, 0x5D, 0xF0, 0x74, 0x07, 0x0C, 0x58, 0x8D, 0x58, 0x00, 0xF0, 0x60, 0x07, + 0x38, 0x54, 0xB9, 0x54, 0x19, 0x80, 0xF1, 0x10, 0x3A, 0x55, 0x19, 0x81, 0xBB, 0x55, 0x10, 0x90, + 0x92, 0x90, 0x10, 0x58, 0x91, 0x58, 0x14, 0x59, 0x95, 0x59, 0x00, 0xF0, 0x60, 0x07, 0x04, 0x80, + 0x18, 0xE4, 0x20, 0x00, 0x06, 0x12, 0x6C, 0x19, 0x19, 0x41, 0x7C, 0x10, 0x6C, 0x19, 0x0C, 0x51, + 0xED, 0x19, 0x8E, 0x51, 0x6B, 0x18, 0x18, 0xF4, 0x00, 0xFF, 0x02, 0x13, 0x6A, 0x10, 0x01, 0x58, + 0xD2, 0xF0, 0xBC, 0x08, 0x76, 0x18, 0x18, 0xF4, 0x03, 0x00, 0x0A, 0x12, 0x00, 0xFC, 0x22, 0x01, + 0x18, 0xF4, 0x01, 0x00, 0x06, 0x13, 0x9E, 0xE7, 0x16, 0x00, 0x4C, 0x10, 0xD1, 0xF0, 0xC6, 0x08, + 0x9E, 0xE7, 0x17, 0x00, 0x42, 0x10, 0xD0, 0xF0, 0xD0, 0x08, 0x9E, 0xE7, 0x19, 0x00, 0x38, 0x10, + 0xCF, 0xF0, 0xDA, 0x08, 0x9E, 0xE7, 0x20, 0x00, 0x2E, 0x10, 0xCE, 0xF0, 0xE4, 0x08, 0x9E, 0xE7, + 0x21, 0x00, 0x24, 0x10, 0xCD, 0xF0, 0xEE, 0x08, 0x9E, 0xE7, 0x22, 0x00, 0x1A, 0x10, 0xCC, 0xF0, + 0x00, 0x09, 0x84, 0x80, 0x19, 0xE4, 0x04, 0x00, 0x06, 0x12, 0x9E, 0xE7, 0x12, 0x00, 0x08, 0x10, + 0xCB, 0xF0, 0x08, 0x09, 0x9E, 0xE7, 0x24, 0x00, 0xB1, 0xF0, 0x08, 0x09, 0x05, 0xF0, 0x1A, 0x09, + 0x09, 0xF0, 0x20, 0x09, 0x1E, 0xF0, 0xF8, 0x09, 0xE4, 0x10, 0x00, 0xF2, 0x5C, 0x0B, 0xE9, 0x10, + 0x9C, 0x32, 0x82, 0xE7, 0x20, 0x00, 0x32, 0x1C, 0xE9, 0x09, 0x00, 0xF2, 0x0E, 0x11, 0x85, 0xF0, + 0xFE, 0x09, 0x69, 0x08, 0x01, 0xF0, 0x40, 0x09, 0x1E, 0xF0, 0xF8, 0x09, 0x00, 0xF0, 0x34, 0x09, + 0x30, 0x44, 0x06, 0x12, 0x9E, 0xE7, 0x42, 0x00, 0xB8, 0x10, 0x04, 0xF6, 0x01, 0x00, 0xB3, 0x45, + 0x74, 0x12, 0x04, 0x80, 0x18, 0xE4, 0x20, 0x00, 0x22, 0x13, 0x4B, 0xE4, 0x02, 0x00, 0x36, 0x12, + 0x4B, 0xE4, 0x28, 0x00, 0xAC, 0x13, 0x00, 0xF2, 0xB8, 0x11, 0x00, 0xF2, 0xC4, 0x11, 0x03, 0xF6, + 0xD0, 0x00, 0xFA, 0x14, 0x82, 0xE7, 0x01, 0x00, 0x00, 0xF0, 0x80, 0x01, 0x9E, 0xE7, 0x44, 0x00, + 0x4B, 0xE4, 0x02, 0x00, 0x06, 0x12, 0x03, 0xE6, 0x02, 0x00, 0x76, 0x10, 0x00, 0xF2, 0x9E, 0x0D, + 0x03, 0xE6, 0x02, 0x00, 0x6C, 0x10, 0x00, 0xF2, 0x9E, 0x0D, 0x19, 0x82, 0x34, 0x46, 0x0A, 0x13, + 0x03, 0xE6, 0x02, 0x00, 0x9E, 0xE7, 0x43, 0x00, 0x68, 0x10, 0x04, 0x80, 0x30, 0xE4, 0x20, 0x00, + 0x04, 0x40, 0x00, 0xF2, 0xB8, 0x11, 0x00, 0xF2, 0xC4, 0x11, 0x82, 0xE7, 0x01, 0x00, 0x06, 0xF7, + 0x02, 0x00, 0x00, 0xF0, 0x08, 0x03, 0x04, 0x80, 0x18, 0xE4, 0x20, 0x00, 0x06, 0x12, 0x03, 0xE6, + 0x02, 0x00, 0x3E, 0x10, 0x04, 0x80, 0x18, 0xE4, 0x02, 0x00, 0x3A, 0x12, 0x04, 0x80, 0x18, 0xE4, + 0xFD, 0x00, 0x04, 0x40, 0x1C, 0x1C, 0x9D, 0xF0, 0xE6, 0x09, 0x1C, 0x1C, 0x9D, 0xF0, 0xEC, 0x09, + 0xC1, 0x10, 0x9E, 0xE7, 0x13, 0x00, 0x0A, 0x10, 0x9E, 0xE7, 0x41, 0x00, 0x04, 0x10, 0x9E, 0xE7, + 0x24, 0x00, 0x00, 0xFC, 0xBE, 0x00, 0x98, 0x57, 0xD5, 0xF0, 0x8A, 0x02, 0x04, 0xE6, 0x04, 0x00, + 0x06, 0x10, 0x04, 0xE6, 0x04, 0x00, 0x9D, 0x41, 0x1C, 0x42, 0x9F, 0xE7, 0x00, 0x00, 0x06, 0xF7, + 0x02, 0x00, 0x03, 0xF6, 0xE0, 0x00, 0x3C, 0x14, 0x44, 0x58, 0x45, 0x58, 0x00, 0xF2, 0xF2, 0x0D, + 0x00, 0xF2, 0x7A, 0x10, 0x00, 0xF2, 0xC2, 0x0F, 0x3C, 0x14, 0x1E, 0x1C, 0x00, 0xF0, 0x80, 0x01, + 0x12, 0x1C, 0x22, 0x1C, 0xD2, 0x14, 0x00, 0xF0, 0x72, 0x01, 0x83, 0x59, 0x03, 0xDC, 0x73, 0x57, + 0x80, 0x5D, 0x00, 0x16, 0x83, 0x59, 0x03, 0xDC, 0x38, 0x54, 0x70, 0x57, 0x33, 0x54, 0x3B, 0x54, + 0x80, 0x5D, 0x00, 0x16, 0x03, 0x57, 0x83, 0x59, 0x38, 0x54, 0x00, 0xCC, 0x00, 0x16, 0x03, 0x57, + 0x83, 0x59, 0x00, 0x4C, 0x00, 0x16, 0x02, 0x80, 0x48, 0xE4, 0x01, 0x00, 0x0E, 0x12, 0x48, 0xE4, + 0x05, 0x00, 0x08, 0x12, 0x00, 0xF2, 0xB8, 0x11, 0x00, 0xF2, 0xC4, 0x11, 0xC1, 0x5A, 0x3A, 0x55, + 0x02, 0xEC, 0xB5, 0x00, 0x45, 0x59, 0x00, 0xF2, 0xF2, 0x0D, 0x83, 0x58, 0x30, 0xE7, 0x00, 0x00, + 0x10, 0x4D, 0x30, 0xE7, 0x40, 0x00, 0x10, 0x4F, 0x38, 0x90, 0xBA, 0x90, 0x10, 0x5C, 0x80, 0x5C, + 0x83, 0x5A, 0x10, 0x4E, 0x04, 0xEA, 0xB5, 0x00, 0x43, 0x5B, 0x03, 0xF4, 0xE0, 0x00, 0x83, 0x59, + 0x04, 0xCC, 0x01, 0x4A, 0x0A, 0x12, 0x45, 0x5A, 0x00, 0xF2, 0xF2, 0x0D, 0x00, 0xF2, 0x34, 0x10, + 0x00, 0x16, 0x08, 0x1C, 0x00, 0xFC, 0xAC, 0x00, 0x06, 0x58, 0x67, 0x18, 0x18, 0xF4, 0x8F, 0xE1, + 0x01, 0xFC, 0xAE, 0x00, 0x19, 0xF4, 0x70, 0x1E, 0xB0, 0x54, 0x07, 0x58, 0x00, 0xFC, 0xB0, 0x00, + 0x08, 0x58, 0x00, 0xFC, 0xB2, 0x00, 0x09, 0x58, 0x0A, 0x1C, 0x00, 0xE6, 0x0F, 0x00, 0x00, 0xEA, + 0xB9, 0x00, 0x38, 0x54, 0x00, 0xFA, 0x24, 0x01, 0x00, 0xFA, 0xB6, 0x00, 0x18, 0x1C, 0x14, 0x1C, + 0x10, 0x1C, 0x32, 0x1C, 0x12, 0x1C, 0x00, 0x16, 0x3E, 0x57, 0x0C, 0x14, 0x0E, 0x47, 0x07, 0xE6, + 0x10, 0x00, 0xCE, 0x47, 0xF5, 0x13, 0x00, 0x16, 0x00, 0xF2, 0x9E, 0x0D, 0x02, 0x4B, 0x03, 0xF6, + 0xE0, 0x00, 0x00, 0xF2, 0x64, 0x0A, 0x01, 0x48, 0x20, 0x12, 0x44, 0x58, 0x45, 0x58, 0x9E, 0xE7, + 0x15, 0x00, 0x9C, 0xE7, 0x04, 0x00, 0x00, 0xF2, 0xF2, 0x0D, 0x00, 0xF2, 0x7A, 0x10, 0x00, 0xF2, + 0xC2, 0x0F, 0x00, 0xF2, 0x76, 0x0A, 0x1E, 0x1C, 0xD5, 0x10, 0x00, 0x16, 0x69, 0x08, 0x48, 0xE4, + 0x04, 0x00, 0x64, 0x12, 0x48, 0xE4, 0x02, 0x00, 0x20, 0x12, 0x48, 0xE4, 0x03, 0x00, 0x1A, 0x12, + 0x48, 0xE4, 0x08, 0x00, 0x14, 0x12, 0x48, 0xE4, 0x01, 0x00, 0xF0, 0x12, 0x48, 0xE4, 0x07, 0x00, + 0x12, 0x12, 0x01, 0xE6, 0x07, 0x00, 0x00, 0xF2, 0x4A, 0x0D, 0x00, 0xF2, 0x0E, 0x11, 0x05, 0xF0, + 0x5C, 0x0B, 0x00, 0x16, 0x00, 0xE6, 0x01, 0x00, 0x00, 0xEA, 0x99, 0x00, 0x02, 0x80, 0x48, 0xE4, + 0x03, 0x00, 0xB9, 0x12, 0x48, 0xE4, 0x06, 0x00, 0xB3, 0x12, 0x01, 0xE6, 0x06, 0x00, 0x00, 0xF2, + 0x4A, 0x0D, 0x00, 0xF2, 0x0E, 0x11, 0x04, 0xE6, 0x02, 0x00, 0x9E, 0xE7, 0x15, 0x00, 0x01, 0xF0, + 0x18, 0x0A, 0x00, 0xF0, 0xFE, 0x09, 0x00, 0x16, 0x02, 0x80, 0x48, 0xE4, 0x10, 0x00, 0x1C, 0x12, + 0x82, 0xE7, 0x08, 0x00, 0x3C, 0x56, 0x03, 0x82, 0x00, 0xF2, 0xDE, 0x0D, 0x30, 0xE7, 0x08, 0x00, + 0x04, 0xF7, 0x70, 0x01, 0x06, 0xF7, 0x02, 0x00, 0x00, 0xF0, 0x80, 0x01, 0x6C, 0x19, 0xED, 0x19, + 0x5D, 0xF0, 0xD0, 0x0B, 0x44, 0x55, 0xE5, 0x55, 0x59, 0xF0, 0x4E, 0x0C, 0x04, 0x55, 0xA5, 0x55, + 0x1F, 0x80, 0x01, 0xEC, 0xB8, 0x00, 0x82, 0x48, 0x82, 0x80, 0x49, 0x44, 0x2E, 0x13, 0x01, 0xEC, + 0xB8, 0x00, 0x41, 0xE4, 0x02, 0x00, 0x01, 0xEA, 0xB8, 0x00, 0x49, 0xE4, 0x11, 0x00, 0x59, 0xF0, + 0x2A, 0x0C, 0x01, 0xE6, 0x17, 0x00, 0x01, 0xEA, 0xB8, 0x00, 0x02, 0x4B, 0x88, 0x90, 0xAC, 0x50, + 0x8A, 0x90, 0xAE, 0x50, 0x01, 0xEC, 0xB8, 0x00, 0x82, 0x48, 0x82, 0x80, 0x10, 0x44, 0x02, 0x4B, + 0x1F, 0x40, 0xC0, 0x44, 0x00, 0xF2, 0xB0, 0x0D, 0x04, 0x55, 0xA5, 0x55, 0x9F, 0x10, 0x0C, 0x51, + 0x8E, 0x51, 0x30, 0x90, 0xB2, 0x90, 0x00, 0x56, 0xA1, 0x56, 0x30, 0x50, 0xB2, 0x50, 0x34, 0x90, + 0xB6, 0x90, 0x40, 0x56, 0xE1, 0x56, 0x34, 0x50, 0xB6, 0x50, 0x65, 0x10, 0xB1, 0xF0, 0x6C, 0x0C, + 0x85, 0xF0, 0xC6, 0x0B, 0xE9, 0x09, 0x4B, 0xE4, 0x03, 0x00, 0x78, 0x12, 0x4B, 0xE4, 0x02, 0x00, + 0x01, 0x13, 0xB1, 0xF0, 0x82, 0x0C, 0x85, 0xF0, 0xC6, 0x0B, 0x69, 0x08, 0x48, 0xE4, 0x03, 0x00, + 0xD5, 0xF0, 0x82, 0x0B, 0x00, 0xF2, 0x0E, 0x11, 0x85, 0xF0, 0xC6, 0x0B, 0xE8, 0x09, 0x3C, 0x56, + 0x00, 0xFC, 0x20, 0x01, 0x98, 0x57, 0x02, 0x13, 0xBB, 0x45, 0x4B, 0xE4, 0x00, 0x00, 0x08, 0x12, + 0x03, 0xE6, 0x01, 0x00, 0x04, 0xF6, 0x00, 0x80, 0xA8, 0x14, 0xD2, 0x14, 0x30, 0x1C, 0x02, 0x80, + 0x48, 0xE4, 0x03, 0x00, 0x10, 0x13, 0x00, 0xFC, 0xB6, 0x00, 0x98, 0x57, 0x02, 0x13, 0x4C, 0x1C, + 0x3E, 0x1C, 0x00, 0xF0, 0x8A, 0x0B, 0x00, 0xFC, 0x24, 0x01, 0xB0, 0x57, 0x00, 0xFA, 0x24, 0x01, + 0x4C, 0x1C, 0x3E, 0x1C, 0x00, 0xF2, 0x0E, 0x11, 0x86, 0xF0, 0x8A, 0x0B, 0x00, 0xF2, 0x88, 0x0E, + 0x00, 0xF0, 0x8A, 0x0B, 0xB1, 0xF0, 0xF4, 0x0C, 0x85, 0xF0, 0x82, 0x0B, 0x69, 0x08, 0x48, 0xE4, + 0x01, 0x00, 0xD5, 0xF0, 0x82, 0x0B, 0xFC, 0x14, 0x42, 0x58, 0x6C, 0x14, 0x80, 0x14, 0x30, 0x1C, + 0x4A, 0xF4, 0x02, 0x00, 0x55, 0xF0, 0x82, 0x0B, 0x4A, 0xF4, 0x01, 0x00, 0x0E, 0x12, 0x02, 0x80, + 0x48, 0xE4, 0x03, 0x00, 0x06, 0x13, 0x3E, 0x1C, 0x00, 0xF0, 0x8A, 0x0B, 0x00, 0xFC, 0xB6, 0x00, + 0xB0, 0x57, 0x00, 0xFA, 0xB6, 0x00, 0x4C, 0x1C, 0x3E, 0x1C, 0x00, 0xF2, 0x0E, 0x11, 0x86, 0xF0, + 0x8A, 0x0B, 0x00, 0xF2, 0xB6, 0x0E, 0x00, 0xF0, 0x8A, 0x0B, 0x4C, 0x1C, 0xB1, 0xF0, 0x4C, 0x0D, + 0x85, 0xF0, 0x58, 0x0D, 0x69, 0x08, 0xF3, 0x10, 0x86, 0xF0, 0x60, 0x0D, 0x4E, 0x1C, 0x89, 0x48, + 0x00, 0x16, 0x00, 0xF6, 0x00, 0x01, 0x00, 0x57, 0x00, 0x57, 0x03, 0x58, 0x00, 0xDC, 0x18, 0xF4, + 0xFF, 0x7F, 0x30, 0x56, 0x00, 0x5C, 0x00, 0x16, 0x00, 0xF6, 0x00, 0x01, 0x00, 0x57, 0x00, 0x57, + 0x03, 0x58, 0x00, 0xDC, 0x18, 0xF4, 0x00, 0x80, 0x30, 0x56, 0x00, 0x5C, 0x00, 0x16, 0x00, 0xF6, + 0x00, 0x01, 0x00, 0x57, 0x00, 0x57, 0x03, 0x58, 0x00, 0xDC, 0x0B, 0x58, 0x00, 0x16, 0x03, 0xF6, + 0x24, 0x01, 0x00, 0xF2, 0x54, 0x0A, 0x03, 0xF6, 0xB6, 0x00, 0x00, 0xF2, 0x54, 0x0A, 0x00, 0x16, + 0x02, 0xEC, 0xB8, 0x00, 0x02, 0x49, 0x18, 0xF4, 0xFF, 0x00, 0x00, 0x54, 0x00, 0x54, 0x00, 0x54, + 0x00, 0xF4, 0x08, 0x00, 0xE1, 0x18, 0x80, 0x54, 0x03, 0x58, 0x00, 0xDD, 0x01, 0xDD, 0x02, 0xDD, + 0x03, 0xDC, 0x02, 0x4B, 0x30, 0x50, 0xB2, 0x50, 0x34, 0x51, 0xB6, 0x51, 0x00, 0x16, 0x45, 0x5A, + 0x1D, 0xF4, 0xFF, 0x00, 0x85, 0x56, 0x85, 0x56, 0x85, 0x56, 0x05, 0xF4, 0x02, 0x12, 0x83, 0x5A, + 0x00, 0x16, 0x1D, 0xF4, 0xFF, 0x00, 0x85, 0x56, 0x85, 0x56, 0x85, 0x56, 0x05, 0xF4, 0x00, 0x12, + 0x83, 0x5A, 0x00, 0x16, 0x38, 0x54, 0xBB, 0x55, 0x3C, 0x56, 0xBD, 0x56, 0x00, 0xF2, 0x0E, 0x11, + 0x85, 0xF0, 0x7E, 0x0E, 0xE9, 0x09, 0xC1, 0x59, 0x00, 0xF2, 0x0E, 0x11, 0x85, 0xF0, 0x7E, 0x0E, + 0xE8, 0x0A, 0x83, 0x55, 0x83, 0x55, 0x4B, 0xF4, 0x90, 0x01, 0x5C, 0xF0, 0x32, 0x0E, 0xBD, 0x56, + 0x40, 0x10, 0x4B, 0xF4, 0x30, 0x00, 0x59, 0xF0, 0x44, 0x0E, 0x01, 0xF6, 0x0C, 0x00, 0x00, 0xF6, + 0x01, 0x00, 0x2E, 0x10, 0x02, 0xFC, 0x9C, 0x00, 0x9A, 0x57, 0x14, 0x13, 0x4B, 0xF4, 0x64, 0x00, + 0x59, 0xF0, 0x60, 0x0E, 0x03, 0xF6, 0x64, 0x00, 0x01, 0xF6, 0x19, 0x00, 0x00, 0xF6, 0x01, 0x00, + 0x43, 0xF4, 0x33, 0x00, 0x56, 0xF0, 0x72, 0x0E, 0x04, 0xF4, 0x00, 0x01, 0x43, 0xF4, 0x19, 0x00, + 0xF3, 0x10, 0xB4, 0x56, 0xC3, 0x58, 0x02, 0xFC, 0x9E, 0x00, 0x9A, 0x57, 0x08, 0x13, 0x3C, 0x56, + 0x00, 0xF6, 0x02, 0x00, 0x00, 0x16, 0x00, 0x16, 0x09, 0xE7, 0x01, 0x00, 0x00, 0xF2, 0x0E, 0x11, + 0x86, 0xF0, 0xB4, 0x0E, 0x09, 0xE7, 0x02, 0x00, 0x00, 0xF2, 0x0E, 0x11, 0x86, 0xF0, 0xB4, 0x0E, + 0x09, 0xE7, 0x03, 0x00, 0x00, 0xF2, 0x0E, 0x11, 0x86, 0xF0, 0xB4, 0x0E, 0x4E, 0x1C, 0x89, 0x49, + 0x00, 0xF2, 0x0E, 0x11, 0x00, 0x16, 0x09, 0xE7, 0x01, 0x00, 0x00, 0xF2, 0x0E, 0x11, 0x86, 0xF0, + 0xEE, 0x0E, 0x09, 0xE7, 0x03, 0x00, 0x00, 0xF2, 0x0E, 0x11, 0x86, 0xF0, 0xEE, 0x0E, 0x09, 0xE7, + 0x01, 0x00, 0x00, 0xF2, 0x0E, 0x11, 0x86, 0xF0, 0xEE, 0x0E, 0x89, 0x49, 0x00, 0xF2, 0x0E, 0x11, + 0x86, 0xF0, 0xEE, 0x0E, 0x4E, 0x1C, 0x89, 0x4A, 0x00, 0xF2, 0x0E, 0x11, 0x00, 0x16, 0x3C, 0x56, + 0x00, 0x16, 0x00, 0xEC, 0x26, 0x01, 0x48, 0xE4, 0x01, 0x00, 0x1E, 0x13, 0x38, 0x44, 0x00, 0xEA, + 0x26, 0x01, 0x49, 0xF4, 0x00, 0x00, 0x04, 0x12, 0x4E, 0x1C, 0x02, 0x10, 0x4C, 0x1C, 0x01, 0xEC, + 0x27, 0x01, 0x89, 0x48, 0x00, 0xF2, 0x0E, 0x11, 0x02, 0x14, 0x00, 0x16, 0x85, 0xF0, 0x4E, 0x0F, + 0x38, 0x54, 0x00, 0xEA, 0x99, 0x00, 0x00, 0xF2, 0x5C, 0x0B, 0x02, 0x80, 0x48, 0xE4, 0x06, 0x00, + 0x1C, 0x13, 0x00, 0xEC, 0x99, 0x00, 0x48, 0xE4, 0x01, 0x00, 0x0A, 0x12, 0x04, 0x80, 0x30, 0xE4, + 0x01, 0x00, 0x04, 0x40, 0x08, 0x10, 0x04, 0x80, 0x18, 0xE4, 0xFE, 0x00, 0x04, 0x40, 0x00, 0x16, + 0x02, 0xF6, 0xE0, 0x00, 0x02, 0x57, 0x03, 0x59, 0x01, 0xCC, 0x81, 0x48, 0x22, 0x12, 0x00, 0x4E, + 0x83, 0x5A, 0x90, 0x4C, 0x20, 0xE7, 0x00, 0x00, 0xC3, 0x58, 0x1B, 0xF4, 0xFF, 0x00, 0x83, 0x55, + 0x83, 0x55, 0x83, 0x55, 0x03, 0xF4, 0x00, 0x12, 0x8B, 0x55, 0x83, 0x59, 0x00, 0x4E, 0x00, 0x16, + 0x00, 0x4E, 0x02, 0xF6, 0xF0, 0x00, 0x02, 0x57, 0x03, 0x59, 0x00, 0x4E, 0x83, 0x5A, 0x30, 0xE7, + 0x00, 0x00, 0x20, 0xE7, 0x00, 0x00, 0x00, 0x16, 0x02, 0xF6, 0xF0, 0x00, 0x02, 0x57, 0x03, 0x59, + 0x01, 0xCC, 0x00, 0x4E, 0x83, 0x5A, 0x30, 0xE7, 0x00, 0x00, 0x80, 0x4C, 0xC3, 0x58, 0x1B, 0xF4, + 0xFF, 0x00, 0x83, 0x55, 0x83, 0x55, 0x83, 0x55, 0x03, 0xF4, 0x00, 0x12, 0x83, 0x59, 0x00, 0x4E, + 0x00, 0x16, 0x03, 0xF6, 0xE0, 0x00, 0x03, 0x57, 0x83, 0x59, 0x3A, 0x55, 0x02, 0xCC, 0x45, 0x5A, + 0x00, 0xF2, 0xF2, 0x0D, 0xC0, 0x5A, 0x40, 0x5C, 0x38, 0x54, 0x00, 0xCD, 0x01, 0xCC, 0x4A, 0x46, + 0x0A, 0x13, 0x83, 0x59, 0x00, 0x4C, 0x01, 0x48, 0x16, 0x13, 0x0C, 0x10, 0xC5, 0x58, 0x00, 0xF2, + 0xF2, 0x0D, 0x00, 0x4C, 0x01, 0x48, 0x08, 0x13, 0x05, 0xF6, 0xF0, 0x00, 0x05, 0x57, 0x08, 0x10, + 0x45, 0x58, 0x00, 0xF2, 0xF2, 0x0D, 0x8D, 0x56, 0x83, 0x5A, 0x80, 0x4C, 0x05, 0x17, 0x00, 0x16, + 0x02, 0x4B, 0x06, 0xF7, 0x04, 0x00, 0x62, 0x0B, 0x03, 0x82, 0x00, 0xF2, 0xDE, 0x0D, 0x02, 0x80, + 0x00, 0x4C, 0x45, 0xF4, 0x02, 0x00, 0x52, 0x14, 0x06, 0xF7, 0x02, 0x00, 0x06, 0x14, 0x00, 0xF2, + 0x50, 0x0F, 0x00, 0x16, 0x02, 0x4B, 0x01, 0xF6, 0xFF, 0x00, 0x38, 0x1C, 0x05, 0xF4, 0x04, 0x00, + 0x83, 0x5A, 0x18, 0xDF, 0x19, 0xDF, 0x1D, 0xF7, 0x3C, 0x00, 0xB8, 0xF0, 0x4A, 0x10, 0x9C, 0x14, + 0x01, 0x48, 0x1C, 0x13, 0x0E, 0xF7, 0x3C, 0x00, 0x03, 0xF7, 0x04, 0x00, 0xAF, 0x19, 0x03, 0x42, + 0x45, 0xF4, 0x02, 0x00, 0x83, 0x5A, 0x02, 0xCC, 0x02, 0x41, 0x45, 0xF4, 0x02, 0x00, 0x00, 0x16, + 0x91, 0x44, 0xD5, 0xF0, 0x3A, 0x10, 0x00, 0xF0, 0x9E, 0x02, 0x01, 0xF6, 0xFF, 0x00, 0x38, 0x1C, + 0x05, 0xF4, 0x04, 0x00, 0x83, 0x5A, 0x18, 0xDF, 0x19, 0xDF, 0x0E, 0xF7, 0x3C, 0x00, 0x03, 0xF7, + 0x04, 0x00, 0x0F, 0x79, 0x1C, 0xF7, 0x3C, 0x00, 0xB8, 0xF0, 0x98, 0x10, 0x4E, 0x14, 0x01, 0x48, + 0x06, 0x13, 0x45, 0xF4, 0x04, 0x00, 0x00, 0x16, 0x91, 0x44, 0xD5, 0xF0, 0x7E, 0x10, 0x00, 0xF0, + 0x9E, 0x02, 0x02, 0xF6, 0xFF, 0x00, 0x38, 0x1C, 0x2C, 0xBC, 0xAE, 0xBC, 0xE2, 0x08, 0x00, 0xEC, + 0xB8, 0x00, 0x02, 0x48, 0x1D, 0xF7, 0x80, 0x00, 0xB8, 0xF0, 0xC8, 0x10, 0x1E, 0x14, 0x01, 0x48, + 0x0E, 0x13, 0x0E, 0xF7, 0x80, 0x00, 0x38, 0x54, 0x03, 0x58, 0xAF, 0x19, 0x82, 0x48, 0x00, 0x16, + 0x82, 0x48, 0x12, 0x45, 0xD5, 0xF0, 0xB6, 0x10, 0x00, 0xF0, 0x9E, 0x02, 0x39, 0xF0, 0xF4, 0x10, + 0x38, 0x44, 0x00, 0x16, 0x7E, 0x18, 0x18, 0xF4, 0x03, 0x00, 0x04, 0x13, 0x61, 0x18, 0x00, 0x16, + 0x38, 0x1C, 0x00, 0xFC, 0x22, 0x01, 0x18, 0xF4, 0x01, 0x00, 0xF1, 0x12, 0xE3, 0x10, 0x30, 0x44, + 0x30, 0x44, 0x30, 0x44, 0xB1, 0xF0, 0x14, 0x11, 0x00, 0x16, 0x3E, 0x57, 0x03, 0xF6, 0xE0, 0x00, + 0x03, 0x57, 0x83, 0x59, 0x04, 0xCC, 0x01, 0x4A, 0x6A, 0x12, 0x45, 0x5A, 0x00, 0xF2, 0xF2, 0x0D, + 0x02, 0x4B, 0x70, 0x14, 0x34, 0x13, 0x02, 0x80, 0x48, 0xE4, 0x08, 0x00, 0x18, 0x12, 0x9C, 0xE7, + 0x02, 0x00, 0x9E, 0xE7, 0x15, 0x00, 0x00, 0xF2, 0xC2, 0x0F, 0x00, 0xF2, 0x76, 0x0A, 0x1E, 0x1C, + 0x01, 0xF6, 0x01, 0x00, 0x00, 0x16, 0x30, 0xE4, 0x10, 0x00, 0x04, 0x40, 0x00, 0xF2, 0xDE, 0x0D, + 0x20, 0xE7, 0x01, 0x00, 0x01, 0xF6, 0x01, 0x00, 0x00, 0x16, 0x04, 0xDC, 0x01, 0x4A, 0x24, 0x12, + 0x45, 0x5A, 0x00, 0xF2, 0xF2, 0x0D, 0x43, 0x5B, 0x06, 0xEC, 0x98, 0x00, 0x00, 0xF2, 0x34, 0x10, + 0xC6, 0x59, 0x20, 0x14, 0x0A, 0x13, 0x00, 0xF2, 0xC2, 0x0F, 0x00, 0xF2, 0x10, 0x10, 0xA7, 0x10, + 0x83, 0x5A, 0xD7, 0x10, 0x0E, 0x47, 0x07, 0xE6, 0x10, 0x00, 0xCE, 0x47, 0x5A, 0xF0, 0x1C, 0x11, + 0xB9, 0x54, 0x00, 0x16, 0x14, 0x90, 0x96, 0x90, 0x02, 0xFC, 0xA8, 0x00, 0x03, 0xFC, 0xAA, 0x00, + 0x48, 0x55, 0x02, 0x13, 0xC9, 0x55, 0x00, 0x16, 0x00, 0xEC, 0xBA, 0x00, 0x10, 0x44, 0x00, 0xEA, + 0xBA, 0x00, 0x00, 0x16, 0x03, 0xF6, 0xC0, 0x00, 0x00, 0xF2, 0x64, 0x0A, 0x10, 0x44, 0x00, 0x4C, + 0x00, 0x16 }; + +unsigned short _adv_mcode_size ASC_INITDATA = + sizeof(_adv_mcode_buf); /* 0x11D2 */ +unsigned long _adv_mcode_chksum ASC_INITDATA = 0x0347D07AUL; + +/* a_init.c */ +/* + * EEPROM Configuration. + * + * All drivers should use this structure to set the default EEPROM + * configuration. The BIOS now uses this structure when it is built. + * Additional structure information can be found in a_condor.h where + * the structure is defined. + */ +STATIC ADVEEP_CONFIG +Default_EEPROM_Config ASC_INITDATA = { + ADV_EEPROM_BIOS_ENABLE, /* cfg_msw */ + 0x0000, /* cfg_lsw */ + 0xFFFF, /* disc_enable */ + 0xFFFF, /* wdtr_able */ + 0xFFFF, /* sdtr_able */ + 0xFFFF, /* start_motor */ + 0xFFFF, /* tagqng_able */ + 0xFFFF, /* bios_scan */ + 0, /* scam_tolerant */ + 7, /* adapter_scsi_id */ + 0, /* bios_boot_delay */ + 3, /* scsi_reset_delay */ + 0, /* bios_id_lun */ + 0, /* termination */ + 0, /* reserved1 */ + 0xFFEF, /* bios_ctrl */ + 0xFFFF, /* ultra_able */ + 0, /* reserved2 */ + ASC_DEF_MAX_HOST_QNG, /* max_host_qng */ + ASC_DEF_MAX_DVC_QNG, /* max_dvc_qng */ + 0, /* dvc_cntl */ + 0, /* bug_fix */ + 0, /* serial_number_word1 */ + 0, /* serial_number_word2 */ + 0, /* serial_number_word3 */ + 0, /* check_sum */ + { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, /* oem_name[16] */ + 0, /* dvc_err_code */ + 0, /* adv_err_code */ + 0, /* adv_err_addr */ + 0, /* saved_dvc_err_code */ + 0, /* saved_adv_err_code */ + 0, /* saved_adv_err_addr */ + 0 /* num_of_err */ +}; + +/* + * Initialize the ADV_DVC_VAR structure. + * + * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR. + * + * For a non-fatal error return a warning code. If there are no warnings + * then 0 is returned. + */ +ASC_INITFUNC( +int +AdvInitGetConfig(ADV_DVC_VAR *asc_dvc) +) +{ + ushort warn_code; + AdvPortAddr iop_base; + uchar pci_cmd_reg; + int status; + + warn_code = 0; + asc_dvc->err_code = 0; + iop_base = asc_dvc->iop_base; + + /* + * PCI Command Register + */ + + if (((pci_cmd_reg = DvcAdvReadPCIConfigByte(asc_dvc, + AscPCIConfigCommandRegister)) + & AscPCICmdRegBits_BusMastering) + != AscPCICmdRegBits_BusMastering) + { + pci_cmd_reg |= AscPCICmdRegBits_BusMastering; + + DvcAdvWritePCIConfigByte(asc_dvc, + AscPCIConfigCommandRegister, pci_cmd_reg); + + if (((DvcAdvReadPCIConfigByte(asc_dvc, AscPCIConfigCommandRegister)) + & AscPCICmdRegBits_BusMastering) + != AscPCICmdRegBits_BusMastering) + { + warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE; + } + } + + /* + * PCI Latency Timer + * + * If the "latency timer" register is 0x20 or above, then we don't need + * to change it. Otherwise, set it to 0x20 (i.e. set it to 0x20 if it + * comes up less than 0x20). + */ + if (DvcAdvReadPCIConfigByte(asc_dvc, AscPCIConfigLatencyTimer) < 0x20) { + DvcAdvWritePCIConfigByte(asc_dvc, AscPCIConfigLatencyTimer, 0x20); + if (DvcAdvReadPCIConfigByte(asc_dvc, AscPCIConfigLatencyTimer) < 0x20) + { + warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE; + } + } + + /* + * Save the state of the PCI Configuration Command Register + * "Parity Error Response Control" Bit. If the bit is clear (0), + * in AdvInitAsc3550Driver() tell the microcode to ignore DMA + * parity errors. + */ + asc_dvc->cfg->control_flag = 0; + if (((DvcAdvReadPCIConfigByte(asc_dvc, AscPCIConfigCommandRegister) + & AscPCICmdRegBits_ParErrRespCtrl)) == 0) + { + asc_dvc->cfg->control_flag |= CONTROL_FLAG_IGNORE_PERR; + } + + asc_dvc->cur_host_qng = 0; + + asc_dvc->cfg->lib_version = (ADV_LIB_VERSION_MAJOR << 8) | + ADV_LIB_VERSION_MINOR; + asc_dvc->cfg->chip_version = + AdvGetChipVersion(iop_base, asc_dvc->bus_type); + + /* + * Reset the chip to start and allow register writes. + */ + if (AdvFindSignature(iop_base) == 0) + { + asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE; + return ADV_ERROR; + } + else { + + AdvResetChip(asc_dvc); + + if ((status = AdvInitFromEEP(asc_dvc)) == ADV_ERROR) + { + return ADV_ERROR; + } + warn_code |= status; + + /* + * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus + * Resets should be performed. + */ + if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) + { + AdvResetSCSIBus(asc_dvc); + } + } + + return warn_code; +} + +/* + * Initialize the ASC3550. + * + * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR. + * + * For a non-fatal error return a warning code. If there are no warnings + * then 0 is returned. + */ +ASC_INITFUNC( +int +AdvInitAsc3550Driver(ADV_DVC_VAR *asc_dvc) +) +{ + AdvPortAddr iop_base; + ushort warn_code; + ulong sum; + int begin_addr; + int end_addr; + int code_sum; + int word; + int rql_addr; /* RISC Queue List address */ + int i; + ushort scsi_cfg1; + uchar biosmem[ASC_MC_BIOSLEN]; /* BIOS RISC Memory 0x40-0x8F. */ + + /* If there is already an error, don't continue. */ + if (asc_dvc->err_code != 0) + { + return ADV_ERROR; + } + + warn_code = 0; + iop_base = asc_dvc->iop_base; + + /* + * Save the RISC memory BIOS region before writing the microcode. + * The BIOS may already be loaded and using its RISC LRAM region + * so its region must be saved and restored. + * + * Note: This code makes the assumption, which is currently true, + * that a chip reset does not clear RISC LRAM. + */ + for (i = 0; i < ASC_MC_BIOSLEN; i++) + { + AdvReadByteLram(iop_base, ASC_MC_BIOSMEM + i, biosmem[i]); + } + + /* + * Load the Microcode + * + * Write the microcode image to RISC memory starting at address 0. + */ + AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0); + for (word = 0; word < _adv_mcode_size; word += 2) + { + AdvWriteWordAutoIncLram(iop_base, + *((ushort *) (&_adv_mcode_buf[word]))); + } + + /* + * Clear the rest of Condor's Internal RAM (8KB). + */ + for (; word < ADV_CONDOR_MEMSIZE; word += 2) + { + AdvWriteWordAutoIncLram(iop_base, 0); + } + + /* + * Verify the microcode checksum. + */ + sum = 0; + AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0); + for (word = 0; word < _adv_mcode_size; word += 2) + { + sum += AdvReadWordAutoIncLram(iop_base); + } + + if (sum != _adv_mcode_chksum) + { + asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM; + return ADV_ERROR; + } + + /* + * Restore the RISC memory BIOS region. + */ + for (i = 0; i < ASC_MC_BIOSLEN; i++) + { + AdvWriteByteLram(iop_base, ASC_MC_BIOSMEM + i, biosmem[i]); + } + + /* + * Calculate and write the microcode code checksum to the microcode + * code checksum location ASC_MC_CODE_CHK_SUM (0x2C). + */ + AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr); + AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr); + code_sum = 0; + for (word = begin_addr; word < end_addr; word += 2) + { + code_sum += *((ushort *) (&_adv_mcode_buf[word])); + } + AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum); + + /* + * Read microcode version and date. + */ + AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE, asc_dvc->cfg->mcode_date); + AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM, asc_dvc->cfg->mcode_version); + + /* + * Initialize microcode operating variables + */ + AdvWriteWordLram(iop_base, ASC_MC_ADAPTER_SCSI_ID, + asc_dvc->chip_scsi_id); + + /* + * If the PCI Configuration Command Register "Parity Error Response + * Control" Bit was clear (0), then set the microcode variable + * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode + * to ignore DMA parity errors. + */ + if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) + { + /* + * Note: Don't remove the use of a temporary variable in + * the following code, otherwise the Microsoft C compiler + * will turn the following lines into a no-op. + */ + AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word); + word |= CONTROL_FLAG_IGNORE_PERR; + AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word); + } + + /* + * Set default microcode operating variables for WDTR, SDTR, and + * command tag queuing based on the EEPROM configuration values. + * + * These ADV_DVC_VAR fields and the microcode variables will be + * changed in AdvInquiryHandling() if it is found a device is + * incapable of a particular feature. + */ + + /* + * Set the microcode ULTRA target mask from EEPROM value. The + * SDTR target mask overrides the ULTRA target mask in the + * microcode so it is safe to set this value without determining + * whether the device supports SDTR. + * + * Note: There is no way to know whether a device supports ULTRA + * speed without attempting a SDTR ULTRA speed negotiation with + * the device. The device will reject the speed if it does not + * support it by responding with an SDTR message containing a + * slower speed. + */ + AdvWriteWordLram(iop_base, ASC_MC_ULTRA_ABLE, asc_dvc->ultra_able); + AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE, asc_dvc->cfg->disc_enable); + + + /* + * Set SCSI_CFG0 Microcode Default Value. + * + * The microcode will set the SCSI_CFG0 register using this value + * after it is started below. + */ + AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0, + PARITY_EN | SEL_TMO_LONG | OUR_ID_EN | asc_dvc->chip_scsi_id); + + /* + * Determine SCSI_CFG1 Microcode Default Value. + * + * The microcode will set the SCSI_CFG1 register using this value + * after it is started below. + */ + + /* Read current SCSI_CFG1 Register value. */ + scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1); + + /* + * If all three connectors are in use, return an error. + */ + if ((scsi_cfg1 & CABLE_ILLEGAL_A) == 0 || + (scsi_cfg1 & CABLE_ILLEGAL_B) == 0) + { + asc_dvc->err_code |= ASC_IERR_ILLEGAL_CONNECTION; + return ADV_ERROR; + } + + /* + * If the internal narrow cable is reversed all of the SCSI_CTRL + * register signals will be set. Check for and return an error if + * this condition is found. + */ + if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) + { + asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE; + return ADV_ERROR; + } + + /* + * If this is a differential board and a single-ended device + * is attached to one of the connectors, return an error. + */ + if ((scsi_cfg1 & DIFF_MODE) && (scsi_cfg1 & DIFF_SENSE) == 0) + { + asc_dvc->err_code |= ASC_IERR_SINGLE_END_DEVICE; + return ADV_ERROR; + } + + /* + * If automatic termination control is enabled, then set the + * termination value based on a table listed in a_condor.h. + * + * If manual termination was specified with an EEPROM setting + * then 'termination' was set-up in AdvInitFromEEP() and + * is ready to be 'ored' into SCSI_CFG1. + */ + if (asc_dvc->cfg->termination == 0) + { + /* + * The software always controls termination by setting TERM_CTL_SEL. + * If TERM_CTL_SEL were set to 0, the hardware would set termination. + */ + asc_dvc->cfg->termination |= TERM_CTL_SEL; + + switch(scsi_cfg1 & CABLE_DETECT) + { + /* TERM_CTL_H: on, TERM_CTL_L: on */ + case 0x3: case 0x7: case 0xB: case 0xD: case 0xE: case 0xF: + asc_dvc->cfg->termination |= (TERM_CTL_H | TERM_CTL_L); + break; + + /* TERM_CTL_H: on, TERM_CTL_L: off */ + case 0x1: case 0x5: case 0x9: case 0xA: case 0xC: + asc_dvc->cfg->termination |= TERM_CTL_H; + break; + + /* TERM_CTL_H: off, TERM_CTL_L: off */ + case 0x2: case 0x6: + break; + } + } + + /* + * Clear any set TERM_CTL_H and TERM_CTL_L bits. + */ + scsi_cfg1 &= ~TERM_CTL; + + /* + * Invert the TERM_CTL_H and TERM_CTL_L bits and then + * set 'scsi_cfg1'. The TERM_POL bit does not need to be + * referenced, because the hardware internally inverts + * the Termination High and Low bits if TERM_POL is set. + */ + scsi_cfg1 |= (TERM_CTL_SEL | (~asc_dvc->cfg->termination & TERM_CTL)); + + /* + * Set SCSI_CFG1 Microcode Default Value + * + * Set filter value and possibly modified termination control + * bits in the Microcode SCSI_CFG1 Register Value. + * + * The microcode will set the SCSI_CFG1 register using this value + * after it is started below. + */ + AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, + FLTR_11_TO_20NS | scsi_cfg1); + + /* + * Set SEL_MASK Microcode Default Value + * + * The microcode will set the SEL_MASK register using this value + * after it is started below. + */ + AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK, + ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id)); + + /* + * Link all the RISC Queue Lists together in a doubly-linked + * NULL terminated list. + * + * Skip the NULL (0) queue which is not used. + */ + for (i = 1, rql_addr = ASC_MC_RISC_Q_LIST_BASE + ASC_MC_RISC_Q_LIST_SIZE; + i < ASC_MC_RISC_Q_TOTAL_CNT; + i++, rql_addr += ASC_MC_RISC_Q_LIST_SIZE) + { + /* + * Set the current RISC Queue List's RQL_FWD and RQL_BWD pointers + * in a one word write and set the state (RQL_STATE) to free. + */ + AdvWriteWordLram(iop_base, rql_addr, ((i + 1) + ((i - 1) << 8))); + AdvWriteByteLram(iop_base, rql_addr + RQL_STATE, ASC_MC_QS_FREE); + } + + /* + * Set the Host and RISC Queue List pointers. + * + * Both sets of pointers are initialized with the same values: + * ASC_MC_RISC_Q_FIRST(0x01) and ASC_MC_RISC_Q_LAST (0xFF). + */ + AdvWriteByteLram(iop_base, ASC_MC_HOST_NEXT_READY, ASC_MC_RISC_Q_FIRST); + AdvWriteByteLram(iop_base, ASC_MC_HOST_NEXT_DONE, ASC_MC_RISC_Q_LAST); + + AdvWriteByteLram(iop_base, ASC_MC_RISC_NEXT_READY, ASC_MC_RISC_Q_FIRST); + AdvWriteByteLram(iop_base, ASC_MC_RISC_NEXT_DONE, ASC_MC_RISC_Q_LAST); + + /* + * Finally, set up the last RISC Queue List (255) with + * a NULL forward pointer. + */ + AdvWriteWordLram(iop_base, rql_addr, (ASC_MC_NULL_Q + ((i - 1) << 8))); + AdvWriteByteLram(iop_base, rql_addr + RQL_STATE, ASC_MC_QS_FREE); + + AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES, + (ADV_INTR_ENABLE_HOST_INTR | ADV_INTR_ENABLE_GLOBAL_INTR)); + + /* + * Note: Don't remove the use of a temporary variable in + * the following code, otherwise the Microsoft C compiler + * will turn the following lines into a no-op. + */ + AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word); + AdvWriteWordRegister(iop_base, IOPW_PC, word); + + /* finally, finally, gentlemen, start your engine */ + AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN); + + return warn_code; +} + +/* + * Read the board's EEPROM configuration. Set fields in ADV_DVC_VAR and + * ADV_DVC_CFG based on the EEPROM settings. The chip is stopped while + * all of this is done. + * + * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR. + * + * For a non-fatal error return a warning code. If there are no warnings + * then 0 is returned. + * + * Note: Chip is stopped on entry. + */ +ASC_INITFUNC( +STATIC int +AdvInitFromEEP(ADV_DVC_VAR *asc_dvc) +) +{ + AdvPortAddr iop_base; + ushort warn_code; + ADVEEP_CONFIG eep_config; + int i; + + iop_base = asc_dvc->iop_base; + + warn_code = 0; + + /* + * Read the board's EEPROM configuration. + * + * Set default values if a bad checksum is found. + */ + if (AdvGetEEPConfig(iop_base, &eep_config) != eep_config.check_sum) + { + warn_code |= ASC_WARN_EEPROM_CHKSUM; + + /* + * Set EEPROM default values. + */ + for (i = 0; i < sizeof(ADVEEP_CONFIG); i++) + { + *((uchar *) &eep_config + i) = + *((uchar *) &Default_EEPROM_Config + i); + } + + /* + * Assume the 6 byte board serial number that was read + * from EEPROM is correct even if the EEPROM checksum + * failed. + */ + eep_config.serial_number_word3 = + AdvReadEEPWord(iop_base, ASC_EEP_DVC_CFG_END - 1); + eep_config.serial_number_word2 = + AdvReadEEPWord(iop_base, ASC_EEP_DVC_CFG_END - 2); + eep_config.serial_number_word1 = + AdvReadEEPWord(iop_base, ASC_EEP_DVC_CFG_END - 3); + AdvSetEEPConfig(iop_base, &eep_config); + } + + /* + * Set ADV_DVC_VAR and ADV_DVC_CFG variables from the + * EEPROM configuration that was read. + * + * This is the mapping of EEPROM fields to Adv Library fields. + */ + asc_dvc->wdtr_able = eep_config.wdtr_able; + asc_dvc->sdtr_able = eep_config.sdtr_able; + asc_dvc->ultra_able = eep_config.ultra_able; + asc_dvc->tagqng_able = eep_config.tagqng_able; + asc_dvc->cfg->disc_enable = eep_config.disc_enable; + asc_dvc->max_host_qng = eep_config.max_host_qng; + asc_dvc->max_dvc_qng = eep_config.max_dvc_qng; + asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ADV_MAX_TID); + asc_dvc->start_motor = eep_config.start_motor; + asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay; + asc_dvc->cfg->bios_boot_wait = eep_config.bios_boot_delay; + asc_dvc->bios_ctrl = eep_config.bios_ctrl; + asc_dvc->no_scam = eep_config.scam_tolerant; + asc_dvc->cfg->serial1 = eep_config.serial_number_word1; + asc_dvc->cfg->serial2 = eep_config.serial_number_word2; + asc_dvc->cfg->serial3 = eep_config.serial_number_word3; + + /* + * Set the host maximum queuing (max. 253, min. 16) and the per device + * maximum queuing (max. 63, min. 4). + */ + if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) + { + eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG; + } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) + { + /* If the value is zero, assume it is uninitialized. */ + if (eep_config.max_host_qng == 0) + { + eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG; + } else + { + eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG; + } + } + + if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) + { + eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG; + } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) + { + /* If the value is zero, assume it is uninitialized. */ + if (eep_config.max_dvc_qng == 0) + { + eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG; + } else + { + eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG; + } + } + + /* + * If 'max_dvc_qng' is greater than 'max_host_qng', then + * set 'max_dvc_qng' to 'max_host_qng'. + */ + if (eep_config.max_dvc_qng > eep_config.max_host_qng) + { + eep_config.max_dvc_qng = eep_config.max_host_qng; + } + + /* + * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_CFG 'max_dvc_qng' + * values based on possibly adjusted EEPROM values. + */ + asc_dvc->max_host_qng = eep_config.max_host_qng; + asc_dvc->max_dvc_qng = eep_config.max_dvc_qng; + + + /* + * If the EEPROM 'termination' field is set to automatic (0), then set + * the ADV_DVC_CFG 'termination' field to automatic also. + * + * If the termination is specified with a non-zero 'termination' + * value check that a legal value is set and set the ADV_DVC_CFG + * 'termination' field appropriately. + */ + if (eep_config.termination == 0) + { + asc_dvc->cfg->termination = 0; /* auto termination */ + } else + { + /* Enable manual control with low off / high off. */ + if (eep_config.termination == 1) + { + asc_dvc->cfg->termination = TERM_CTL_SEL; + + /* Enable manual control with low off / high on. */ + } else if (eep_config.termination == 2) + { + asc_dvc->cfg->termination = TERM_CTL_SEL | TERM_CTL_H; + + /* Enable manual control with low on / high on. */ + } else if (eep_config.termination == 3) + { + asc_dvc->cfg->termination = TERM_CTL_SEL | TERM_CTL_H | TERM_CTL_L; + } else + { + /* + * The EEPROM 'termination' field contains a bad value. Use + * automatic termination instead. + */ + asc_dvc->cfg->termination = 0; + warn_code |= ASC_WARN_EEPROM_TERMINATION; + } + } + + return warn_code; +} + +/* + * Read EEPROM configuration into the specified buffer. + * + * Return a checksum based on the EEPROM configuration read. + */ +ASC_INITFUNC( +STATIC ushort +AdvGetEEPConfig(AdvPortAddr iop_base, ADVEEP_CONFIG *cfg_buf) +) +{ + ushort wval, chksum; + ushort *wbuf; + int eep_addr; + + wbuf = (ushort *) cfg_buf; + chksum = 0; + + for (eep_addr = ASC_EEP_DVC_CFG_BEGIN; + eep_addr < ASC_EEP_DVC_CFG_END; + eep_addr++, wbuf++) + { + wval = AdvReadEEPWord(iop_base, eep_addr); + chksum += wval; + *wbuf = wval; + } + *wbuf = AdvReadEEPWord(iop_base, eep_addr); + wbuf++; + for (eep_addr = ASC_EEP_DVC_CTL_BEGIN; + eep_addr < ASC_EEP_MAX_WORD_ADDR; + eep_addr++, wbuf++) + { + *wbuf = AdvReadEEPWord(iop_base, eep_addr); + } + return chksum; +} + +/* + * Read the EEPROM from specified location + */ +ASC_INITFUNC( +STATIC ushort +AdvReadEEPWord(AdvPortAddr iop_base, int eep_word_addr) +) +{ + AdvWriteWordRegister(iop_base, IOPW_EE_CMD, + ASC_EEP_CMD_READ | eep_word_addr); + AdvWaitEEPCmd(iop_base); + return AdvReadWordRegister(iop_base, IOPW_EE_DATA); +} + +/* + * Wait for EEPROM command to complete + */ +ASC_INITFUNC( +STATIC void +AdvWaitEEPCmd(AdvPortAddr iop_base) +) +{ + int eep_delay_ms; + + for (eep_delay_ms = 0; eep_delay_ms < ASC_EEP_DELAY_MS; eep_delay_ms++) + { + if (AdvReadWordRegister(iop_base, IOPW_EE_CMD) & ASC_EEP_CMD_DONE) + { + break; + } + DvcSleepMilliSecond(1); + } + if ((AdvReadWordRegister(iop_base, IOPW_EE_CMD) & ASC_EEP_CMD_DONE) == 0) + { + ADV_ASSERT(0); + } + return; +} + +/* + * Write the EEPROM from 'cfg_buf'. + */ +ASC_INITFUNC( +STATIC void +AdvSetEEPConfig(AdvPortAddr iop_base, ADVEEP_CONFIG *cfg_buf) +) +{ + ushort *wbuf; + ushort addr, chksum; + + wbuf = (ushort *) cfg_buf; + chksum = 0; + + AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE); + AdvWaitEEPCmd(iop_base); + + /* + * Write EEPROM from word 0 to word 15 + */ + for (addr = ASC_EEP_DVC_CFG_BEGIN; + addr < ASC_EEP_DVC_CFG_END; addr++, wbuf++) + { + chksum += *wbuf; + AdvWriteWordRegister(iop_base, IOPW_EE_DATA, *wbuf); + AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr); + AdvWaitEEPCmd(iop_base); + DvcSleepMilliSecond(ASC_EEP_DELAY_MS); + } + + /* + * Write EEPROM checksum at word 18 + */ + AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum); + AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr); + AdvWaitEEPCmd(iop_base); + wbuf++; /* skip over check_sum */ + + /* + * Write EEPROM OEM name at words 19 to 26 + */ + for (addr = ASC_EEP_DVC_CTL_BEGIN; + addr < ASC_EEP_MAX_WORD_ADDR; addr++, wbuf++) + { + AdvWriteWordRegister(iop_base, IOPW_EE_DATA, *wbuf); + AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr); + AdvWaitEEPCmd(iop_base); + } + AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE); + AdvWaitEEPCmd(iop_base); + return; +} + +/* + * This function resets the chip and SCSI bus + * + * It is up to the caller to add a delay to let the bus settle after + * calling this function. + * + * The SCSI_CFG0, SCSI_CFG1, and MEM_CFG registers are set-up in + * AdvInitAsc3550Driver(). Here when doing a write to one of these + * registers read first and then write. + * + * Note: A SCSI Bus Reset can not be done until after the EEPROM + * configuration is read to determine whether SCSI Bus Resets + * should be performed. + */ +ASC_INITFUNC( +STATIC void +AdvResetChip(ADV_DVC_VAR *asc_dvc) +) +{ + AdvPortAddr iop_base; + ushort word; + uchar byte; + + iop_base = asc_dvc->iop_base; + + /* + * Reset Chip. + */ + AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, ADV_CTRL_REG_CMD_RESET); + DvcSleepMilliSecond(100); + AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, ADV_CTRL_REG_CMD_WR_IO_REG); + + /* + * Initialize Chip registers. + * + * Note: Don't remove the use of a temporary variable in the following + * code, otherwise the Microsoft C compiler will turn the following lines + * into a no-op. + */ + byte = AdvReadByteRegister(iop_base, IOPB_MEM_CFG); + byte |= RAM_SZ_8KB; + AdvWriteByteRegister(iop_base, IOPB_MEM_CFG, byte); + + word = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1); + word &= ~BIG_ENDIAN; + AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1, word); + + /* + * Setting the START_CTL_EMFU 3:2 bits sets a FIFO threshold + * of 128 bytes. This register is only accessible to the host. + */ + AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0, + START_CTL_EMFU | READ_CMD_MRM); +} + +/* a_advlib.c */ +/* + * Description: + * Send a SCSI request to the ASC3550 chip + * + * If there is no SG list for the request, set 'sg_entry_cnt' to 0. + * + * If 'sg_real_addr' is non-zero on entry, AscGetSGList() will not be + * called. It is assumed the caller has already initialized 'sg_real_addr'. + * + * Return: + * ADV_SUCCESS(1) - the request is in the mailbox + * ADV_BUSY(0) - total request count > 253, try later + * ADV_ERROR(-1) - invalid scsi request Q + */ +STATIC int +AdvExeScsiQueue(ADV_DVC_VAR *asc_dvc, + ADV_SCSI_REQ_Q *scsiq) +{ + if (scsiq == (ADV_SCSI_REQ_Q *) 0L) + { + /* 'scsiq' should never be NULL. */ + ADV_ASSERT(0); + return ADV_ERROR; + } + + return AdvSendScsiCmd(asc_dvc, scsiq); +} + +/* + * Reset SCSI Bus and purge all outstanding requests. + * + * Return Value: + * ADV_TRUE(1) - All requests are purged and SCSI Bus is reset. + * + * Note: Should always return ADV_TRUE. + */ +STATIC int +AdvResetSB(ADV_DVC_VAR *asc_dvc) +{ + int status; + + status = AdvSendIdleCmd(asc_dvc, (ushort) IDLE_CMD_SCSI_RESET, 0L, 0); + + AdvResetSCSIBus(asc_dvc); + + return status; +} + +/* + * Reset SCSI Bus and delay. + */ +STATIC void +AdvResetSCSIBus(ADV_DVC_VAR *asc_dvc) +{ + AdvPortAddr iop_base; + ushort scsi_ctrl; + + iop_base = asc_dvc->iop_base; + + /* + * The microcode currently sets the SCSI Bus Reset signal while + * handling the AscSendIdleCmd() IDLE_CMD_SCSI_RESET command above. + * But the SCSI Bus Reset Hold Time in the microcode is not deterministic + * (it may in fact be for less than the SCSI Spec. minimum of 25 us). + * Therefore on return the Adv Library sets the SCSI Bus Reset signal + * for ASC_SCSI_RESET_HOLD_TIME_US, which is defined to be greater + * than 25 us. + */ + scsi_ctrl = AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL); + AdvWriteWordRegister(iop_base, IOPW_SCSI_CTRL, + scsi_ctrl | ADV_SCSI_CTRL_RSTOUT); + DvcDelayMicroSecond(asc_dvc, (ushort) ASC_SCSI_RESET_HOLD_TIME_US); + AdvWriteWordRegister(iop_base, IOPW_SCSI_CTRL, + scsi_ctrl & ~ADV_SCSI_CTRL_RSTOUT); + + DvcSleepMilliSecond((ulong) asc_dvc->scsi_reset_wait * 1000); +} + + +/* + * Adv Library Interrupt Service Routine + * + * This function is called by a driver's interrupt service routine. + * The function disables and re-enables interrupts. + * + * When a microcode idle command is completed, the ADV_DVC_VAR + * 'idle_cmd_done' field is set to ADV_TRUE. + * + * Note: AdvISR() can be called when interrupts are disabled or even + * when there is no hardware interrupt condition present. It will + * always check for completed idle commands and microcode requests. + * This is an important feature that shouldn't be changed because it + * allows commands to be completed from polling mode loops. + * + * Return: + * ADV_TRUE(1) - interrupt was pending + * ADV_FALSE(0) - no interrupt was pending + */ +STATIC int +AdvISR(ADV_DVC_VAR *asc_dvc) +{ + AdvPortAddr iop_base; + uchar int_stat; + ushort next_done_loc, target_bit; + int completed_q; + int flags; + ADV_SCSI_REQ_Q *scsiq; + ASC_REQ_SENSE *sense_data; + int ret; + + flags = DvcEnterCritical(); + iop_base = asc_dvc->iop_base; + + if (AdvIsIntPending(iop_base)) + { + ret = ADV_TRUE; + } else + { + ret = ADV_FALSE; + } + + /* Reading the register clears the interrupt. */ + int_stat = AdvReadByteRegister(iop_base, IOPB_INTR_STATUS_REG); + + if (int_stat & ADV_INTR_STATUS_INTRB) + { + asc_dvc->idle_cmd_done = ADV_TRUE; + } + + /* + * Notify the driver of a hardware detected SCSI Bus Reset. + */ + if (int_stat & ADV_INTR_STATUS_INTRC) + { + if (asc_dvc->sbreset_callback != 0) + { + (*(ADV_SBRESET_CALLBACK) asc_dvc->sbreset_callback)(asc_dvc); + } + } + + /* + * ASC_MC_HOST_NEXT_DONE (0x129) is actually the last completed RISC + * Queue List request. Its forward pointer (RQL_FWD) points to the + * current completed RISC Queue List request. + */ + AdvReadByteLram(iop_base, ASC_MC_HOST_NEXT_DONE, next_done_loc); + next_done_loc = ASC_MC_RISC_Q_LIST_BASE + + (next_done_loc * ASC_MC_RISC_Q_LIST_SIZE) + RQL_FWD; + + AdvReadByteLram(iop_base, next_done_loc, completed_q); + + /* Loop until all completed Q's are processed. */ + while (completed_q != ASC_MC_NULL_Q) + { + AdvWriteByteLram(iop_base, ASC_MC_HOST_NEXT_DONE, completed_q); + + next_done_loc = ASC_MC_RISC_Q_LIST_BASE + + (completed_q * ASC_MC_RISC_Q_LIST_SIZE); + + /* + * Read the ADV_SCSI_REQ_Q virtual address pointer from + * the RISC list entry. The microcode has changed the + * ADV_SCSI_REQ_Q physical address to its virtual address. + * + * Refer to comments at the end of AdvSendScsiCmd() for + * more information on the RISC list structure. + */ + { + ushort lsw, msw; + AdvReadWordLram(iop_base, next_done_loc + RQL_PHYADDR, lsw); + AdvReadWordLram(iop_base, next_done_loc + RQL_PHYADDR + 2, msw); + + scsiq = (ADV_SCSI_REQ_Q *) (((ulong) msw << 16) | lsw); + } + ADV_ASSERT(scsiq != NULL); + + target_bit = ADV_TID_TO_TIDMASK(scsiq->target_id); + + /* + * Clear request microcode control flag. + */ + scsiq->cntl = 0; + + /* + * Check Condition handling + */ + if ((scsiq->done_status == QD_WITH_ERROR) && + (scsiq->scsi_status == SS_CHK_CONDITION) && + (sense_data = (ASC_REQ_SENSE *) scsiq->vsense_addr) != 0 && + (scsiq->orig_sense_len - scsiq->sense_len) >= ASC_MIN_SENSE_LEN) + { + /* + * Command returned with a check condition and valid + * sense data. + */ + } + /* + * If the command that completed was a SCSI INQUIRY and + * LUN 0 was sent the command, then process the INQUIRY + * command information for the device. + */ + else if (scsiq->done_status == QD_NO_ERROR && + scsiq->cdb[0] == SCSICMD_Inquiry && + scsiq->target_lun == 0) + { + AdvInquiryHandling(asc_dvc, scsiq); + } + + + /* Change the RISC Queue List state to free. */ + AdvWriteByteLram(iop_base, next_done_loc + RQL_STATE, ASC_MC_QS_FREE); + + /* Get the RISC Queue List forward pointer. */ + AdvReadByteLram(iop_base, next_done_loc + RQL_FWD, completed_q); + + /* + * Notify the driver of the completed request by passing + * the ADV_SCSI_REQ_Q pointer to its callback function. + */ + ADV_ASSERT(asc_dvc->cur_host_qng > 0); + asc_dvc->cur_host_qng--; + scsiq->a_flag |= ADV_SCSIQ_DONE; + (*(ADV_ISR_CALLBACK) asc_dvc->isr_callback)(asc_dvc, scsiq); + /* + * Note: After the driver callback function is called, 'scsiq' + * can no longer be referenced. + * + * Fall through and continue processing other completed + * requests... + */ + + /* + * Disable interrupts again in case the driver inadvertently + * enabled interrupts in its callback function. + * + * The DvcEnterCritical() return value is ignored, because + * the 'flags' saved when AdvISR() was first entered will be + * used to restore the interrupt flag on exit. + */ + (void) DvcEnterCritical(); + } + DvcLeaveCritical(flags); + return ret; +} + +/* + * Send an idle command to the chip and wait for completion. + * + * Interrupts do not have to be enabled on entry. + * + * Return Values: + * ADV_TRUE - command completed successfully + * ADV_FALSE - command failed + */ +STATIC int +AdvSendIdleCmd(ADV_DVC_VAR *asc_dvc, + ushort idle_cmd, + ulong idle_cmd_parameter, + int flags) +{ + int last_int_level; + ulong i; + AdvPortAddr iop_base; + int ret; + + asc_dvc->idle_cmd_done = 0; + + last_int_level = DvcEnterCritical(); + iop_base = asc_dvc->iop_base; + + /* + * Write the idle command value after the idle command parameter + * has been written to avoid a race condition. If the order is not + * followed, the microcode may process the idle command before the + * parameters have been written to LRAM. + */ + AdvWriteDWordLram(iop_base, ASC_MC_IDLE_PARA_STAT, idle_cmd_parameter); + AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD, idle_cmd); + DvcLeaveCritical(last_int_level); + + /* + * If the 'flags' argument contains the ADV_NOWAIT flag, then + * return with success. + */ + if (flags & ADV_NOWAIT) + { + return ADV_TRUE; + } + + for (i = 0; i < SCSI_WAIT_10_SEC * SCSI_MS_PER_SEC; i++) + { + /* + * 'idle_cmd_done' is set by AdvISR(). + */ + if (asc_dvc->idle_cmd_done) + { + break; + } + DvcSleepMilliSecond(1); + + /* + * If interrupts were disabled on entry to AdvSendIdleCmd(), + * then they will still be disabled here. Call AdvISR() to + * check for the idle command completion. + */ + (void) AdvISR(asc_dvc); + } + + last_int_level = DvcEnterCritical(); + + if (asc_dvc->idle_cmd_done == ADV_FALSE) + { + ADV_ASSERT(0); /* The idle command should never timeout. */ + return ADV_FALSE; + } else + { + AdvReadWordLram(iop_base, ASC_MC_IDLE_PARA_STAT, ret); + return ret; + } +} + +/* + * Send the SCSI request block to the adapter + * + * Each of the 255 Adv Library/Microcode RISC Lists or mailboxes has the + * following structure: + * + * 0: RQL_FWD - RISC list forward pointer (1 byte) + * 1: RQL_BWD - RISC list backward pointer (1 byte) + * 2: RQL_STATE - RISC list state byte - free, ready, done, aborted (1 byte) + * 3: RQL_TID - request target id (1 byte) + * 4: RQL_PHYADDR - ADV_SCSI_REQ_Q physical pointer (4 bytes) + * + * Return: + * ADV_SUCCESS(1) - the request is in the mailbox + * ADV_BUSY(0) - total request count > 253, try later + */ +STATIC int +AdvSendScsiCmd( + ADV_DVC_VAR *asc_dvc, + ADV_SCSI_REQ_Q *scsiq) +{ + ushort next_ready_loc; + uchar next_ready_loc_fwd; + int last_int_level; + AdvPortAddr iop_base; + long req_size; + ulong q_phy_addr; + + /* + * The ADV_SCSI_REQ_Q 'target_id' field should never be equal + * to the host adapter ID or exceed ADV_MAX_TID. + */ + if (scsiq->target_id == asc_dvc->chip_scsi_id || + scsiq->target_id > ADV_MAX_TID) + { + scsiq->host_status = QHSTA_M_INVALID_DEVICE; + scsiq->done_status = QD_WITH_ERROR; + return ADV_ERROR; + } + + iop_base = asc_dvc->iop_base; + + last_int_level = DvcEnterCritical(); + + if (asc_dvc->cur_host_qng >= asc_dvc->max_host_qng) + { + DvcLeaveCritical(last_int_level); + return ADV_BUSY; + } else + { + ADV_ASSERT(asc_dvc->cur_host_qng < ASC_MC_RISC_Q_TOTAL_CNT); + asc_dvc->cur_host_qng++; + } + + /* + * Clear the ADV_SCSI_REQ_Q done flag. + */ + scsiq->a_flag &= ~ADV_SCSIQ_DONE; + + /* + * Save the original sense buffer length. + * + * After the request completes 'sense_len' will be set to the residual + * byte count of the Auto-Request Sense if a command returns CHECK + * CONDITION and the Sense Data is valid indicated by 'host_status' not + * being set to QHSTA_M_AUTO_REQ_SENSE_FAIL. To determine the valid + * Sense Data Length subtract 'sense_len' from 'orig_sense_len'. + */ + scsiq->orig_sense_len = scsiq->sense_len; + + AdvReadByteLram(iop_base, ASC_MC_HOST_NEXT_READY, next_ready_loc); + next_ready_loc = ASC_MC_RISC_Q_LIST_BASE + + (next_ready_loc * ASC_MC_RISC_Q_LIST_SIZE); + + /* + * Write the physical address of the Q to the mailbox. + * We need to skip the first four bytes, because the microcode + * uses them internally for linking Q's together. + */ + req_size = sizeof(ADV_SCSI_REQ_Q); + q_phy_addr = DvcGetPhyAddr(asc_dvc, scsiq, + (uchar *) scsiq, &req_size, + ADV_IS_SCSIQ_FLAG); + ADV_ASSERT(ADV_DWALIGN(q_phy_addr) == q_phy_addr); + ADV_ASSERT(req_size >= sizeof(ADV_SCSI_REQ_Q)); + + scsiq->scsiq_ptr = (ADV_SCSI_REQ_Q *) scsiq; + + /* + * The RISC list structure, which 'next_ready_loc' is a pointer + * to in microcode LRAM, has the format detailed in the comment + * header for this function. + * + * Write the ADV_SCSI_REQ_Q physical pointer to 'next_ready_loc' request. + */ + AdvWriteDWordLram(iop_base, next_ready_loc + RQL_PHYADDR, q_phy_addr); + + /* Write target_id to 'next_ready_loc' request. */ + AdvWriteByteLram(iop_base, next_ready_loc + RQL_TID, scsiq->target_id); + + /* + * Set the ASC_MC_HOST_NEXT_READY (0x128) microcode variable to + * the 'next_ready_loc' request forward pointer. + * + * Do this *before* changing the 'next_ready_loc' queue to QS_READY. + * After the state is changed to QS_READY 'RQL_FWD' will be changed + * by the microcode. + * + * NOTE: The temporary variable 'next_ready_loc_fwd' is required to + * prevent some compilers from optimizing out 'AdvReadByteLram()' if + * it were used as the 3rd argument to 'AdvWriteByteLram()'. + */ + AdvReadByteLram(iop_base, next_ready_loc + RQL_FWD, next_ready_loc_fwd); + AdvWriteByteLram(iop_base, ASC_MC_HOST_NEXT_READY, next_ready_loc_fwd); + + /* + * Change the state of 'next_ready_loc' request from QS_FREE to + * QS_READY which will cause the microcode to pick it up and + * execute it. + * + * Can't reference 'next_ready_loc' after changing the request + * state to QS_READY. The microcode now owns the request. + */ + AdvWriteByteLram(iop_base, next_ready_loc + RQL_STATE, ASC_MC_QS_READY); + + DvcLeaveCritical(last_int_level); + return ADV_SUCCESS; +} + +/* + * Inquiry Information Byte 7 Handling + * + * Handle SCSI Inquiry Command information for a device by setting + * microcode operating variables that affect WDTR, SDTR, and Tag + * Queuing. + */ +STATIC void +AdvInquiryHandling( + ADV_DVC_VAR *asc_dvc, + ADV_SCSI_REQ_Q *scsiq) +{ + AdvPortAddr iop_base; + uchar tid; + ASC_SCSI_INQUIRY *inq; + ushort tidmask; + ushort cfg_word; + + /* + * AdvInquiryHandling() requires up to INQUIRY information Byte 7 + * to be available. + * + * If less than 8 bytes of INQUIRY information were requested or less + * than 8 bytes were transferred, then return. cdb[4] is the request + * length and the ADV_SCSI_REQ_Q 'data_cnt' field is set by the + * microcode to the transfer residual count. + */ + if (scsiq->cdb[4] < 8 || (scsiq->cdb[4] - scsiq->data_cnt) < 8) + { + return; + } + + iop_base = asc_dvc->iop_base; + tid = scsiq->target_id; + inq = (ASC_SCSI_INQUIRY *) scsiq->vdata_addr; + + /* + * WDTR, SDTR, and Tag Queuing cannot be enabled for old devices. + */ + if (inq->byte3.rsp_data_fmt < 2 && inq->byte2.ansi_apr_ver < 2) + { + return; + } else + { + /* + * INQUIRY Byte 7 Handling + * + * Use a device's INQUIRY byte 7 to determine whether it + * supports WDTR, SDTR, and Tag Queuing. If the feature + * is enabled in the EEPROM and the device supports the + * feature, then enable it in the microcode. + */ + + tidmask = ADV_TID_TO_TIDMASK(tid); + + /* + * Wide Transfers + * + * If the EEPROM enabled WDTR for the device and the device + * supports wide bus (16 bit) transfers, then turn on the + * device's 'wdtr_able' bit and write the new value to the + * microcode. + */ + if ((asc_dvc->wdtr_able & tidmask) && inq->byte7.WBus16) + { + AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, cfg_word); + if ((cfg_word & tidmask) == 0) + { + cfg_word |= tidmask; + AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, cfg_word); + + /* + * Clear the microcode "WDTR negotiation" done indicator + * for the target to cause it to negotiate with the new + * setting set above. + */ + AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE, cfg_word); + cfg_word &= ~tidmask; + AdvWriteWordLram(iop_base, ASC_MC_WDTR_DONE, cfg_word); + } + } + + /* + * Synchronous Transfers + * + * If the EEPROM enabled SDTR for the device and the device + * supports synchronous transfers, then turn on the device's + * 'sdtr_able' bit. Write the new value to the microcode. + */ + if ((asc_dvc->sdtr_able & tidmask) && inq->byte7.Sync) + { + AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, cfg_word); + if ((cfg_word & tidmask) == 0) + { + cfg_word |= tidmask; + AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, cfg_word); + + /* + * Clear the microcode "SDTR negotiation" done indicator + * for the target to cause it to negotiate with the new + * setting set above. + */ + AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word); + cfg_word &= ~tidmask; + AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word); + } + } + + /* + * If the EEPROM enabled Tag Queuing for device and the + * device supports Tag Queuing, then turn on the device's + * 'tagqng_enable' bit in the microcode and set the microcode + * maximum command count to the ADV_DVC_VAR 'max_dvc_qng' + * value. + * + * Tag Queuing is disabled for the BIOS which runs in polled + * mode and would see no benefit from Tag Queuing. Also by + * disabling Tag Queuing in the BIOS devices with Tag Queuing + * bugs will at least work with the BIOS. + */ + if ((asc_dvc->tagqng_able & tidmask) && inq->byte7.CmdQue) + { + AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, cfg_word); + cfg_word |= tidmask; + AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, cfg_word); + AdvWriteByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid, + asc_dvc->max_dvc_qng); + } + } } diff -u --recursive --new-file v2.1.80/linux/drivers/scsi/advansys.h linux/drivers/scsi/advansys.h --- v2.1.80/linux/drivers/scsi/advansys.h Tue Jan 20 16:52:42 1998 +++ linux/drivers/scsi/advansys.h Fri Jan 23 17:35:23 1998 @@ -1,9 +1,9 @@ -/* $Id: advansys.h,v 1.6 1997/05/30 19:25:12 davem Exp $ */ +/* $Id: advansys.h,v 1.17 1998/01/08 21:23:49 bobf Exp bobf $ */ /* * advansys.h - Linux Host Driver for AdvanSys SCSI Adapters * - * Copyright (c) 1995-1997 Advanced System Products, Inc. + * Copyright (c) 1995-1998 Advanced System Products, Inc. * All Rights Reserved. * * Redistribution and use in source and binary forms, with or without @@ -18,7 +18,7 @@ * ftp://ftp.advansys.com/pub/linux * * Please send questions, comments, bug reports to: - * bobf@advansys.com (Bob Frey) + * bobf@advansys.com (Bob Frey) */ #ifndef _ADVANSYS_H @@ -40,10 +40,18 @@ int advansys_command(Scsi_Cmnd *); int advansys_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *)); int advansys_abort(Scsi_Cmnd *); +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,89) +int advansys_reset(Scsi_Cmnd *); +#else /* version >= v1.3.89 */ int advansys_reset(Scsi_Cmnd *, unsigned int); +#endif /* version >= v1.3.89 */ +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0) +int advansys_biosparam(Disk *, int, int[]); +#else /* version >= v1.3.0 */ int advansys_biosparam(Disk *, kdev_t, int[]); extern struct proc_dir_entry proc_scsi_advansys; int advansys_proc_info(char *, char **, off_t, int, int, int); +#endif /* version >= v1.3.0 */ /* init/main.c setup function */ void advansys_setup(char *, int *); @@ -51,31 +59,116 @@ /* * AdvanSys Host Driver Scsi_Host_Template (struct SHT) from hosts.h. */ +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0) #define ADVANSYS { \ - proc_dir: &proc_scsi_advansys, \ - proc_info: advansys_proc_info, \ - name: "advansys", \ - detect: advansys_detect, \ - release: advansys_release, \ - info: advansys_info, \ - command: advansys_command, \ - queuecommand: advansys_queuecommand, \ - abort: advansys_abort, \ - reset: advansys_reset, \ - bios_param: advansys_biosparam, \ - /* \ - * Because the driver may control an ISA adapter 'unchecked_isa_dma' \ - * must be set. The flag will be cleared in advansys_detect for non-ISA \ - * adapters. Refer to the comment in scsi_module.c for more information. \ - */ \ - unchecked_isa_dma: 1, \ - /* \ - * All adapters controlled by this driver are capable of large \ - * 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. \ - */ \ - use_clustering: ENABLE_CLUSTERING, \ + NULL, /* struct SHT *next */ \ + NULL, /* int *usage_count */ \ + "advansys", /* char *name */ \ + advansys_detect, /* int (*detect)(struct SHT *) */ \ + advansys_release, /* int (*release)(struct Scsi_Host *) */ \ + advansys_info, /* const char *(*info)(struct Scsi_Host *) */ \ + advansys_command, /* int (*command)(Scsi_Cmnd *) */ \ + advansys_queuecommand, \ + /* int (*queuecommand)(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)) */ \ + advansys_abort, /* int (*abort)(Scsi_Cmnd *) */ \ + advansys_reset, /* int (*reset)(Scsi_Cmnd *) */ \ + NULL, /* int (*slave_attach)(int, int) */ \ + advansys_biosparam, /* int (* bios_param)(Disk *, int, int []) */ \ + /* \ + * The following fields are set per adapter in advansys_detect(). \ + */ \ + 0, /* int can_queue */ \ + 0, /* int this_id */ \ + 0, /* short unsigned int sg_tablesize */ \ + 0, /* short cmd_per_lun */ \ + 0, /* unsigned char present */ \ + /* \ + * Because the driver may control an ISA adapter 'unchecked_isa_dma' \ + * must be set. The flag will be cleared in advansys_detect for non-ISA \ + * adapters. Refer to the comment in scsi_module.c for more information. \ + */ \ + 1, /* unsigned unchecked_isa_dma:1 */ \ + /* \ + * All adapters controlled by this driver are capable of large \ + * 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. \ + */ \ + ENABLE_CLUSTERING, /* unsigned use_clustering:1 */ \ } +#elif LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,75) +#define ADVANSYS { \ + NULL, /* struct SHT *next */ \ + NULL, \ + /* version < v2.1.23 long *usage_count */ \ + /* version >= v2.1.23 struct module * */ \ + &proc_scsi_advansys, /* struct proc_dir_entry *proc_dir */ \ + advansys_proc_info, \ + /* int (*proc_info)(char *, char **, off_t, int, int, int) */ \ + "advansys", /* const char *name */ \ + advansys_detect, /* int (*detect)(struct SHT *) */ \ + advansys_release, /* int (*release)(struct Scsi_Host *) */ \ + advansys_info, /* const char *(*info)(struct Scsi_Host *) */ \ + advansys_command, /* int (*command)(Scsi_Cmnd *) */ \ + advansys_queuecommand, \ + /* int (*queuecommand)(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)) */ \ + advansys_abort, /* int (*abort)(Scsi_Cmnd *) */ \ + advansys_reset, \ + /* version < v1.3.89 int (*reset)(Scsi_Cmnd *) */ \ + /* version >= v1.3.89 int (*reset)(Scsi_Cmnd *, unsigned int) */ \ + NULL, /* int (*slave_attach)(int, int) */ \ + advansys_biosparam, /* int (* bios_param)(Disk *, kdev_t, int []) */ \ + /* \ + * The following fields are set per adapter in advansys_detect(). \ + */ \ + 0, /* int can_queue */ \ + 0, /* int this_id */ \ + 0, /* short unsigned int sg_tablesize */ \ + 0, /* short cmd_per_lun */ \ + 0, /* unsigned char present */ \ + /* \ + * Because the driver may control an ISA adapter 'unchecked_isa_dma' \ + * must be set. The flag will be cleared in advansys_detect for non-ISA \ + * adapters. Refer to the comment in scsi_module.c for more information. \ + */ \ + 1, /* unsigned unchecked_isa_dma:1 */ \ + /* \ + * All adapters controlled by this driver are capable of large \ + * 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. \ + */ \ + ENABLE_CLUSTERING, /* unsigned use_clustering:1 */ \ +} +#else /* version >= v2.1.75 */ +#define ADVANSYS { \ + proc_dir: &proc_scsi_advansys, \ + proc_info: advansys_proc_info, \ + name: "advansys", \ + detect: advansys_detect, \ + release: advansys_release, \ + info: advansys_info, \ + command: advansys_command, \ + queuecommand: advansys_queuecommand, \ + abort: advansys_abort, \ + reset: advansys_reset, \ + bios_param: advansys_biosparam, \ + /* \ + * Because the driver may control an ISA adapter 'unchecked_isa_dma' \ + * must be set. The flag will be cleared in advansys_detect for non-ISA \ + * adapters. Refer to the comment in scsi_module.c for more information. \ + */ \ + unchecked_isa_dma: 1, \ + /* \ + * All adapters controlled by this driver are capable of large \ + * 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. \ + */ \ + use_clustering: ENABLE_CLUSTERING, \ +} +#endif /* version >= v2.1.75 */ #endif /* _ADVANSYS_H */ diff -u --recursive --new-file v2.1.80/linux/drivers/scsi/pci2000.h linux/drivers/scsi/pci2000.h --- v2.1.80/linux/drivers/scsi/pci2000.h Sun Dec 21 17:04:49 1997 +++ linux/drivers/scsi/pci2000.h Fri Jan 23 17:38:04 1998 @@ -209,7 +209,7 @@ queuecommand: Pci2000_QueueCommand, \ abort: Pci2000_Abort, \ reset: Pci2000_Reset, \ - biosparam: Pci2000_BiosParam, \ + bios_param: Pci2000_BiosParam, \ can_queue: 16, \ this_id: -1, \ sg_tablesize: 16, \ diff -u --recursive --new-file v2.1.80/linux/drivers/scsi/pci2220i.h linux/drivers/scsi/pci2220i.h --- v2.1.80/linux/drivers/scsi/pci2220i.h Sun Dec 21 17:04:49 1997 +++ linux/drivers/scsi/pci2220i.h Fri Jan 23 17:38:04 1998 @@ -328,7 +328,7 @@ queuecommand: Pci2220i_QueueCommand, \ abort: Pci2220i_Abort, \ reset: Pci2220i_Reset, \ - biosparam: Pci2220i_BiosParam, \ + bios_param: Pci2220i_BiosParam, \ can_queue: 1, \ this_id: -1, \ sg_tablesize: SG_NONE, \ diff -u --recursive --new-file v2.1.80/linux/drivers/scsi/pluto.c linux/drivers/scsi/pluto.c --- v2.1.80/linux/drivers/scsi/pluto.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/scsi/pluto.c Wed Jan 21 17:04:39 1998 @@ -0,0 +1,313 @@ +/* pluto.c: SparcSTORAGE Array SCSI host adapter driver. + * + * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "scsi.h" +#include "hosts.h" +#include "../fc4/fcp_scsi.h" +#include "pluto.h" + +#include + +/* #define PLUTO_DEBUG */ + +#define pluto_printk printk ("PLUTO %s: ", fc->name); printk + +#ifdef PLUTO_DEBUG +#define PLD(x) pluto_printk x; +#define PLND(x) printk ("PLUTO: "); printk x; +#else +#define PLD(x) +#define PLND(x) +#endif + +struct proc_dir_entry proc_scsi_pluto = { + PROC_SCSI_PLUTO, 5, "pluto", + S_IFDIR | S_IRUGO | S_IXUGO, 2 +}; + +static struct ctrl_inquiry { + struct Scsi_Host host; + struct pluto pluto; + Scsi_Cmnd cmd; + char inquiry[256]; + fc_channel *fc; +} *fcs __initdata; +static int fcscount __initdata; +static atomic_t fcss __initdata; +static struct timer_list fc_timer __initdata = { 0 }; +struct semaphore fc_sem __initdata = MUTEX_LOCKED; + +static int pluto_encode_addr(Scsi_Cmnd *SCpnt, u16 *addr); + +__initfunc(static void pluto_detect_timeout(unsigned long data)) +{ + PLND(("Timeout\n")) + up(&fc_sem); +} + +__initfunc(static void pluto_detect_done(Scsi_Cmnd *SCpnt)) +{ + /* Do nothing */ +} + +__initfunc(static void pluto_detect_scsi_done(Scsi_Cmnd *SCpnt)) +{ + SCpnt->request.rq_status = RQ_SCSI_DONE; + PLND(("Detect done %08lx\n", (long)SCpnt)) + if (atomic_dec_and_test (&fcss)) + up(&fc_sem); +} + +static void pluto_select_queue_depths(struct Scsi_Host *host, Scsi_Device *devlist) +{ + Scsi_Device *device; + + for (device = devlist; device; device = device->next) { + if (device->host != host) continue; + if (device->tagged_supported) + device->queue_depth = /* 254 */ 8; + else + device->queue_depth = 2; + } +} + +/* Detect all SSAs attached to the machine. + To be fast, do it on all online FC channels at the same time. */ +__initfunc(int pluto_detect(Scsi_Host_Template *tpnt)) +{ + int i, retry, nplutos; + fc_channel *fc; + Scsi_Device dev; + + tpnt->proc_dir = &proc_scsi_pluto; + fcscount = 0; + for_each_online_fc_channel(fc) + fcscount++; + PLND(("%d channels online\n", fcscount)) + if (!fcscount) + return 0; + fcs = (struct ctrl_inquiry *) scsi_init_malloc (sizeof (struct ctrl_inquiry) * fcscount, GFP_DMA); + if (!fcs) { + printk ("PLUTO: Not enough memory to probe\n"); + return 0; + } + + memset (fcs, 0, sizeof (struct ctrl_inquiry) * fcscount); + memset (&dev, 0, sizeof(dev)); + atomic_set (&fcss, fcscount); + fc_timer.function = pluto_detect_timeout; + + i = 0; + for_each_online_fc_channel(fc) { + Scsi_Cmnd *SCpnt; + struct Scsi_Host *host; + struct pluto *pluto; + + if (i == fcscount) break; + + PLD(("trying to find SSA\n")) + + /* If this is already registered to some other SCSI host, then it cannot be pluto */ + if (fc->scsi_name[0]) continue; + memcpy (fc->scsi_name, "SSA", 4); + + fcs[i].fc = fc; + + fc->can_queue = PLUTO_CAN_QUEUE; + fc->rsp_size = 64; + fc->encode_addr = pluto_encode_addr; + + fc->fcp_register(fc, TYPE_SCSI_FCP, 0); + + SCpnt = &(fcs[i].cmd); + host = &(fcs[i].host); + pluto = (struct pluto *)host->hostdata; + + pluto->fc = fc; + + SCpnt->host = host; + SCpnt->cmnd[0] = INQUIRY; + SCpnt->cmnd[4] = 255; + + /* FC layer requires this, so that SCpnt->device->tagged_supported is initially 0 */ + SCpnt->device = &dev; + + SCpnt->cmd_len = COMMAND_SIZE(INQUIRY); + + SCpnt->request.rq_status = RQ_SCSI_BUSY; + + SCpnt->done = pluto_detect_done; + SCpnt->bufflen = 256; + SCpnt->buffer = fcs[i].inquiry; + SCpnt->request_bufflen = 256; + SCpnt->request_buffer = fcs[i].inquiry; + PLD(("set up %d %08lx\n", i, (long)SCpnt)) + i++; + } + + for (retry = 0; retry < 5; retry++) { + for (i = 0; i < fcscount; i++) { + if (!fcs[i].fc) break; + if (fcs[i].cmd.request.rq_status != RQ_SCSI_DONE) { + disable_irq(fcs[i].fc->irq); + PLND(("queuecommand %d %d\n", retry, i)) + fcp_scsi_queuecommand (&(fcs[i].cmd), + pluto_detect_scsi_done); + enable_irq(fcs[i].fc->irq); + } + } + + fc_timer.expires = jiffies + 10 * HZ; + add_timer(&fc_timer); + + down(&fc_sem); + PLND(("Woken up\n")) + if (!atomic_read(&fcss)) + break; /* All fc channels have answered us */ + } + del_timer(&fc_timer); + + PLND(("Finished search\n")) + for (i = 0, nplutos = 0; i < fcscount; i++) { + Scsi_Cmnd *SCpnt; + + if (!(fc = fcs[i].fc)) break; + + SCpnt = &(fcs[i].cmd); + + /* Let FC mid-level free allocated resources */ + SCpnt->done (SCpnt); + + if (!SCpnt->result) { + struct pluto_inquiry *inq; + struct pluto *pluto; + struct Scsi_Host *host; + + inq = (struct pluto_inquiry *)fcs[i].inquiry; + + if ((inq->dtype & 0x1f) == TYPE_PROCESSOR && + !strncmp (inq->vendor_id, "SUN", 3) && + !strncmp (inq->product_id, "SSA", 3)) { + char *p; + long *ages; + + ages = kmalloc (((inq->channels + 1) * inq->targets) * sizeof(long), GFP_KERNEL); + if (!ages) continue; + + host = scsi_register (tpnt, sizeof (struct pluto)); + if (!host) panic ("Cannot register PLUTO host\n"); + + nplutos++; + + pluto = (struct pluto *)host->hostdata; + + host->max_id = inq->targets; + host->max_channel = inq->channels; + host->irq = fc->irq; + + host->select_queue_depths = pluto_select_queue_depths; + + fc->channels = inq->channels + 1; + fc->targets = inq->targets; + fc->ages = ages; + memset (ages, 0, ((inq->channels + 1) * inq->targets) * sizeof(long)); + + pluto->fc = fc; + memcpy (pluto->rev_str, inq->revision, 4); + pluto->rev_str[4] = 0; + p = strchr (pluto->rev_str, ' '); + if (p) *p = 0; + memcpy (pluto->fw_rev_str, inq->fw_revision, 4); + pluto->fw_rev_str[4] = 0; + p = strchr (pluto->fw_rev_str, ' '); + if (p) *p = 0; + memcpy (pluto->serial_str, inq->serial, 12); + pluto->serial_str[12] = 0; + p = strchr (pluto->serial_str, ' '); + if (p) *p = 0; + + PLD(("Found SSA rev %s fw rev %s serial %s %dx%d\n", pluto->rev_str, pluto->fw_rev_str, pluto->serial_str, host->max_channel, host->max_id)) + } else + fc->fcp_register(fc, TYPE_SCSI_FCP, 1); + } else + fc->fcp_register(fc, TYPE_SCSI_FCP, 1); + } + scsi_init_free((char *)fcs, sizeof (struct ctrl_inquiry) * fcscount); + if (nplutos) + printk ("PLUTO: Total of %d SparcSTORAGE Arrays found\n", nplutos); + return nplutos; +} + +int pluto_release(struct Scsi_Host *host) +{ + struct pluto *pluto = (struct pluto *)host->hostdata; + fc_channel *fc = pluto->fc; + + fc->fcp_register(fc, TYPE_SCSI_FCP, 1); + kfree (fc->ages); + return 0; +} + +const char *pluto_info(struct Scsi_Host *host) +{ + static char buf[80]; + struct pluto *pluto = (struct pluto *) host->hostdata; + + sprintf(buf, "SUN SparcSTORAGE Array %s fw %s serial %s %dx%d on %s", + pluto->rev_str, pluto->fw_rev_str, pluto->serial_str, + host->max_channel, host->max_id, pluto->fc->name); + return buf; +} + +/* SSA uses this FC4S addressing: + switch (addr[0]) + { + case 0: CONTROLLER - All of addr[1]..addr[3] has to be 0 + case 1: SINGLE DISK - addr[1] channel, addr[2] id, addr[3] 0 + case 2: DISK GROUP - ??? + } + + So that SCSI mid-layer can access to these, we reserve + channel 0 id 0 lun 0 for CONTROLLER + and channels 1 .. max_channel are normal single disks. + */ +static int pluto_encode_addr(Scsi_Cmnd *SCpnt, u16 *addr) +{ + PLND(("encode addr %d %d %d\n", SCpnt->channel, SCpnt->target, SCpnt->cmnd[1] & 0xe0)) + /* We don't support LUNs */ + if (SCpnt->cmnd[1] & 0xe0) return -EINVAL; + if (!SCpnt->channel) { + if (SCpnt->target) return -EINVAL; + memset (addr, 0, 4 * sizeof(u16)); + } else { + addr[0] = 1; + addr[1] = SCpnt->channel - 1; + addr[2] = SCpnt->target; + addr[3] = 0; + } + PLND(("trying %04x%04x%04x%04x\n", addr[0], addr[1], addr[2], addr[3])) + return 0; +} + +#ifdef MODULE + +Scsi_Host_Template driver_template = PLUTO; + +#include "scsi_module.c" + +EXPORT_NO_SYMBOLS; +#endif /* MODULE */ diff -u --recursive --new-file v2.1.80/linux/drivers/scsi/pluto.h linux/drivers/scsi/pluto.h --- v2.1.80/linux/drivers/scsi/pluto.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/scsi/pluto.h Wed Jan 21 17:04:39 1998 @@ -0,0 +1,59 @@ +/* pluto.h: SparcSTORAGE Array SCSI host adapter driver definitions. + * + * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + */ + +#ifndef _PLUTO_H +#define _PLUTO_H + +#include "../fc4/fcp_scsi.h" + +struct pluto { + /* This must be first */ + fc_channel *fc; + char rev_str[5]; + char fw_rev_str[5]; + char serial_str[13]; +}; + +struct pluto_inquiry { + u8 dtype; + u8 removable:1, qualifier:7; + u8 iso:2, ecma:3, ansi:3; + u8 aenc:1, trmiop:1, :2, rdf:4; + u8 len; + u8 xxx1; + u8 xxx2; + u8 reladdr:1, wbus32:1, wbus16:1, sync:1, linked:1, :1, cmdque:1, softreset:1; + u8 vendor_id[8]; + u8 product_id[16]; + u8 revision[4]; + u8 fw_revision[4]; + u8 serial[12]; + u8 xxx3[2]; + u8 channels; + u8 targets; +}; + +/* This is the max number of outstanding SCSI commands per pluto */ +#define PLUTO_CAN_QUEUE 254 + +int pluto_detect(Scsi_Host_Template *); +int pluto_release(struct Scsi_Host *); +const char * pluto_info(struct Scsi_Host *); + +#define PLUTO { \ + detect: pluto_detect, \ + release: pluto_release, \ + info: pluto_info, \ + queuecommand: fcp_scsi_queuecommand, \ + abort: fcp_scsi_abort, \ + reset: fcp_scsi_reset, \ + can_queue: PLUTO_CAN_QUEUE, \ + this_id: -1, \ + sg_tablesize: 1, \ + cmd_per_lun: 1, \ + use_clustering: ENABLE_CLUSTERING \ +} + +#endif /* !(_PLUTO_H) */ diff -u --recursive --new-file v2.1.80/linux/drivers/scsi/psi240i.h linux/drivers/scsi/psi240i.h --- v2.1.80/linux/drivers/scsi/psi240i.h Sun Dec 21 17:04:49 1997 +++ linux/drivers/scsi/psi240i.h Fri Jan 23 17:38:04 1998 @@ -327,7 +327,7 @@ queuecommand: Psi240i_QueueCommand, \ abort: Psi240i_Abort, \ reset: Psi240i_Reset, \ - biosparam: Psi240i_BiosParam, \ + bios_param: Psi240i_BiosParam, \ can_queue: 1, \ this_id: -1, \ sg_tablesize: SG_NONE, \ diff -u --recursive --new-file v2.1.80/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c --- v2.1.80/linux/drivers/scsi/scsi.c Thu Jan 15 21:11:01 1998 +++ linux/drivers/scsi/scsi.c Fri Jan 23 17:38:04 1998 @@ -200,16 +200,6 @@ static void scsi_dump_status(int level); -/* - * This is the number of clock ticks we should wait before we time out - * and abort the command. This is for where the scsi.c module generates - * the command, not where it originates from a higher level, in which - * case the timeout is specified there. - * - */ - - - struct dev_info{ const char * vendor; const char * model; @@ -3208,7 +3198,7 @@ printk(" %d %d %d : %d %p\n", shpnt->host_failed, shpnt->host_busy, - shpnt->host_active, + atomic_read(&shpnt->host_active), shpnt->host_blocked, shpnt->pending_commands); diff -u --recursive --new-file v2.1.80/linux/drivers/scsi/t128.c linux/drivers/scsi/t128.c --- v2.1.80/linux/drivers/scsi/t128.c Sun Jan 4 10:55:09 1998 +++ linux/drivers/scsi/t128.c Fri Jan 23 17:38:04 1998 @@ -141,11 +141,11 @@ #define NO_OVERRIDES (sizeof(overrides) / sizeof(struct override)) static struct base { - unsigned char *address; + unsigned int address; int noauto; } bases[] __initdata = { - {(unsigned char *) 0xcc000, 0}, {(unsigned char *) 0xc8000, 0}, - {(unsigned char *) 0xdc000, 0}, {(unsigned char *) 0xd8000, 0}}; + { 0xcc000, 0}, { 0xc8000, 0}, { 0xdc000, 0}, { 0xd8000, 0} +}; #define NO_BASES (sizeof (bases) / sizeof (struct base)) @@ -178,7 +178,7 @@ overrides[commandline_current].address = (unsigned char *) ints[1]; overrides[commandline_current].irq = ints[2]; for (i = 0; i < NO_BASES; ++i) - if (bases[i].address == (unsigned char *) ints[1]) { + if (bases[i].address == ints[1]) { bases[i].noauto = 1; break; } @@ -216,7 +216,7 @@ else for (; !base && (current_base < NO_BASES); ++current_base) { #if (TDEBUG & TDEBUG_INIT) - printk("scsi-t128 : probing address %08x\n", (unsigned int) bases[current_base].address); + printk("scsi-t128 : probing address %08x\n", bases[current_base].address); #endif for (sig = 0; sig < NO_SIGNATURES; ++sig) if (!bases[current_base].noauto && @@ -224,7 +224,7 @@ signatures[sig].offset, signatures[sig].string, strlen(signatures[sig].string))) { - base = bases[current_base].address; + base = (unsigned char *) bases[current_base].address; #if (TDEBUG & TDEBUG_INIT) printk("scsi-t128 : detected board.\n"); #endif diff -u --recursive --new-file v2.1.80/linux/drivers/sound/audio.c linux/drivers/sound/audio.c --- v2.1.80/linux/drivers/sound/audio.c Tue Jan 20 16:44:57 1998 +++ linux/drivers/sound/audio.c Fri Jan 23 17:38:04 1998 @@ -350,7 +350,7 @@ int audio_ioctl(int dev, struct fileinfo *file_must_not_be_used, unsigned int cmd, caddr_t arg) { - int val, info, count; + int val = 0, info, count; unsigned long flags; struct dma_buffparms *dmap; diff -u --recursive --new-file v2.1.80/linux/drivers/sound/dev_table.c linux/drivers/sound/dev_table.c --- v2.1.80/linux/drivers/sound/dev_table.c Tue Jan 20 16:44:57 1998 +++ linux/drivers/sound/dev_table.c Fri Jan 23 17:38:04 1998 @@ -36,9 +36,9 @@ static void start_services(void) { +#ifdef FIXME int soundcards_installed; -#ifdef FIXME if (!(soundcards_installed = sndtable_get_cardcount())) return; /* No cards detected */ #endif diff -u --recursive --new-file v2.1.80/linux/drivers/sound/gus_card.c linux/drivers/sound/gus_card.c --- v2.1.80/linux/drivers/sound/gus_card.c Sun Dec 21 17:41:24 1997 +++ linux/drivers/sound/gus_card.c Thu Jan 22 14:46:41 1998 @@ -28,8 +28,7 @@ extern int have_gus_max; int gus_pnp_flag = 0; -void -attach_gus_card(struct address_info *hw_config) +void attach_gus_card(struct address_info *hw_config) { snd_set_irq_handler(hw_config->irq, gusintr, "Gravis Ultrasound", hw_config->osp); @@ -48,8 +47,7 @@ #endif } -int -probe_gus(struct address_info *hw_config) +int probe_gus(struct address_info *hw_config) { int irq; int io_addr; @@ -63,13 +61,13 @@ if (irq != 3 && irq != 5 && irq != 7 && irq != 9 && irq != 11 && irq != 12 && irq != 15) { - printk("GUS: Unsupported IRQ %d\n", irq); + printk(KERN_ERR "GUS: Unsupported IRQ %d\n", irq); return 0; } if (check_region(hw_config->io_base, 16)) - printk("GUS: I/O range conflict (1)\n"); + printk(KERN_ERR "GUS: I/O range conflict (1)\n"); else if (check_region(hw_config->io_base + 0x100, 16)) - printk("GUS: I/O range conflict (2)\n"); + printk(KERN_ERR "GUS: I/O range conflict (2)\n"); else if (gus_wave_detect(hw_config->io_base)) return 1; @@ -95,8 +93,7 @@ return 0; } -void -unload_gus(struct address_info *hw_config) +void unload_gus(struct address_info *hw_config) { DDB(printk("unload_gus(%x)\n", hw_config->io_base)); @@ -112,8 +109,7 @@ sound_free_dma(hw_config->dma2); } -void -gusintr(int irq, void *dev_id, struct pt_regs *dummy) +void gusintr(int irq, void *dev_id, struct pt_regs *dummy) { unsigned char src; extern int gus_timer_enabled; @@ -126,56 +122,50 @@ #endif while (1) - { - if (!(src = inb(u_IrqStatus))) - return; - - if (src & DMA_TC_IRQ) - { - guswave_dma_irq(); - } - if (src & (MIDI_TX_IRQ | MIDI_RX_IRQ)) - { + { + if (!(src = inb(u_IrqStatus))) + return; + + if (src & DMA_TC_IRQ) + { + guswave_dma_irq(); + } + if (src & (MIDI_TX_IRQ | MIDI_RX_IRQ)) + { #if defined(CONFIG_MIDI) - gus_midi_interrupt(0); + gus_midi_interrupt(0); #endif - } - if (src & (GF1_TIMER1_IRQ | GF1_TIMER2_IRQ)) - { + } + if (src & (GF1_TIMER1_IRQ | GF1_TIMER2_IRQ)) + { #if defined(CONFIG_SEQUENCER) || defined(CONFIG_SEQUENCER_MODULE) - if (gus_timer_enabled) - { - sound_timer_interrupt(); - } - gus_write8(0x45, 0); /* Ack IRQ */ - gus_timer_command(4, 0x80); /* Reset IRQ flags */ - + if (gus_timer_enabled) + sound_timer_interrupt(); + gus_write8(0x45, 0); /* Ack IRQ */ + gus_timer_command(4, 0x80); /* Reset IRQ flags */ #else - gus_write8(0x45, 0); /* Stop timers */ + gus_write8(0x45, 0); /* Stop timers */ #endif - } - if (src & (WAVETABLE_IRQ | ENVELOPE_IRQ)) - { - gus_voice_irq(); - } - } + } + if (src & (WAVETABLE_IRQ | ENVELOPE_IRQ)) + gus_voice_irq(); + } } #endif /* - * Some extra code for the 16 bit sampling option + * Some extra code for the 16 bit sampling option */ + #ifdef CONFIG_GUS16 -int -probe_gus_db16(struct address_info *hw_config) +int probe_gus_db16(struct address_info *hw_config) { return ad1848_detect(hw_config->io_base, NULL, hw_config->osp); } -void -attach_gus_db16(struct address_info *hw_config) +void attach_gus_db16(struct address_info *hw_config) { #if defined(CONFIG_GUSHW) || defined(MODULE) gus_pcm_volume = 100; @@ -189,8 +179,7 @@ hw_config->osp); } -void -unload_gus_db16(struct address_info *hw_config) +void unload_gus_db16(struct address_info *hw_config) { ad1848_unload(hw_config->io_base, @@ -226,16 +215,15 @@ MODULE_PARM(gus16, "i"); MODULE_PARM(db16, "i"); -int -init_module(void) +int init_module(void) { - printk("Gravis Ultrasound audio driver Copyright (C) by Hannu Savolainen 1993-1996\n"); + printk(KERN_INFO "Gravis Ultrasound audio driver Copyright (C) by Hannu Savolainen 1993-1996\n"); if (io == -1 || dma == -1 || irq == -1) - { - printk("I/O, IRQ, and DMA are mandatory\n"); - return -EINVAL; - } + { + printk(KERN_ERR "I/O, IRQ, and DMA are mandatory\n"); + return -EINVAL; + } config.io_base = io; config.irq = irq; config.dma = dma; @@ -244,10 +232,10 @@ #if defined(CONFIG_GUS16) if (probe_gus_db16(&config) && gus16) - { - attach_gus_db16(&config); - db16 = 1; - } + { + attach_gus_db16(&config); + db16 = 1; + } #endif if (probe_gus(&config) == 0) return -ENODEV; @@ -256,8 +244,7 @@ return 0; } -void -cleanup_module(void) +void cleanup_module(void) { #if defined(CONFIG_GUS16) if (db16) diff -u --recursive --new-file v2.1.80/linux/drivers/sound/gus_midi.c linux/drivers/sound/gus_midi.c --- v2.1.80/linux/drivers/sound/gus_midi.c Tue Dec 30 10:59:17 1997 +++ linux/drivers/sound/gus_midi.c Thu Jan 22 14:46:41 1998 @@ -33,24 +33,18 @@ extern int gus_base, gus_irq, gus_dma; extern int *gus_osp; -static int -GUS_MIDI_STATUS(void) +static int GUS_MIDI_STATUS(void) { return inb(u_MidiStatus); } -static int -gus_midi_open(int dev, int mode, - void (*input) (int dev, unsigned char data), - void (*output) (int dev) -) +static int gus_midi_open(int dev, int mode, void (*input) (int dev, unsigned char data), void (*output) (int dev)) { - if (midi_busy) - { - printk("GUS: Midi busy\n"); - return -EBUSY; - } + { +/* printk("GUS: Midi busy\n");*/ + return -EBUSY; + } outb((MIDI_RESET), u_MidiControl); gus_delay(); @@ -59,10 +53,10 @@ if (mode == OPEN_READ || mode == OPEN_READWRITE) if (!gus_pnp_flag) - { - gus_midi_control |= MIDI_ENABLE_RCV; - input_opened = 1; - } + { + gus_midi_control |= MIDI_ENABLE_RCV; + input_opened = 1; + } outb((gus_midi_control), u_MidiControl); /* Enable */ midi_busy = 1; @@ -72,8 +66,7 @@ return 0; } -static int -dump_to_midi(unsigned char midi_byte) +static int dump_to_midi(unsigned char midi_byte) { unsigned long flags; int ok = 0; @@ -84,24 +77,24 @@ cli(); if (GUS_MIDI_STATUS() & MIDI_XMIT_EMPTY) - { - ok = 1; - outb((midi_byte), u_MidiData); - } else - { - /* - * Enable Midi xmit interrupts (again) - */ - gus_midi_control |= MIDI_ENABLE_XMIT; - outb((gus_midi_control), u_MidiControl); - } + { + ok = 1; + outb((midi_byte), u_MidiData); + } + else + { + /* + * Enable Midi xmit interrupts (again) + */ + gus_midi_control |= MIDI_ENABLE_XMIT; + outb((gus_midi_control), u_MidiControl); + } restore_flags(flags); return ok; } -static void -gus_midi_close(int dev) +static void gus_midi_close(int dev) { /* * Reset FIFO pointers, disable intrs @@ -111,10 +104,8 @@ midi_busy = 0; } -static int -gus_midi_out(int dev, unsigned char midi_byte) +static int gus_midi_out(int dev, unsigned char midi_byte) { - unsigned long flags; /* @@ -125,15 +116,14 @@ cli(); while (qlen && dump_to_midi(tmp_queue[qhead])) - { - qlen--; - qhead++; - } - + { + qlen--; + qhead++; + } restore_flags(flags); /* - * Output the byte if the local queue is empty. + * Output the byte if the local queue is empty. */ if (!qlen) @@ -143,14 +133,13 @@ */ /* - * Put to the local queue + * Put to the local queue */ if (qlen >= 256) return 0; /* * Local queue full */ - save_flags(flags); cli(); @@ -159,29 +148,24 @@ qtail++; restore_flags(flags); - return 1; } -static int -gus_midi_start_read(int dev) +static int gus_midi_start_read(int dev) { return 0; } -static int -gus_midi_end_read(int dev) +static int gus_midi_end_read(int dev) { return 0; } -static void -gus_midi_kick(int dev) +static void gus_midi_kick(int dev) { } -static int -gus_midi_buffer_status(int dev) +static int gus_midi_buffer_status(int dev) { unsigned long flags; @@ -192,12 +176,11 @@ cli(); if (qlen && dump_to_midi(tmp_queue[qhead])) - { - qlen--; - qhead++; - } + { + qlen--; + qhead++; + } restore_flags(flags); - return (qlen > 0) | !(GUS_MIDI_STATUS() & MIDI_XMIT_EMPTY); } @@ -207,7 +190,9 @@ static struct midi_operations gus_midi_operations = { - {"Gravis UltraSound Midi", 0, 0, SNDCARD_GUS}, + { + "Gravis UltraSound Midi", 0, 0, SNDCARD_GUS + }, &std_midi_synth, {0}, gus_midi_open, @@ -224,16 +209,15 @@ NULL }; -void -gus_midi_init(struct address_info *hw_config) +void gus_midi_init(struct address_info *hw_config) { - int dev = sound_alloc_mididev(); + int dev = sound_alloc_mididev(); if (dev == -1) - { - printk(KERN_INFO "gus_midi: Too many midi devices detected\n"); - return; - } + { + printk(KERN_INFO "gus_midi: Too many midi devices detected\n"); + return; + } outb((MIDI_RESET), u_MidiControl); std_midi_synth.midi_dev = my_dev = dev; @@ -243,44 +227,41 @@ return; } -void -gus_midi_interrupt(int dummy) +void gus_midi_interrupt(int dummy) { volatile unsigned char stat, data; - unsigned long flags; - int timeout = 10; + unsigned long flags; + int timeout = 10; save_flags(flags); cli(); while (timeout-- > 0 && (stat = GUS_MIDI_STATUS()) & (MIDI_RCV_FULL | MIDI_XMIT_EMPTY)) - { - if (stat & MIDI_RCV_FULL) - { - data = inb(u_MidiData); - if (input_opened) - midi_input_intr(my_dev, data); - } - if (stat & MIDI_XMIT_EMPTY) - { - while (qlen && dump_to_midi(tmp_queue[qhead])) - { - qlen--; - qhead++; - } - - if (!qlen) - { - /* - * Disable Midi output interrupts, since no data in the buffer - */ - gus_midi_control &= ~MIDI_ENABLE_XMIT; - outb((gus_midi_control), u_MidiControl); - outb((gus_midi_control), u_MidiControl); - } - } - } - + { + if (stat & MIDI_RCV_FULL) + { + data = inb(u_MidiData); + if (input_opened) + midi_input_intr(my_dev, data); + } + if (stat & MIDI_XMIT_EMPTY) + { + while (qlen && dump_to_midi(tmp_queue[qhead])) + { + qlen--; + qhead++; + } + if (!qlen) + { + /* + * Disable Midi output interrupts, since no data in the buffer + */ + gus_midi_control &= ~MIDI_ENABLE_XMIT; + outb((gus_midi_control), u_MidiControl); + outb((gus_midi_control), u_MidiControl); + } + } + } restore_flags(flags); } diff -u --recursive --new-file v2.1.80/linux/drivers/sound/gus_vol.c linux/drivers/sound/gus_vol.c --- v2.1.80/linux/drivers/sound/gus_vol.c Sat Nov 29 10:33:20 1997 +++ linux/drivers/sound/gus_vol.c Thu Jan 22 14:46:41 1998 @@ -34,10 +34,10 @@ * we can give a big boost to very weak voices like nylon guitar and the * basses. The normal value is 64. Strings are assigned lower values. */ -unsigned short -gus_adagio_vol(int vel, int mainv, int xpn, int voicev) + +unsigned short gus_adagio_vol(int vel, int mainv, int xpn, int voicev) { - int i, m, n, x; + int i, m, n, x; /* @@ -50,6 +50,7 @@ /* * Boost expression by voice volume above neutral. */ + if (voicev > 65) xpn += voicev - 64; xpn += (voicev - 64) / 2; @@ -85,18 +86,22 @@ * Convert to GUS's logarithmic form with 4 bit exponent i and 8 bit * mantissa m. */ + n = x; i = 7; if (n < 128) - { + { while (i > 0 && n < (1 << i)) i--; - } else + } + else + { while (n > 255) - { + { n >>= 1; i++; - } + } + } /* * Mantissa is part of linear volume not expressed in exponent. (This is * not quite like real logs -- I wonder if it's right.) @@ -107,12 +112,12 @@ * Adjust mantissa to 8 bits. */ if (m > 0) - { - if (i > 8) - m >>= i - 8; - else if (i < 8) - m <<= 8 - i; - } + { + if (i > 8) + m >>= i - 8; + else if (i < 8) + m <<= 8 - i; + } return ((i << 8) + m); } @@ -122,10 +127,9 @@ * and the volume set by the mixer-device (default 60%). */ -unsigned short -gus_linear_vol(int vol, int mainvol) +unsigned short gus_linear_vol(int vol, int mainvol) { - int mixer_mainvol; + int mixer_mainvol; if (vol <= 0) vol = 0; @@ -146,7 +150,6 @@ #else mainvol = 127; #endif - return gus_linearvol[(((vol * mainvol) / 127) * mixer_mainvol) / 100]; } diff -u --recursive --new-file v2.1.80/linux/drivers/sound/gus_wave.c linux/drivers/sound/gus_wave.c --- v2.1.80/linux/drivers/sound/gus_wave.c Tue Jan 20 16:44:57 1998 +++ linux/drivers/sound/gus_wave.c Thu Jan 22 14:46:41 1998 @@ -32,42 +32,42 @@ #define NOT_SAMPLE 0xffff struct voice_info - { - unsigned long orig_freq; - unsigned long current_freq; - unsigned long mode; - int fixed_pitch; - int bender; - int bender_range; - int panning; - int midi_volume; - unsigned int initial_volume; - unsigned int current_volume; - int loop_irq_mode, loop_irq_parm; +{ + unsigned long orig_freq; + unsigned long current_freq; + unsigned long mode; + int fixed_pitch; + int bender; + int bender_range; + int panning; + int midi_volume; + unsigned int initial_volume; + unsigned int current_volume; + int loop_irq_mode, loop_irq_parm; #define LMODE_FINISH 1 #define LMODE_PCM 2 #define LMODE_PCM_STOP 3 - int volume_irq_mode, volume_irq_parm; + int volume_irq_mode, volume_irq_parm; #define VMODE_HALT 1 #define VMODE_ENVELOPE 2 #define VMODE_START_NOTE 3 - int env_phase; - unsigned char env_rate[6]; - unsigned char env_offset[6]; - - /* - * Volume computation parameters for gus_adagio_vol() - */ - int main_vol, expression_vol, patch_vol; - - /* Variables for "Ultraclick" removal */ - int dev_pending, note_pending, volume_pending, - sample_pending; - char kill_pending; - long offset_pending; + int env_phase; + unsigned char env_rate[6]; + unsigned char env_offset[6]; + + /* + * Volume computation parameters for gus_adagio_vol() + */ + int main_vol, expression_vol, patch_vol; + + /* Variables for "Ultraclick" removal */ + int dev_pending, note_pending, volume_pending, + sample_pending; + char kill_pending; + long offset_pending; - }; +}; static struct voice_alloc_info *voice_alloc; @@ -101,6 +101,7 @@ * Current version of this driver doesn't allow synth and PCM functions * at the same time. The active_device specifies the active driver */ + static int active_device = 0; #define GUS_DEV_WAVE 1 /* Wave table synth */ @@ -114,12 +115,14 @@ static char bounce_buf[8 * 1024]; /* Must match value set to max_fragment */ static struct wait_queue *dram_sleeper = NULL; -static volatile struct snd_wait dram_sleep_flag = -{0}; +static volatile struct snd_wait dram_sleep_flag = { + 0 +}; /* * Variables and buffers for PCM output */ + #define MAX_PCM_BUFFERS (128*MAX_REALTIME_FACTOR) /* Don't change */ static int pcm_bsize, pcm_nblk, pcm_banksize; @@ -172,8 +175,10 @@ static int patch_table[MAX_PATCH]; static int patch_map[32]; -static struct synth_info gus_info = -{"Gravis UltraSound", 0, SYNTH_TYPE_SAMPLE, SAMPLE_TYPE_GUS, 0, 16, 0, MAX_PATCH}; +static struct synth_info gus_info = { + "Gravis UltraSound", 0, SYNTH_TYPE_SAMPLE, SAMPLE_TYPE_GUS, + 0, 16, 0, MAX_PATCH +}; static void gus_poke(long addr, unsigned char data); static void compute_and_set_volume(int voice, int volume, int ramp_time); @@ -187,10 +192,9 @@ #define INSTANT_RAMP -1 /* Instant change. No ramping */ #define FAST_RAMP 0 /* Fastest possible ramp */ -static void -reset_sample_memory(void) +static void reset_sample_memory(void) { - int i; + int i; for (i = 0; i <= MAX_SAMPLE; i++) sample_ptrs[i] = -1; @@ -209,17 +213,15 @@ patch_table[i] = NOT_SAMPLE; } -void -gus_delay(void) +void gus_delay(void) { - int i; + int i; for (i = 0; i < 7; i++) inb(u_DRAMIO); } -static void -gus_poke(long addr, unsigned char data) +static void gus_poke(long addr, unsigned char data) { /* Writes a byte to the DRAM */ unsigned long flags; @@ -235,8 +237,7 @@ restore_flags(flags); } -static unsigned char -gus_peek(long addr) +static unsigned char gus_peek(long addr) { /* Reads a byte from the DRAM */ unsigned long flags; unsigned char tmp; @@ -255,8 +256,7 @@ return tmp; } -void -gus_write8(int reg, unsigned int data) +void gus_write8(int reg, unsigned int data) { /* Writes to an indirect register (8 bit) */ unsigned long flags; @@ -269,9 +269,9 @@ restore_flags(flags); } -static unsigned char -gus_read8(int reg) -{ /* Reads from an indirect register (8 bit). Offset 0x80. */ +static unsigned char gus_read8(int reg) +{ + /* Reads from an indirect register (8 bit). Offset 0x80. */ unsigned long flags; unsigned char val; @@ -284,9 +284,9 @@ return val; } -static unsigned char -gus_look8(int reg) -{ /* Reads from an indirect register (8 bit). No additional offset. */ +static unsigned char gus_look8(int reg) +{ + /* Reads from an indirect register (8 bit). No additional offset. */ unsigned long flags; unsigned char val; @@ -299,9 +299,9 @@ return val; } -static void -gus_write16(int reg, unsigned int data) -{ /* Writes to an indirect register (16 bit) */ +static void gus_write16(int reg, unsigned int data) +{ + /* Writes to an indirect register (16 bit) */ unsigned long flags; save_flags(flags); @@ -315,9 +315,9 @@ restore_flags(flags); } -static unsigned short -gus_read16(int reg) -{ /* Reads from an indirect register (16 bit). Offset 0x80. */ +static unsigned short gus_read16(int reg) +{ + /* Reads from an indirect register (16 bit). Offset 0x80. */ unsigned long flags; unsigned char hi, lo; @@ -334,9 +334,9 @@ return ((hi << 8) & 0xff00) | lo; } -static unsigned short -gus_look16(int reg) -{ /* Reads from an indirect register (16 bit). No additional offset. */ +static unsigned short gus_look16(int reg) +{ + /* Reads from an indirect register (16 bit). No additional offset. */ unsigned long flags; unsigned char hi, lo; @@ -353,32 +353,33 @@ return ((hi << 8) & 0xff00) | lo; } -static void -gus_write_addr(int reg, unsigned long address, int frac, int is16bit) -{ /* Writes an 24 bit memory address */ +static void gus_write_addr(int reg, unsigned long address, int frac, int is16bit) +{ + /* Writes an 24 bit memory address */ unsigned long hold_address; unsigned long flags; save_flags(flags); cli(); if (is16bit) - { - if (iw_mode) - { - /* Interwave spesific address translations */ - address >>= 1; - } else - { - /* - * Special processing required for 16 bit patches - */ - - hold_address = address; - address = address >> 1; - address &= 0x0001ffffL; - address |= (hold_address & 0x000c0000L); - } - } + { + if (iw_mode) + { + /* Interwave spesific address translations */ + address >>= 1; + } + else + { + /* + * Special processing required for 16 bit patches + */ + + hold_address = address; + address = address >> 1; + address &= 0x0001ffffL; + address |= (hold_address & 0x000c0000L); + } + } gus_write16(reg, (unsigned short) ((address >> 7) & 0xffff)); gus_write16(reg + 1, (unsigned short) ((address << 9) & 0xffff) + (frac << 5)); @@ -390,17 +391,14 @@ restore_flags(flags); } -static void -gus_select_voice(int voice) +static void gus_select_voice(int voice) { if (voice < 0 || voice > 31) return; - outb((voice), u_Voice); } -static void -gus_select_max_voices(int nvoices) +static void gus_select_max_voices(int nvoices) { if (iw_mode) nvoices = 32; @@ -410,26 +408,22 @@ nvoices = 32; voice_alloc->max_voice = nr_voices = nvoices; - gus_write8(0x0e, (nvoices - 1) | 0xc0); } -static void -gus_voice_on(unsigned int mode) +static void gus_voice_on(unsigned int mode) { gus_write8(0x00, (unsigned char) (mode & 0xfc)); gus_delay(); gus_write8(0x00, (unsigned char) (mode & 0xfc)); } -static void -gus_voice_off(void) +static void gus_voice_off(void) { gus_write8(0x00, gus_read8(0x00) | 0x03); } -static void -gus_voice_mode(unsigned int m) +static void gus_voice_mode(unsigned int m) { unsigned char mode = (unsigned char) (m & 0xff); @@ -439,8 +433,7 @@ gus_write8(0x00, (gus_read8(0x00) & 0x03) | (mode & 0xfc)); } -static void -gus_voice_freq(unsigned long freq) +static void gus_voice_freq(unsigned long freq) { unsigned long divisor = freq_div_table[nr_voices - 14]; unsigned short fc; @@ -455,34 +448,29 @@ gus_write16(0x01, fc); } -static void -gus_voice_volume(unsigned int vol) +static void gus_voice_volume(unsigned int vol) { gus_write8(0x0d, 0x03); /* Stop ramp before setting volume */ gus_write16(0x09, (unsigned short) (vol << 4)); } -static void -gus_voice_balance(unsigned int balance) +static void gus_voice_balance(unsigned int balance) { gus_write8(0x0c, (unsigned char) (balance & 0xff)); } -static void -gus_ramp_range(unsigned int low, unsigned int high) +static void gus_ramp_range(unsigned int low, unsigned int high) { gus_write8(0x07, (unsigned char) ((low >> 4) & 0xff)); gus_write8(0x08, (unsigned char) ((high >> 4) & 0xff)); } -static void -gus_ramp_rate(unsigned int scale, unsigned int rate) +static void gus_ramp_rate(unsigned int scale, unsigned int rate) { gus_write8(0x06, (unsigned char) (((scale & 0x03) << 6) | (rate & 0x3f))); } -static void -gus_rampon(unsigned int m) +static void gus_rampon(unsigned int m) { unsigned char mode = (unsigned char) (m & 0xff); @@ -491,10 +479,9 @@ gus_write8(0x0d, mode & 0xfc); } -static void -gus_ramp_mode(unsigned int m) +static void gus_ramp_mode(unsigned int m) { - unsigned char mode = (unsigned char) (m & 0xff); + unsigned char mode = (unsigned char) (m & 0xff); gus_write8(0x0d, (gus_read8(0x0d) & 0x03) | (mode & 0xfc)); /* Leave the last 2 bits alone */ @@ -502,16 +489,14 @@ gus_write8(0x0d, (gus_read8(0x0d) & 0x03) | (mode & 0xfc)); } -static void -gus_rampoff(void) +static void gus_rampoff(void) { gus_write8(0x0d, 0x03); } -static void -gus_set_voice_pos(int voice, long position) +static void gus_set_voice_pos(int voice, long position) { - int sample_no; + int sample_no; if ((sample_no = sample_map[voice]) != -1) if (position < samples[sample_no].len) @@ -522,8 +507,7 @@ samples[sample_no].mode & WAVE_16_BITS); } -static void -gus_voice_init(int voice) +static void gus_voice_init(int voice) { unsigned long flags; @@ -541,8 +525,7 @@ } -static void -gus_voice_init2(int voice) +static void gus_voice_init2(int voice) { voices[voice].panning = 0; voices[voice].mode = 0; @@ -564,30 +547,30 @@ voices[voice].fixed_pitch = 0; } -static void -step_envelope(int voice) +static void step_envelope(int voice) { unsigned vol, prev_vol, phase; unsigned char rate; long int flags; if (voices[voice].mode & WAVE_SUSTAIN_ON && voices[voice].env_phase == 2) - { - save_flags(flags); - cli(); - gus_select_voice(voice); - gus_rampoff(); - restore_flags(flags); - return; - /* - * Sustain phase begins. Continue envelope after receiving note off. - */ - } + { + save_flags(flags); + cli(); + gus_select_voice(voice); + gus_rampoff(); + restore_flags(flags); + return; + /* + * Sustain phase begins. Continue envelope after receiving note off. + */ + } if (voices[voice].env_phase >= 5) - { /* Envelope finished. Shoot the voice down */ - gus_voice_init(voice); - return; - } + { + /* Envelope finished. Shoot the voice down */ + gus_voice_init(voice); + return; + } prev_vol = voices[voice].current_volume; phase = ++voices[voice].env_phase; compute_volume(voice, voices[voice].midi_volume); @@ -606,30 +589,30 @@ voices[voice].volume_irq_mode = VMODE_ENVELOPE; if (((vol - prev_vol) / 64) == 0) /* No significant volume change */ - { - restore_flags(flags); - step_envelope(voice); /* Continue the envelope on the next step */ - return; - } + { + restore_flags(flags); + step_envelope(voice); /* Continue the envelope on the next step */ + return; + } if (vol > prev_vol) - { - if (vol >= (4096 - 64)) - vol = 4096 - 65; - gus_ramp_range(0, vol); - gus_rampon(0x20); /* Increasing volume, with IRQ */ - } else - { - if (vol <= 64) - vol = 65; - gus_ramp_range(vol, 4030); - gus_rampon(0x60); /* Decreasing volume, with IRQ */ - } + { + if (vol >= (4096 - 64)) + vol = 4096 - 65; + gus_ramp_range(0, vol); + gus_rampon(0x20); /* Increasing volume, with IRQ */ + } + else + { + if (vol <= 64) + vol = 65; + gus_ramp_range(vol, 4030); + gus_rampon(0x60); /* Decreasing volume, with IRQ */ + } voices[voice].current_volume = vol; restore_flags(flags); } -static void -init_envelope(int voice) +static void init_envelope(int voice) { voices[voice].env_phase = -1; voices[voice].current_volume = 64; @@ -637,17 +620,15 @@ step_envelope(voice); } -static void -start_release(int voice, long int flags) +static void start_release(int voice, long int flags) { if (gus_read8(0x00) & 0x03) return; /* Voice already stopped */ voices[voice].env_phase = 2; /* Will be incremented by step_envelope */ - voices[voice].current_volume = - voices[voice].initial_volume = - gus_read16(0x09) >> 4; /* Get current volume */ + voices[voice].current_volume = voices[voice].initial_volume = + gus_read16(0x09) >> 4; /* Get current volume */ voices[voice].mode &= ~WAVE_SUSTAIN_ON; gus_rampoff(); @@ -655,42 +636,41 @@ step_envelope(voice); } -static void -gus_voice_fade(int voice) +static void gus_voice_fade(int voice) { - int instr_no = sample_map[voice], is16bits; - long int flags; + int instr_no = sample_map[voice], is16bits; + long int flags; save_flags(flags); cli(); gus_select_voice(voice); if (instr_no < 0 || instr_no > MAX_SAMPLE) - { - gus_write8(0x00, 0x03); /* Hard stop */ - voice_alloc->map[voice] = 0; - restore_flags(flags); - return; - } + { + gus_write8(0x00, 0x03); /* Hard stop */ + voice_alloc->map[voice] = 0; + restore_flags(flags); + return; + } is16bits = (samples[instr_no].mode & WAVE_16_BITS) ? 1 : 0; /* 8 or 16 bits */ if (voices[voice].mode & WAVE_ENVELOPES) - { - start_release(voice, flags); - restore_flags(flags); - return; - } + { + start_release(voice, flags); + restore_flags(flags); + return; + } /* * Ramp the volume down but not too quickly. */ if ((int) (gus_read16(0x09) >> 4) < 100) /* Get current volume */ - { - gus_voice_off(); - gus_rampoff(); - gus_voice_init(voice); - restore_flags(flags); - return; - } + { + gus_voice_off(); + gus_rampoff(); + gus_voice_init(voice); + restore_flags(flags); + return; + } gus_ramp_range(65, 4030); gus_ramp_rate(2, 4); gus_rampon(0x40 | 0x20); /* Down, once, with IRQ */ @@ -698,10 +678,9 @@ restore_flags(flags); } -static void -gus_reset(void) +static void gus_reset(void) { - int i; + int i; gus_select_max_voices(24); volume_base = 3071; @@ -709,23 +688,24 @@ volume_method = VOL_METHOD_ADAGIO; for (i = 0; i < 32; i++) - { - gus_voice_init(i); /* Turn voice off */ - gus_voice_init2(i); - } + { + gus_voice_init(i); /* Turn voice off */ + gus_voice_init2(i); + } } -static void -gus_initialize(void) +static void gus_initialize(void) { - unsigned long flags; - unsigned char dma_image, irq_image, tmp; + unsigned long flags; + unsigned char dma_image, irq_image, tmp; - static unsigned char gus_irq_map[16] = - {0, 0, 0, 3, 0, 2, 0, 4, 0, 1, 0, 5, 6, 0, 0, 7}; - - static unsigned char gus_dma_map[8] = - {0, 1, 0, 2, 0, 3, 4, 5}; + static unsigned char gus_irq_map[16] = { + 0, 0, 0, 3, 0, 2, 0, 4, 0, 1, 0, 5, 6, 0, 0, 7 + }; + + static unsigned char gus_dma_map[8] = { + 0, 1, 0, 2, 0, 3, 4, 5 + }; save_flags(flags); cli(); @@ -787,37 +767,39 @@ irq_image = 0; tmp = gus_irq_map[gus_irq]; if (!gus_pnp_flag && !tmp) - printk("Warning! GUS IRQ not selected\n"); + printk(KERN_WARNING "Warning! GUS IRQ not selected\n"); irq_image |= tmp; irq_image |= 0x40; /* Combine IRQ1 (GF1) and IRQ2 (Midi) */ dual_dma_mode = 1; if (gus_dma2 == gus_dma || gus_dma2 == -1) - { - dual_dma_mode = 0; - dma_image = 0x40; /* Combine DMA1 (DRAM) and IRQ2 (ADC) */ - - tmp = gus_dma_map[gus_dma]; - if (!tmp) - printk("Warning! GUS DMA not selected\n"); + { + dual_dma_mode = 0; + dma_image = 0x40; /* Combine DMA1 (DRAM) and IRQ2 (ADC) */ - dma_image |= tmp; - } else + tmp = gus_dma_map[gus_dma]; + if (!tmp) + printk(KERN_WARNING "Warning! GUS DMA not selected\n"); + + dma_image |= tmp; + } + else + { /* Setup dual DMA channel mode for GUS MAX */ - { - dma_image = gus_dma_map[gus_dma]; - if (!dma_image) - printk("Warning! GUS DMA not selected\n"); - - tmp = gus_dma_map[gus_dma2] << 3; - if (!tmp) - { - printk("Warning! Invalid GUS MAX DMA\n"); - tmp = 0x40; /* Combine DMA channels */ + + dma_image = gus_dma_map[gus_dma]; + if (!dma_image) + printk(KERN_WARNING "Warning! GUS DMA not selected\n"); + + tmp = gus_dma_map[gus_dma2] << 3; + if (!tmp) + { + printk(KERN_WARNING "Warning! Invalid GUS MAX DMA\n"); + tmp = 0x40; /* Combine DMA channels */ dual_dma_mode = 0; - } - dma_image |= tmp; - } + } + dma_image |= tmp; + } /* * For some reason the IRQ and DMA addresses must be written twice @@ -848,8 +830,8 @@ mix_image &= ~0x02; /* Enable line out */ mix_image |= 0x08; /* Enable IRQ */ outb((mix_image), u_Mixer); /* - * Turn mixer channels on - * Note! Mic in is left off. + * Turn mixer channels on + * Note! Mic in is left off. */ gus_select_voice(0); /* This disables writes to IRQ/DMA reg */ @@ -869,17 +851,16 @@ } -static void -pnp_mem_init(void) +static void pnp_mem_init(void) { #include "iwmem.h" #define CHUNK_SIZE (256*1024) #define BANK_SIZE (4*1024*1024) #define CHUNKS_PER_BANK (BANK_SIZE/CHUNK_SIZE) - int bank, chunk, addr, total = 0; - int bank_sizes[4]; - int i, j, bits = -1, nbanks = 0; + int bank, chunk, addr, total = 0; + int bank_sizes[4]; + int i, j, bits = -1, nbanks = 0; /* * This routine determines what kind of RAM is installed in each of the four @@ -902,133 +883,137 @@ * Perform the DRAM size detection for each bank individually. */ for (bank = 0; bank < 4; bank++) - { - int size = 0; + { + int size = 0; + + addr = bank * BANK_SIZE; - addr = bank * BANK_SIZE; + /* Clean check points of each chunk */ + for (chunk = 0; chunk < CHUNKS_PER_BANK; chunk++) + { + gus_poke(addr + chunk * CHUNK_SIZE + 0L, 0x00); + gus_poke(addr + chunk * CHUNK_SIZE + 1L, 0x00); + } - /* Clean check points of each chunk */ - for (chunk = 0; chunk < CHUNKS_PER_BANK; chunk++) - { - gus_poke(addr + chunk * CHUNK_SIZE + 0L, 0x00); - gus_poke(addr + chunk * CHUNK_SIZE + 1L, 0x00); - } - - /* Write a value to each chunk point and verify the result */ - for (chunk = 0; chunk < CHUNKS_PER_BANK; chunk++) - { - gus_poke(addr + chunk * CHUNK_SIZE + 0L, 0x55); - gus_poke(addr + chunk * CHUNK_SIZE + 1L, 0xAA); + /* Write a value to each chunk point and verify the result */ + for (chunk = 0; chunk < CHUNKS_PER_BANK; chunk++) + { + gus_poke(addr + chunk * CHUNK_SIZE + 0L, 0x55); + gus_poke(addr + chunk * CHUNK_SIZE + 1L, 0xAA); - if (gus_peek(addr + chunk * CHUNK_SIZE + 0L) == 0x55 && + if (gus_peek(addr + chunk * CHUNK_SIZE + 0L) == 0x55 && gus_peek(addr + chunk * CHUNK_SIZE + 1L) == 0xAA) - { /* OK. There is RAM. Now check for possible shadows */ - int ok = 1, chunk2; + { + /* OK. There is RAM. Now check for possible shadows */ + int ok = 1, chunk2; - for (chunk2 = 0; ok && chunk2 < chunk; chunk2++) - if (gus_peek(addr + chunk2 * CHUNK_SIZE + 0L) || - gus_peek(addr + chunk2 * CHUNK_SIZE + 1L)) - ok = 0; /* Addressing wraps */ - - if (ok) - size = (chunk + 1) * CHUNK_SIZE; - } - gus_poke(addr + chunk * CHUNK_SIZE + 0L, 0x00); - gus_poke(addr + chunk * CHUNK_SIZE + 1L, 0x00); - } - - bank_sizes[bank] = size; - if (size) - nbanks = bank + 1; - DDB(printk("Interwave: Bank %d, size=%dk\n", bank, size / 1024)); - } + for (chunk2 = 0; ok && chunk2 < chunk; chunk2++) + if (gus_peek(addr + chunk2 * CHUNK_SIZE + 0L) || + gus_peek(addr + chunk2 * CHUNK_SIZE + 1L)) + ok = 0; /* Addressing wraps */ + + if (ok) + size = (chunk + 1) * CHUNK_SIZE; + } + gus_poke(addr + chunk * CHUNK_SIZE + 0L, 0x00); + gus_poke(addr + chunk * CHUNK_SIZE + 1L, 0x00); + } + bank_sizes[bank] = size; + if (size) + nbanks = bank + 1; + DDB(printk("Interwave: Bank %d, size=%dk\n", bank, size / 1024)); + } if (nbanks == 0) /* No RAM - Give up */ - { - printk("Sound: An Interwave audio chip detected but no DRAM\n"); - printk("Sound: Unable to work with this card.\n"); - gus_write8(0x19, gus_read8(0x19) & ~0x01); - gus_mem_size = 0; - return; - } -/* - * Now we know how much DRAM there is in each bank. The next step is - * to find a DRAM size encoding (0 to 12) which is best for the combination - * we have. - * - * First try if any of the possible alternatives matches exactly the amount - * of memory we have. - */ + { + printk(KERN_ERR "Sound: An Interwave audio chip detected but no DRAM\n"); + printk(KERN_ERR "Sound: Unable to work with this card.\n"); + gus_write8(0x19, gus_read8(0x19) & ~0x01); + gus_mem_size = 0; + return; + } + + /* + * Now we know how much DRAM there is in each bank. The next step is + * to find a DRAM size encoding (0 to 12) which is best for the combination + * we have. + * + * First try if any of the possible alternatives matches exactly the amount + * of memory we have. + */ for (i = 0; bits == -1 && i < 13; i++) - { - bits = i; + { + bits = i; - for (j = 0; bits != -1 && j < 4; j++) - if (mem_decode[i][j] != bank_sizes[j]) - bits = -1; /* No hit */ - } + for (j = 0; bits != -1 && j < 4; j++) + if (mem_decode[i][j] != bank_sizes[j]) + bits = -1; /* No hit */ + } + + /* + * If necessary, try to find a combination where other than the last + * bank matches our configuration and the last bank is left oversized. + * In this way we don't leave holes in the middle of memory. + */ -/* - * If necessary, try to find a combination where other than the last - * bank matches our configuration and the last bank is left oversized. - * In this way we don't leave holes in the middle of memory. - */ if (bits == -1) /* No luck yet */ + { for (i = 0; bits == -1 && i < 13; i++) - { - bits = i; + { + bits = i; - for (j = 0; bits != -1 && j < nbanks - 1; j++) - if (mem_decode[i][j] != bank_sizes[j]) - bits = -1; /* No hit */ - if (mem_decode[i][nbanks - 1] < bank_sizes[nbanks - 1]) - bits = -1; /* The last bank is too small */ - } -/* - * The last resort is to search for a combination where the last bank is - * smaller than the actual SIMM. This leaves some memory in the last bank - * unused but doesn't leave holes in the DRAM address space. - */ + for (j = 0; bits != -1 && j < nbanks - 1; j++) + if (mem_decode[i][j] != bank_sizes[j]) + bits = -1; /* No hit */ + if (mem_decode[i][nbanks - 1] < bank_sizes[nbanks - 1]) + bits = -1; /* The last bank is too small */ + } + } + /* + * The last resort is to search for a combination where the last bank is + * smaller than the actual SIMM. This leaves some memory in the last bank + * unused but doesn't leave holes in the DRAM address space. + */ if (bits == -1) /* No luck yet */ - { - for (i = 0; bits == -1 && i < 13; i++) - { - bits = i; - - for (j = 0; bits != -1 && j < nbanks - 1; j++) - if (mem_decode[i][j] != bank_sizes[j]) - bits = -1; /* No hit */ - } - - if (bits != -1) - { - printk("Interwave: Can't use all installed RAM.\n"); - printk("Interwave: Try reordering SIMMS.\n"); - } - } + { + for (i = 0; bits == -1 && i < 13; i++) + { + bits = i; + + for (j = 0; bits != -1 && j < nbanks - 1; j++) + if (mem_decode[i][j] != bank_sizes[j]) + bits = -1; /* No hit */ + } + if (bits != -1) + { + printk(KERN_INFO "Interwave: Can't use all installed RAM.\n"); + printk(KERN_INFO "Interwave: Try reordering SIMMS.\n"); + } + } if (bits == -1) - { - printk("Interwave: Can't find working DRAM encoding.\n"); - printk("Interwave: Defaulting to 256k. Try reordering SIMMS.\n"); - bits = 0; - } + { + printk(KERN_INFO "Interwave: Can't find working DRAM encoding.\n"); + printk(KERN_INFO "Interwave: Defaulting to 256k. Try reordering SIMMS.\n"); + bits = 0; + } DDB(printk("Interwave: Selecting DRAM addressing mode %d\n", bits)); for (bank = 0; bank < 4; bank++) - { - DDB(printk(" Bank %d, mem=%dk (limit %dk)\n", bank, bank_sizes[bank] / 1024, mem_decode[bits][bank] / 1024)); + { + DDB(printk(" Bank %d, mem=%dk (limit %dk)\n", bank, bank_sizes[bank] / 1024, mem_decode[bits][bank] / 1024)); - if (bank_sizes[bank] > mem_decode[bits][bank]) - total += mem_decode[bits][bank]; - else - total += bank_sizes[bank]; - } + if (bank_sizes[bank] > mem_decode[bits][bank]) + total += mem_decode[bits][bank]; + else + total += bank_sizes[bank]; + } DDB(printk("Total %dk of DRAM (enhanced mode)\n", total / 1024)); -/* - * Set the memory addressing mode. - */ + + /* + * Set the memory addressing mode. + */ gus_write16(0x52, (gus_look16(0x52) & 0xfff0) | bits); /* Leave the chip into enhanced mode. Disable LFO */ @@ -1037,8 +1022,7 @@ gus_write8(0x19, (gus_read8(0x19) | 0x01) & ~0x02); } -int -gus_wave_detect(int baseaddr) +int gus_wave_detect(int baseaddr) { unsigned long i, max_mem = 1024L; unsigned long loc; @@ -1059,15 +1043,18 @@ gus_write8(0x5b, ~val); /* Invert all bits */ if ((gus_look8(0x5b) & 0xf0) == (val & 0xf0)) /* No change */ + { if ((gus_look8(0x5b) & 0x0f) == ((~val) & 0x0f)) /* Change */ - { - DDB(printk("Interwave chip version %d detected\n", (val & 0xf0) >> 4)); - gus_pnp_flag = 1; - } else - { - DDB(printk("Not an Interwave chip (%x)\n", gus_look8(0x5b))); - gus_pnp_flag = 0; - } + { + DDB(printk("Interwave chip version %d detected\n", (val & 0xf0) >> 4)); + gus_pnp_flag = 1; + } + else + { + DDB(printk("Not an Interwave chip (%x)\n", gus_look8(0x5b))); + gus_pnp_flag = 0; + } + } gus_write8(0x5b, val); /* Restore all bits */ #endif @@ -1084,28 +1071,26 @@ /* Now zero it out so that I can check for mirroring .. */ gus_poke(0L, 0x00); for (i = 1L; i < max_mem; i++) - { - int n, failed; + { + int n, failed; - /* check for mirroring ... */ - if (gus_peek(0L) != 0) - break; - loc = i << 10; - - for (n = loc - 1, failed = 0; n <= loc; n++) - { - gus_poke(loc, 0xaa); - if (gus_peek(loc) != 0xaa) - failed = 1; - - gus_poke(loc, 0x55); - if (gus_peek(loc) != 0x55) - failed = 1; - } + /* check for mirroring ... */ + if (gus_peek(0L) != 0) + break; + loc = i << 10; - if (failed) - break; - } + for (n = loc - 1, failed = 0; n <= loc; n++) + { + gus_poke(loc, 0xaa); + if (gus_peek(loc) != 0xaa) + failed = 1; + gus_poke(loc, 0x55); + if (gus_peek(loc) != 0x55) + failed = 1; + } + if (failed) + break; + } gus_mem_size = i << 10; return 1; } @@ -1113,30 +1098,30 @@ static int guswave_ioctl(int dev, unsigned int cmd, caddr_t arg) { - switch (cmd) { - case SNDCTL_SYNTH_INFO: - gus_info.nr_voices = nr_voices; - return __copy_to_user(arg, &gus_info, sizeof(gus_info)); - - case SNDCTL_SEQ_RESETSAMPLES: - reset_sample_memory(); - return 0; + switch (cmd) + { + case SNDCTL_SYNTH_INFO: + gus_info.nr_voices = nr_voices; + return copy_to_user(arg, &gus_info, sizeof(gus_info)); + + case SNDCTL_SEQ_RESETSAMPLES: + reset_sample_memory(); + return 0; - case SNDCTL_SEQ_PERCMODE: - return 0; + case SNDCTL_SEQ_PERCMODE: + return 0; - case SNDCTL_SYNTH_MEMAVL: - return (gus_mem_size == 0) ? 0 : gus_mem_size - free_mem_ptr - 32; + case SNDCTL_SYNTH_MEMAVL: + return (gus_mem_size == 0) ? 0 : gus_mem_size - free_mem_ptr - 32; - default: - return -EINVAL; + default: + return -EINVAL; } } -static int -guswave_set_instr(int dev, int voice, int instr_no) +static int guswave_set_instr(int dev, int voice, int instr_no) { - int sample_no; + int sample_no; if (instr_no < 0 || instr_no > MAX_PATCH) instr_no = 0; /* Default to acoustic piano */ @@ -1145,103 +1130,97 @@ return -EINVAL; if (voices[voice].volume_irq_mode == VMODE_START_NOTE) - { - voices[voice].sample_pending = instr_no; - return 0; - } + { + voices[voice].sample_pending = instr_no; + return 0; + } sample_no = patch_table[instr_no]; patch_map[voice] = -1; if (sample_no == NOT_SAMPLE) - { - printk("GUS: Undefined patch %d for voice %d\n", instr_no, voice); - return -EINVAL; /* Patch not defined */ - } + { +/* printk("GUS: Undefined patch %d for voice %d\n", instr_no, voice);*/ + return -EINVAL; /* Patch not defined */ + } if (sample_ptrs[sample_no] == -1) /* Sample not loaded */ - { - printk("GUS: Sample #%d not loaded for patch %d (voice %d)\n", sample_no, instr_no, voice); - return -EINVAL; - } + { +/* printk("GUS: Sample #%d not loaded for patch %d (voice %d)\n", sample_no, instr_no, voice);*/ + return -EINVAL; + } sample_map[voice] = sample_no; patch_map[voice] = instr_no; return 0; } -static int -guswave_kill_note(int dev, int voice, int note, int velocity) +static int guswave_kill_note(int dev, int voice, int note, int velocity) { - unsigned long flags; + unsigned long flags; save_flags(flags); cli(); /* voice_alloc->map[voice] = 0xffff; */ if (voices[voice].volume_irq_mode == VMODE_START_NOTE) - { - voices[voice].kill_pending = 1; - restore_flags(flags); - } else - { - restore_flags(flags); - gus_voice_fade(voice); - } + { + voices[voice].kill_pending = 1; + restore_flags(flags); + } + else + { + restore_flags(flags); + gus_voice_fade(voice); + } restore_flags(flags); return 0; } -static void -guswave_aftertouch(int dev, int voice, int pressure) +static void guswave_aftertouch(int dev, int voice, int pressure) { } -static void -guswave_panning(int dev, int voice, int value) +static void guswave_panning(int dev, int voice, int value) { if (voice >= 0 || voice < 32) voices[voice].panning = value; } -static void -guswave_volume_method(int dev, int mode) +static void guswave_volume_method(int dev, int mode) { if (mode == VOL_METHOD_LINEAR || mode == VOL_METHOD_ADAGIO) volume_method = mode; } -static void -compute_volume(int voice, int volume) +static void compute_volume(int voice, int volume) { if (volume < 128) voices[voice].midi_volume = volume; switch (volume_method) - { - case VOL_METHOD_ADAGIO: - voices[voice].initial_volume = - gus_adagio_vol(voices[voice].midi_volume, voices[voice].main_vol, - voices[voice].expression_vol, - voices[voice].patch_vol); - break; - - case VOL_METHOD_LINEAR: /* Totally ignores patch-volume and expression */ - voices[voice].initial_volume = - gus_linear_vol(volume, voices[voice].main_vol); - break; - - default: - voices[voice].initial_volume = volume_base + - (voices[voice].midi_volume * volume_scale); - } + { + case VOL_METHOD_ADAGIO: + voices[voice].initial_volume = + gus_adagio_vol(voices[voice].midi_volume, voices[voice].main_vol, + voices[voice].expression_vol, + voices[voice].patch_vol); + break; + + case VOL_METHOD_LINEAR: /* Totally ignores patch-volume and expression */ + voices[voice].initial_volume = gus_linear_vol(volume, voices[voice].main_vol); + break; + + default: + voices[voice].initial_volume = volume_base + + (voices[voice].midi_volume * volume_scale); + } if (voices[voice].initial_volume > 4030) voices[voice].initial_volume = 4030; } -static void -compute_and_set_volume(int voice, int volume, int ramp_time) +static void compute_and_set_volume(int voice, int volume, int ramp_time) { - int curr, target, rate; - unsigned long flags; + int curr, target, rate; + unsigned long flags; compute_volume(voice, volume); voices[voice].current_volume = voices[voice].initial_volume; @@ -1249,7 +1228,7 @@ save_flags(flags); cli(); /* - * CAUTION! Interrupts disabled. Enable them before returning + * CAUTION! Interrupts disabled. Enable them before returning */ gus_select_voice(voice); @@ -1258,12 +1237,12 @@ target = voices[voice].initial_volume; if (ramp_time == INSTANT_RAMP) - { - gus_rampoff(); - gus_voice_volume(target); - restore_flags(flags); - return; - } + { + gus_rampoff(); + gus_voice_volume(target); + restore_flags(flags); + return; + } if (ramp_time == FAST_RAMP) rate = 63; else @@ -1271,34 +1250,34 @@ gus_ramp_rate(0, rate); if ((target - curr) / 64 == 0) /* Close enough to target. */ - { - gus_rampoff(); - gus_voice_volume(target); - restore_flags(flags); - return; - } + { + gus_rampoff(); + gus_voice_volume(target); + restore_flags(flags); + return; + } if (target > curr) - { - if (target > (4095 - 65)) - target = 4095 - 65; - gus_ramp_range(curr, target); - gus_rampon(0x00); /* Ramp up, once, no IRQ */ - } else - { - if (target < 65) - target = 65; + { + if (target > (4095 - 65)) + target = 4095 - 65; + gus_ramp_range(curr, target); + gus_rampon(0x00); /* Ramp up, once, no IRQ */ + } + else + { + if (target < 65) + target = 65; - gus_ramp_range(target, curr); - gus_rampon(0x40); /* Ramp down, once, no irq */ - } + gus_ramp_range(target, curr); + gus_rampon(0x40); /* Ramp down, once, no irq */ + } restore_flags(flags); } -static void -dynamic_volume_change(int voice) +static void dynamic_volume_change(int voice) { - unsigned char status; - unsigned long flags; + unsigned char status; + unsigned long flags; save_flags(flags); cli(); @@ -1310,10 +1289,11 @@ return; /* Voice was not running */ if (!(voices[voice].mode & WAVE_ENVELOPES)) - { - compute_and_set_volume(voice, voices[voice].midi_volume, 1); - return; - } + { + compute_and_set_volume(voice, voices[voice].midi_volume, 1); + return; + } + /* * Voice is running and has envelopes. */ @@ -1325,10 +1305,10 @@ restore_flags(flags); if (status & 0x03) /* Sustain phase? */ - { - compute_and_set_volume(voice, voices[voice].midi_volume, 1); - return; - } + { + compute_and_set_volume(voice, voices[voice].midi_volume, 1); + return; + } if (voices[voice].env_phase < 0) return; @@ -1336,8 +1316,7 @@ } -static void -guswave_controller(int dev, int voice, int ctrl_num, int value) +static void guswave_controller(int dev, int voice, int ctrl_num, int value) { unsigned long flags; unsigned long freq; @@ -1346,88 +1325,84 @@ return; switch (ctrl_num) - { - case CTRL_PITCH_BENDER: - voices[voice].bender = value; - - if (voices[voice].volume_irq_mode != VMODE_START_NOTE) - { - freq = compute_finetune(voices[voice].orig_freq, value, - voices[voice].bender_range, 0); - voices[voice].current_freq = freq; - - save_flags(flags); - cli(); - gus_select_voice(voice); - gus_voice_freq(freq); - restore_flags(flags); - } - break; - - case CTRL_PITCH_BENDER_RANGE: - voices[voice].bender_range = value; - break; - case CTL_EXPRESSION: - value /= 128; - case CTRL_EXPRESSION: - if (volume_method == VOL_METHOD_ADAGIO) - { - voices[voice].expression_vol = value; - if (voices[voice].volume_irq_mode != VMODE_START_NOTE) - dynamic_volume_change(voice); - } - break; - - case CTL_PAN: - voices[voice].panning = (value * 2) - 128; - break; - - case CTL_MAIN_VOLUME: - value = (value * 100) / 16383; - - case CTRL_MAIN_VOLUME: - voices[voice].main_vol = value; - if (voices[voice].volume_irq_mode != VMODE_START_NOTE) - dynamic_volume_change(voice); - break; + { + case CTRL_PITCH_BENDER: + voices[voice].bender = value; - default: - break; - } + if (voices[voice].volume_irq_mode != VMODE_START_NOTE) + { + freq = compute_finetune(voices[voice].orig_freq, value, voices[voice].bender_range, 0); + voices[voice].current_freq = freq; + + save_flags(flags); + cli(); + gus_select_voice(voice); + gus_voice_freq(freq); + restore_flags(flags); + } + break; + + case CTRL_PITCH_BENDER_RANGE: + voices[voice].bender_range = value; + break; + case CTL_EXPRESSION: + value /= 128; + case CTRL_EXPRESSION: + if (volume_method == VOL_METHOD_ADAGIO) + { + voices[voice].expression_vol = value; + if (voices[voice].volume_irq_mode != VMODE_START_NOTE) + dynamic_volume_change(voice); + } + break; + + case CTL_PAN: + voices[voice].panning = (value * 2) - 128; + break; + + case CTL_MAIN_VOLUME: + value = (value * 100) / 16383; + + case CTRL_MAIN_VOLUME: + voices[voice].main_vol = value; + if (voices[voice].volume_irq_mode != VMODE_START_NOTE) + dynamic_volume_change(voice); + break; + + default: + break; + } } -static int -guswave_start_note2(int dev, int voice, int note_num, int volume) +static int guswave_start_note2(int dev, int voice, int note_num, int volume) { - int sample, best_sample, best_delta, delta_freq; - int is16bits, samplep, patch, pan; + int sample, best_sample, best_delta, delta_freq; + int is16bits, samplep, patch, pan; unsigned long note_freq, base_note, freq, flags; unsigned char mode = 0; if (voice < 0 || voice > 31) - { - printk("GUS: Invalid voice\n"); - return -EINVAL; - } + { +/* printk("GUS: Invalid voice\n");*/ + return -EINVAL; + } if (note_num == 255) - { - if (voices[voice].mode & WAVE_ENVELOPES) - { - voices[voice].midi_volume = volume; - dynamic_volume_change(voice); - return 0; - } - compute_and_set_volume(voice, volume, 1); - return 0; - } + { + if (voices[voice].mode & WAVE_ENVELOPES) + { + voices[voice].midi_volume = volume; + dynamic_volume_change(voice); + return 0; + } + compute_and_set_volume(voice, volume, 1); + return 0; + } if ((patch = patch_map[voice]) == -1) - { - return -EINVAL; - } + return -EINVAL; if ((samplep = patch_table[patch]) == NOT_SAMPLE) - { - return -EINVAL; - } + { + return -EINVAL; + } note_freq = note_to_freq(note_num); /* @@ -1439,30 +1414,32 @@ best_sample = samplep; best_delta = 1000000; while (samplep != 0 && samplep != NOT_SAMPLE && sample == -1) - { - delta_freq = note_freq - samples[samplep].base_note; - if (delta_freq < 0) - delta_freq = -delta_freq; - if (delta_freq < best_delta) - { - best_sample = samplep; - best_delta = delta_freq; - } - if (samples[samplep].low_note <= note_freq && - note_freq <= samples[samplep].high_note) - sample = samplep; - else - samplep = samples[samplep].key; /* Link to next sample */ + { + delta_freq = note_freq - samples[samplep].base_note; + if (delta_freq < 0) + delta_freq = -delta_freq; + if (delta_freq < best_delta) + { + best_sample = samplep; + best_delta = delta_freq; + } + if (samples[samplep].low_note <= note_freq && + note_freq <= samples[samplep].high_note) + { + sample = samplep; + } + else + samplep = samples[samplep].key; /* Link to next sample */ } if (sample == -1) sample = best_sample; if (sample == -1) - { - printk("GUS: Patch %d not defined for note %d\n", patch, note_num); - return 0; /* Should play default patch ??? */ - } - is16bits = (samples[sample].mode & WAVE_16_BITS) ? 1 : 0; + { +/* printk("GUS: Patch %d not defined for note %d\n", patch, note_num);*/ + return 0; /* Should play default patch ??? */ + } + is16bits = (samples[sample].mode & WAVE_16_BITS) ? 1 : 0; voices[voice].mode = samples[sample].mode; voices[voice].patch_vol = samples[sample].volume; @@ -1470,27 +1447,28 @@ gus_write8(0x15, 0x00); /* RAM, Reset voice deactivate bit of SMSI */ if (voices[voice].mode & WAVE_ENVELOPES) - { - int i; + { + int i; - for (i = 0; i < 6; i++) - { - voices[voice].env_rate[i] = samples[sample].env_rate[i]; - voices[voice].env_offset[i] = samples[sample].env_offset[i]; - } - } + for (i = 0; i < 6; i++) + { + voices[voice].env_rate[i] = samples[sample].env_rate[i]; + voices[voice].env_offset[i] = samples[sample].env_offset[i]; + } + } sample_map[voice] = sample; if (voices[voice].fixed_pitch) /* Fixed pitch */ - { + { freq = samples[sample].base_freq; - } else - { - base_note = samples[sample].base_note / 100; - note_freq /= 100; + } + else + { + base_note = samples[sample].base_note / 100; + note_freq /= 100; - freq = samples[sample].base_freq * note_freq / base_note; - } + freq = samples[sample].base_freq * note_freq / base_note; + } voices[voice].orig_freq = freq; @@ -1511,15 +1489,15 @@ pan = 15; if (samples[sample].mode & WAVE_16_BITS) - { - mode |= 0x04; /* 16 bits */ - if ((sample_ptrs[sample] / GUS_BANK_SIZE) != - ((sample_ptrs[sample] + samples[sample].len) / GUS_BANK_SIZE)) - printk("GUS: Sample address error\n"); - } - /************************************************************************* - * CAUTION! Interrupts disabled. Don't return before enabling - *************************************************************************/ + { + mode |= 0x04; /* 16 bits */ + if ((sample_ptrs[sample] / GUS_BANK_SIZE) != + ((sample_ptrs[sample] + samples[sample].len) / GUS_BANK_SIZE)) + printk(KERN_ERR "GUS: Sample address error\n"); + } + /************************************************************************* + * CAUTION! Interrupts disabled. Don't return before enabling + *************************************************************************/ save_flags(flags); cli(); @@ -1530,13 +1508,14 @@ restore_flags(flags); if (voices[voice].mode & WAVE_ENVELOPES) - { - compute_volume(voice, volume); - init_envelope(voice); - } else - { - compute_and_set_volume(voice, volume, 0); - } + { + compute_volume(voice, volume); + init_envelope(voice); + } + else + { + compute_and_set_volume(voice, volume, 0); + } save_flags(flags); cli(); @@ -1544,43 +1523,38 @@ if (samples[sample].mode & WAVE_LOOP_BACK) gus_write_addr(0x0a, sample_ptrs[sample] + samples[sample].len - - voices[voice].offset_pending, 0, is16bits); /* start=end */ + voices[voice].offset_pending, 0, is16bits); /* start=end */ else - gus_write_addr(0x0a, sample_ptrs[sample] + voices[voice].offset_pending, - 0, is16bits); /* Sample start=begin */ + gus_write_addr(0x0a, sample_ptrs[sample] + voices[voice].offset_pending, 0, is16bits); /* Sample start=begin */ if (samples[sample].mode & WAVE_LOOPING) - { - mode |= 0x08; + { + mode |= 0x08; - if (samples[sample].mode & WAVE_BIDIR_LOOP) - mode |= 0x10; + if (samples[sample].mode & WAVE_BIDIR_LOOP) + mode |= 0x10; - if (samples[sample].mode & WAVE_LOOP_BACK) - { - gus_write_addr(0x0a, - sample_ptrs[sample] + samples[sample].loop_end - + if (samples[sample].mode & WAVE_LOOP_BACK) + { + gus_write_addr(0x0a, sample_ptrs[sample] + samples[sample].loop_end - voices[voice].offset_pending, (samples[sample].fractions >> 4) & 0x0f, is16bits); - mode |= 0x40; - } - gus_write_addr(0x02, sample_ptrs[sample] + samples[sample].loop_start, - samples[sample].fractions & 0x0f, - is16bits); /* Loop start location */ - gus_write_addr(0x04, sample_ptrs[sample] + samples[sample].loop_end, - (samples[sample].fractions >> 4) & 0x0f, - is16bits); /* Loop end location */ - } else - { - mode |= 0x20; /* Loop IRQ at the end */ - voices[voice].loop_irq_mode = LMODE_FINISH; /* Ramp down at the end */ - voices[voice].loop_irq_parm = 1; - gus_write_addr(0x02, sample_ptrs[sample], - 0, is16bits); /* Loop start location */ - gus_write_addr(0x04, sample_ptrs[sample] + samples[sample].len - 1, - (samples[sample].fractions >> 4) & 0x0f, - is16bits); /* Loop end location */ - } + mode |= 0x40; + } + gus_write_addr(0x02, sample_ptrs[sample] + samples[sample].loop_start, + samples[sample].fractions & 0x0f, is16bits); /* Loop start location */ + gus_write_addr(0x04, sample_ptrs[sample] + samples[sample].loop_end, + (samples[sample].fractions >> 4) & 0x0f, is16bits); /* Loop end location */ + } + else + { + mode |= 0x20; /* Loop IRQ at the end */ + voices[voice].loop_irq_mode = LMODE_FINISH; /* Ramp down at the end */ + voices[voice].loop_irq_parm = 1; + gus_write_addr(0x02, sample_ptrs[sample], 0, is16bits); /* Loop start location */ + gus_write_addr(0x04, sample_ptrs[sample] + samples[sample].len - 1, + (samples[sample].fractions >> 4) & 0x0f, is16bits); /* Loop end location */ + } gus_voice_freq(freq); gus_voice_balance(pan); gus_voice_on(mode); @@ -1595,82 +1569,81 @@ * ramping. */ -static int -guswave_start_note(int dev, int voice, int note_num, int volume) +static int guswave_start_note(int dev, int voice, int note_num, int volume) { - long int flags; - int mode; - int ret_val = 0; + long int flags; + int mode; + int ret_val = 0; save_flags(flags); cli(); if (note_num == 255) - { - if (voices[voice].volume_irq_mode == VMODE_START_NOTE) - { - voices[voice].volume_pending = volume; - } else - { - ret_val = guswave_start_note2(dev, voice, note_num, volume); - } - } else - { - gus_select_voice(voice); - mode = gus_read8(0x00); - if (mode & 0x20) - gus_write8(0x00, mode & 0xdf); /* No interrupt! */ - - voices[voice].offset_pending = 0; - voices[voice].kill_pending = 0; - voices[voice].volume_irq_mode = 0; - voices[voice].loop_irq_mode = 0; - - if (voices[voice].sample_pending >= 0) - { - restore_flags(flags); /* Run temporarily with interrupts enabled */ - guswave_set_instr(voices[voice].dev_pending, voice, - voices[voice].sample_pending); - voices[voice].sample_pending = -1; - save_flags(flags); - cli(); - gus_select_voice(voice); /* Reselect the voice (just to be sure) */ - } - if ((mode & 0x01) || (int) ((gus_read16(0x09) >> 4) < (unsigned) 2065)) - { - ret_val = guswave_start_note2(dev, voice, note_num, volume); - } else - { - voices[voice].dev_pending = dev; - voices[voice].note_pending = note_num; - voices[voice].volume_pending = volume; - voices[voice].volume_irq_mode = VMODE_START_NOTE; - - gus_rampoff(); - gus_ramp_range(2000, 4065); - gus_ramp_rate(0, 63); /* Fastest possible rate */ - gus_rampon(0x20 | 0x40); /* Ramp down, once, irq */ - } - } + { + if (voices[voice].volume_irq_mode == VMODE_START_NOTE) + { + voices[voice].volume_pending = volume; + } + else + { + ret_val = guswave_start_note2(dev, voice, note_num, volume); + } + } + else + { + gus_select_voice(voice); + mode = gus_read8(0x00); + if (mode & 0x20) + gus_write8(0x00, mode & 0xdf); /* No interrupt! */ + + voices[voice].offset_pending = 0; + voices[voice].kill_pending = 0; + voices[voice].volume_irq_mode = 0; + voices[voice].loop_irq_mode = 0; + + if (voices[voice].sample_pending >= 0) + { + restore_flags(flags); /* Run temporarily with interrupts enabled */ + guswave_set_instr(voices[voice].dev_pending, voice, voices[voice].sample_pending); + voices[voice].sample_pending = -1; + save_flags(flags); + cli(); + gus_select_voice(voice); /* Reselect the voice (just to be sure) */ + } + if ((mode & 0x01) || (int) ((gus_read16(0x09) >> 4) < (unsigned) 2065)) + { + ret_val = guswave_start_note2(dev, voice, note_num, volume); + } + else + { + voices[voice].dev_pending = dev; + voices[voice].note_pending = note_num; + voices[voice].volume_pending = volume; + voices[voice].volume_irq_mode = VMODE_START_NOTE; + + gus_rampoff(); + gus_ramp_range(2000, 4065); + gus_ramp_rate(0, 63); /* Fastest possible rate */ + gus_rampon(0x20 | 0x40); /* Ramp down, once, irq */ + } + } restore_flags(flags); return ret_val; } -static void -guswave_reset(int dev) +static void guswave_reset(int dev) { - int i; + int i; for (i = 0; i < 32; i++) - { - gus_voice_init(i); - gus_voice_init2(i); - } + { + gus_voice_init(i); + gus_voice_init2(i); + } } -static int -guswave_open(int dev, int mode) +static int guswave_open(int dev, int mode) { - int err; + int err; if (gus_busy) return -EBUSY; @@ -1678,10 +1651,11 @@ voice_alloc->timestamp = 0; if ((err = DMAbuf_open_dma(gus_devnum)) < 0) - { - /* printk( "GUS: Loading samples without DMA\n"); */ - gus_no_dma = 1; /* Upload samples using PIO */ - } else + { + /* printk( "GUS: Loading samples without DMA\n"); */ + gus_no_dma = 1; /* Upload samples using PIO */ + } + else gus_no_dma = 0; dram_sleep_flag.opts = WK_NONE; @@ -1696,8 +1670,7 @@ return 0; } -static void -guswave_close(int dev) +static void guswave_close(int dev) { gus_busy = 0; active_device = 0; @@ -1707,35 +1680,34 @@ DMAbuf_close_dma(gus_devnum); } -static int -guswave_load_patch(int dev, int format, const char *addr, +static int guswave_load_patch(int dev, int format, const char *addr, int offs, int count, int pmgr_flag) { struct patch_info patch; - int instr; - long sizeof_patch; + int instr; + long sizeof_patch; - unsigned long blk_sz, blk_end, left, src_offs, target; + unsigned long blk_sz, blk_end, left, src_offs, target; sizeof_patch = (long) &patch.data[0] - (long) &patch; /* Header size */ if (format != GUS_PATCH) - { - printk("GUS Error: Invalid patch format (key) 0x%x\n", format); - return -EINVAL; - } + { +/* printk("GUS Error: Invalid patch format (key) 0x%x\n", format);*/ + return -EINVAL; + } if (count < sizeof_patch) - { - printk("GUS Error: Patch header too short\n"); + { +/* printk("GUS Error: Patch header too short\n");*/ return -EINVAL; - } + } count -= sizeof_patch; if (free_sample >= MAX_SAMPLE) - { - printk("GUS: Sample table full\n"); + { +/* printk("GUS: Sample table full\n");*/ return -ENOSPC; - } + } /* * Copy the header from user space but ignore the first bytes which have * been transferred already. @@ -1746,63 +1718,63 @@ if (patch.mode & WAVE_ROM) return -EINVAL; if (gus_mem_size == 0) - return -ENOSPC; instr = patch.instr_no; if (instr < 0 || instr > MAX_PATCH) - { - printk("GUS: Invalid patch number %d\n", instr); - return -EINVAL; - } + { +/* printk(KERN_ERR "GUS: Invalid patch number %d\n", instr);*/ + return -EINVAL; + } if (count < patch.len) - { - printk("GUS Warning: Patch record too short (%d<%d)\n", count, (int) patch.len); - patch.len = count; - } + { +/* printk(KERN_ERR "GUS Warning: Patch record too short (%d<%d)\n", count, (int) patch.len);*/ + patch.len = count; + } if (patch.len <= 0 || patch.len > gus_mem_size) - { - printk("GUS: Invalid sample length %d\n", (int) patch.len); - return -EINVAL; - } + { +/* printk(KERN_ERR "GUS: Invalid sample length %d\n", (int) patch.len);*/ + return -EINVAL; + } if (patch.mode & WAVE_LOOPING) - { - if (patch.loop_start < 0 || patch.loop_start >= patch.len) - { - printk("GUS: Invalid loop start\n"); - return -EINVAL; - } - if (patch.loop_end < patch.loop_start || patch.loop_end > patch.len) - { - printk("GUS: Invalid loop end\n"); - return -EINVAL; - } - } + { + if (patch.loop_start < 0 || patch.loop_start >= patch.len) + { +/* printk(KERN_ERR "GUS: Invalid loop start\n");*/ + return -EINVAL; + } + if (patch.loop_end < patch.loop_start || patch.loop_end > patch.len) + { +/* printk(KERN_ERR "GUS: Invalid loop end\n");*/ + return -EINVAL; + } + } free_mem_ptr = (free_mem_ptr + 31) & ~31; /* 32 byte alignment */ if (patch.mode & WAVE_16_BITS) - { - /* - * 16 bit samples must fit one 256k bank. - */ - if (patch.len >= GUS_BANK_SIZE) - { - printk("GUS: Sample (16 bit) too long %d\n", (int) patch.len); - return -ENOSPC; - } - if ((free_mem_ptr / GUS_BANK_SIZE) != - ((free_mem_ptr + patch.len) / GUS_BANK_SIZE)) - { - unsigned long tmp_mem = /* Align to 256K */ - ((free_mem_ptr / GUS_BANK_SIZE) + 1) * GUS_BANK_SIZE; + { + /* + * 16 bit samples must fit one 256k bank. + */ + if (patch.len >= GUS_BANK_SIZE) + { +/* printk("GUS: Sample (16 bit) too long %d\n", (int) patch.len);*/ + return -ENOSPC; + } + if ((free_mem_ptr / GUS_BANK_SIZE) != + ((free_mem_ptr + patch.len) / GUS_BANK_SIZE)) + { + unsigned long tmp_mem = + /* Align to 256K */ + ((free_mem_ptr / GUS_BANK_SIZE) + 1) * GUS_BANK_SIZE; - if ((tmp_mem + patch.len) > gus_mem_size) - return -ENOSPC; + if ((tmp_mem + patch.len) > gus_mem_size) + return -ENOSPC; - free_mem_ptr = tmp_mem; /* This leaves unusable memory */ - } - } + free_mem_ptr = tmp_mem; /* This leaves unusable memory */ + } + } if ((free_mem_ptr + patch.len) > gus_mem_size) return -ENOSPC; @@ -1816,9 +1788,9 @@ patch.mode &= ~WAVE_TREMOLO; if (!(patch.mode & WAVE_FRACTIONS)) - { + { patch.fractions = 0; - } + } memcpy((char *) &samples[free_sample], &patch, sizeof_patch); /* @@ -1837,162 +1809,154 @@ target = free_mem_ptr; while (left) /* Not completely transferred yet */ - { - blk_sz = audio_devs[gus_devnum]->dmap_out->bytes_in_use; - if (blk_sz > left) - blk_sz = left; - - /* - * DMA cannot cross bank (256k) boundaries. Check for that. - */ - blk_end = target + blk_sz; - - if ((target / GUS_BANK_SIZE) != (blk_end / GUS_BANK_SIZE)) - { /* Split the block */ - - blk_end &= ~(GUS_BANK_SIZE - 1); - blk_sz = blk_end - target; - } - if (gus_no_dma) - { - /* - * For some reason the DMA is not possible. We have to use PIO. - */ - long i; - unsigned char data; - - for (i = 0; i < blk_sz; i++) - { - get_user(*(unsigned char *) &data, (unsigned char *) &((addr)[sizeof_patch + i])); - if (patch.mode & WAVE_UNSIGNED) - if (!(patch.mode & WAVE_16_BITS) || (i & 0x01)) - data ^= 0x80; /* Convert to signed */ - gus_poke(target + i, data); - } - } else - { - unsigned long address, hold_address; - unsigned char dma_command; - unsigned long flags; - - if (audio_devs[gus_devnum]->dmap_out->raw_buf == NULL) - { - printk("GUS: DMA buffer == NULL\n"); - return -ENOSPC; - } - /* - * OK, move now. First in and then out. - */ - - copy_from_user(audio_devs[gus_devnum]->dmap_out->raw_buf, &(addr)[sizeof_patch + src_offs], blk_sz); - - save_flags(flags); - cli(); -/******** INTERRUPTS DISABLED NOW ********/ - gus_write8(0x41, 0); /* Disable GF1 DMA */ - DMAbuf_start_dma(gus_devnum, - audio_devs[gus_devnum]->dmap_out->raw_buf_phys, - blk_sz, DMA_MODE_WRITE); - - /* - * Set the DRAM address for the wave data - */ - - if (iw_mode) - { - /* Different address translation in enhanced mode */ - - unsigned char hi; - - if (gus_dma > 4) - address = target >> 1; /* Convert to 16 bit word address */ - else - address = target; - - hi = (unsigned char) ((address >> 16) & 0xf0); - hi += (unsigned char) (address & 0x0f); - - gus_write16(0x42, (address >> 4) & 0xffff); /* DMA address (low) */ - gus_write8(0x50, hi); - } else - { - address = target; + { + blk_sz = audio_devs[gus_devnum]->dmap_out->bytes_in_use; + if (blk_sz > left) + blk_sz = left; - if (audio_devs[gus_devnum]->dmap_out->dma > 3) - { - hold_address = address; - address = address >> 1; - address &= 0x0001ffffL; - address |= (hold_address & 0x000c0000L); - } - gus_write16(0x42, (address >> 4) & 0xffff); /* DRAM DMA address */ - } + /* + * DMA cannot cross bank (256k) boundaries. Check for that. + */ + + blk_end = target + blk_sz; - /* - * Start the DMA transfer - */ - - dma_command = 0x21; /* IRQ enable, DMA start */ - if (patch.mode & WAVE_UNSIGNED) - dma_command |= 0x80; /* Invert MSB */ - if (patch.mode & WAVE_16_BITS) - dma_command |= 0x40; /* 16 bit _DATA_ */ - if (audio_devs[gus_devnum]->dmap_out->dma > 3) - dma_command |= 0x04; /* 16 bit DMA _channel_ */ - - gus_write8(0x41, dma_command); /* Lets go luteet (=bugs) */ - - /* - * Sleep here until the DRAM DMA done interrupt is served - */ - active_device = GUS_DEV_WAVE; - - - { - unsigned long tlimit; - - if (HZ) - current->timeout = tlimit = jiffies + (HZ); - else - tlimit = (unsigned long) -1; - dram_sleep_flag.opts = WK_SLEEP; - interruptible_sleep_on(&dram_sleeper); - if (!(dram_sleep_flag.opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - dram_sleep_flag.opts |= WK_TIMEOUT; - } - dram_sleep_flag.opts &= ~WK_SLEEP; - }; - if ((dram_sleep_flag.opts & WK_TIMEOUT)) - printk("GUS: DMA Transfer timed out\n"); - restore_flags(flags); - } - - /* - * Now the next part - */ - - left -= blk_sz; - src_offs += blk_sz; - target += blk_sz; + if ((target / GUS_BANK_SIZE) != (blk_end / GUS_BANK_SIZE)) + { + /* Split the block */ + blk_end &= ~(GUS_BANK_SIZE - 1); + blk_sz = blk_end - target; + } + if (gus_no_dma) + { + /* + * For some reason the DMA is not possible. We have to use PIO. + */ + long i; + unsigned char data; - gus_write8(0x41, 0); /* Stop DMA */ - } + for (i = 0; i < blk_sz; i++) + { + get_user(*(unsigned char *) &data, (unsigned char *) &((addr)[sizeof_patch + i])); + if (patch.mode & WAVE_UNSIGNED) + if (!(patch.mode & WAVE_16_BITS) || (i & 0x01)) + data ^= 0x80; /* Convert to signed */ + gus_poke(target + i, data); + } + } + else + { + unsigned long address, hold_address; + unsigned char dma_command; + unsigned long flags; + unsigned long tlimit; - free_mem_ptr += patch.len; + if (audio_devs[gus_devnum]->dmap_out->raw_buf == NULL) + { + printk(KERN_ERR "GUS: DMA buffer == NULL\n"); + return -ENOSPC; + } + /* + * OK, move now. First in and then out. + */ + + copy_from_user(audio_devs[gus_devnum]->dmap_out->raw_buf, &(addr)[sizeof_patch + src_offs], blk_sz); + + save_flags(flags); + cli(); + /******** INTERRUPTS DISABLED NOW ********/ + gus_write8(0x41, 0); /* Disable GF1 DMA */ + DMAbuf_start_dma(gus_devnum, audio_devs[gus_devnum]->dmap_out->raw_buf_phys, + blk_sz, DMA_MODE_WRITE); + + /* + * Set the DRAM address for the wave data + */ + if (iw_mode) + { + /* Different address translation in enhanced mode */ + + unsigned char hi; + + if (gus_dma > 4) + address = target >> 1; /* Convert to 16 bit word address */ + else + address = target; + + hi = (unsigned char) ((address >> 16) & 0xf0); + hi += (unsigned char) (address & 0x0f); + + gus_write16(0x42, (address >> 4) & 0xffff); /* DMA address (low) */ + gus_write8(0x50, hi); + } + else + { + address = target; + if (audio_devs[gus_devnum]->dmap_out->dma > 3) + { + hold_address = address; + address = address >> 1; + address &= 0x0001ffffL; + address |= (hold_address & 0x000c0000L); + } + gus_write16(0x42, (address >> 4) & 0xffff); /* DRAM DMA address */ + } + + /* + * Start the DMA transfer + */ + + dma_command = 0x21; /* IRQ enable, DMA start */ + if (patch.mode & WAVE_UNSIGNED) + dma_command |= 0x80; /* Invert MSB */ + if (patch.mode & WAVE_16_BITS) + dma_command |= 0x40; /* 16 bit _DATA_ */ + if (audio_devs[gus_devnum]->dmap_out->dma > 3) + dma_command |= 0x04; /* 16 bit DMA _channel_ */ + + gus_write8(0x41, dma_command); /* Lets go luteet (=bugs) */ + + /* + * Sleep here until the DRAM DMA done interrupt is served + */ + active_device = GUS_DEV_WAVE; + + current->timeout = tlimit = jiffies + HZ; + dram_sleep_flag.opts = WK_SLEEP; + interruptible_sleep_on(&dram_sleeper); + if (!(dram_sleep_flag.opts & WK_WAKEUP)) + { + if (jiffies >= tlimit) + dram_sleep_flag.opts |= WK_TIMEOUT; + } + dram_sleep_flag.opts &= ~WK_SLEEP; + if ((dram_sleep_flag.opts & WK_TIMEOUT)) + printk(KERN_WARNING "GUS: DMA Transfer timed out\n"); + restore_flags(flags); + } + + /* + * Now the next part + */ + + left -= blk_sz; + src_offs += blk_sz; + target += blk_sz; + + gus_write8(0x41, 0); /* Stop DMA */ + } + + free_mem_ptr += patch.len; free_sample++; return 0; } -static void -guswave_hw_control(int dev, unsigned char *event_rec) +static void guswave_hw_control(int dev, unsigned char *event_rec) { - int voice, cmd; - unsigned short p1, p2; - unsigned int plong; - unsigned flags; + int voice, cmd; + unsigned short p1, p2; + unsigned int plong; + unsigned flags; cmd = event_rec[2]; voice = event_rec[3]; @@ -2001,156 +1965,152 @@ plong = *(unsigned int *) &event_rec[4]; if ((voices[voice].volume_irq_mode == VMODE_START_NOTE) && - (cmd != _GUS_VOICESAMPLE) && (cmd != _GUS_VOICE_POS)) + (cmd != _GUS_VOICESAMPLE) && (cmd != _GUS_VOICE_POS)) do_volume_irq(voice); switch (cmd) - { + { + case _GUS_NUMVOICES: + save_flags(flags); + cli(); + gus_select_voice(voice); + gus_select_max_voices(p1); + restore_flags(flags); + break; + + case _GUS_VOICESAMPLE: + guswave_set_instr(dev, voice, p1); + break; - case _GUS_NUMVOICES: - save_flags(flags); - cli(); - gus_select_voice(voice); - gus_select_max_voices(p1); - restore_flags(flags); - break; - - case _GUS_VOICESAMPLE: - guswave_set_instr(dev, voice, p1); - break; - - case _GUS_VOICEON: - save_flags(flags); - cli(); - gus_select_voice(voice); - p1 &= ~0x20; /* Don't allow interrupts */ - gus_voice_on(p1); - restore_flags(flags); - break; - - case _GUS_VOICEOFF: - save_flags(flags); - cli(); - gus_select_voice(voice); - gus_voice_off(); - restore_flags(flags); - break; - - case _GUS_VOICEFADE: - gus_voice_fade(voice); - break; - - case _GUS_VOICEMODE: - save_flags(flags); - cli(); - gus_select_voice(voice); - p1 &= ~0x20; /* Don't allow interrupts */ - gus_voice_mode(p1); - restore_flags(flags); - break; - - case _GUS_VOICEBALA: - save_flags(flags); - cli(); - gus_select_voice(voice); - gus_voice_balance(p1); - restore_flags(flags); - break; - - case _GUS_VOICEFREQ: - save_flags(flags); - cli(); - gus_select_voice(voice); - gus_voice_freq(plong); - restore_flags(flags); - break; - - case _GUS_VOICEVOL: - save_flags(flags); - cli(); - gus_select_voice(voice); - gus_voice_volume(p1); - restore_flags(flags); - break; - - case _GUS_VOICEVOL2: /* Just update the software voice level */ - voices[voice].initial_volume = - voices[voice].current_volume = p1; - break; - - case _GUS_RAMPRANGE: - if (voices[voice].mode & WAVE_ENVELOPES) - break; /* NO-NO */ - save_flags(flags); - cli(); - gus_select_voice(voice); - gus_ramp_range(p1, p2); - restore_flags(flags); - break; - - case _GUS_RAMPRATE: - if (voices[voice].mode & WAVE_ENVELOPES) - break; /* NJET-NJET */ - save_flags(flags); - cli(); - gus_select_voice(voice); - gus_ramp_rate(p1, p2); - restore_flags(flags); - break; - - case _GUS_RAMPMODE: - if (voices[voice].mode & WAVE_ENVELOPES) - break; /* NO-NO */ - save_flags(flags); - cli(); - gus_select_voice(voice); - p1 &= ~0x20; /* Don't allow interrupts */ - gus_ramp_mode(p1); - restore_flags(flags); - break; - - case _GUS_RAMPON: - if (voices[voice].mode & WAVE_ENVELOPES) - break; /* EI-EI */ - save_flags(flags); - cli(); - gus_select_voice(voice); - p1 &= ~0x20; /* Don't allow interrupts */ - gus_rampon(p1); - restore_flags(flags); - break; - - case _GUS_RAMPOFF: - if (voices[voice].mode & WAVE_ENVELOPES) - break; /* NEJ-NEJ */ - save_flags(flags); - cli(); - gus_select_voice(voice); - gus_rampoff(); - restore_flags(flags); - break; - - case _GUS_VOLUME_SCALE: - volume_base = p1; - volume_scale = p2; - break; - - case _GUS_VOICE_POS: - save_flags(flags); - cli(); - gus_select_voice(voice); - gus_set_voice_pos(voice, plong); - restore_flags(flags); - break; + case _GUS_VOICEON: + save_flags(flags); + cli(); + gus_select_voice(voice); + p1 &= ~0x20; /* Don't allow interrupts */ + gus_voice_on(p1); + restore_flags(flags); + break; - default:; - } + case _GUS_VOICEOFF: + save_flags(flags); + cli(); + gus_select_voice(voice); + gus_voice_off(); + restore_flags(flags); + break; + + case _GUS_VOICEFADE: + gus_voice_fade(voice); + break; + + case _GUS_VOICEMODE: + save_flags(flags); + cli(); + gus_select_voice(voice); + p1 &= ~0x20; /* Don't allow interrupts */ + gus_voice_mode(p1); + restore_flags(flags); + break; + + case _GUS_VOICEBALA: + save_flags(flags); + cli(); + gus_select_voice(voice); + gus_voice_balance(p1); + restore_flags(flags); + break; + + case _GUS_VOICEFREQ: + save_flags(flags); + cli(); + gus_select_voice(voice); + gus_voice_freq(plong); + restore_flags(flags); + break; + + case _GUS_VOICEVOL: + save_flags(flags); + cli(); + gus_select_voice(voice); + gus_voice_volume(p1); + restore_flags(flags); + break; + + case _GUS_VOICEVOL2: /* Just update the software voice level */ + voices[voice].initial_volume = voices[voice].current_volume = p1; + break; + + case _GUS_RAMPRANGE: + if (voices[voice].mode & WAVE_ENVELOPES) + break; /* NO-NO */ + save_flags(flags); + cli(); + gus_select_voice(voice); + gus_ramp_range(p1, p2); + restore_flags(flags); + break; + + case _GUS_RAMPRATE: + if (voices[voice].mode & WAVE_ENVELOPES) + break; /* NJET-NJET */ + save_flags(flags); + cli(); + gus_select_voice(voice); + gus_ramp_rate(p1, p2); + restore_flags(flags); + break; + + case _GUS_RAMPMODE: + if (voices[voice].mode & WAVE_ENVELOPES) + break; /* NO-NO */ + save_flags(flags); + cli(); + gus_select_voice(voice); + p1 &= ~0x20; /* Don't allow interrupts */ + gus_ramp_mode(p1); + restore_flags(flags); + break; + + case _GUS_RAMPON: + if (voices[voice].mode & WAVE_ENVELOPES) + break; /* EI-EI */ + save_flags(flags); + cli(); + gus_select_voice(voice); + p1 &= ~0x20; /* Don't allow interrupts */ + gus_rampon(p1); + restore_flags(flags); + break; + + case _GUS_RAMPOFF: + if (voices[voice].mode & WAVE_ENVELOPES) + break; /* NEJ-NEJ */ + save_flags(flags); + cli(); + gus_select_voice(voice); + gus_rampoff(); + restore_flags(flags); + break; + + case _GUS_VOLUME_SCALE: + volume_base = p1; + volume_scale = p2; + break; + + case _GUS_VOICE_POS: + save_flags(flags); + cli(); + gus_select_voice(voice); + gus_set_voice_pos(voice, plong); + restore_flags(flags); + break; + + default: + } } -static int -gus_audio_set_speed(int speed) +static int gus_audio_set_speed(int speed) { - if (speed <= 0) speed = gus_audio_speed; @@ -2163,18 +2123,17 @@ gus_audio_speed = speed; if (only_read_access) - { - /* Compute nearest valid recording speed and return it */ + { + /* Compute nearest valid recording speed and return it */ - /* speed = (9878400 / (gus_audio_speed + 2)) / 16; */ - speed = (((9878400 + gus_audio_speed / 2) / (gus_audio_speed + 2)) + 8) / 16; - speed = (9878400 / (speed * 16)) - 2; - } + /* speed = (9878400 / (gus_audio_speed + 2)) / 16; */ + speed = (((9878400 + gus_audio_speed / 2) / (gus_audio_speed + 2)) + 8) / 16; + speed = (9878400 / (speed * 16)) - 2; + } return speed; } -static int -gus_audio_set_channels(int channels) +static int gus_audio_set_channels(int channels) { if (!channels) return gus_audio_channels; @@ -2186,8 +2145,7 @@ return channels; } -static int -gus_audio_set_bits(int bits) +static int gus_audio_set_bits(int bits) { if (!bits) return gus_audio_bits; @@ -2206,70 +2164,75 @@ { int val; - switch (cmd) { - case SOUND_PCM_WRITE_RATE: - if (__get_user(val, (int *)arg)) - return -EFAULT; - val = gus_audio_set_speed(val); - return __put_user(val, (int *)arg); + switch (cmd) + { + case SOUND_PCM_WRITE_RATE: + if (get_user(val, (int *)arg)) + return -EFAULT; + val = gus_audio_set_speed(val); + break; - case SOUND_PCM_READ_RATE: - return __put_user(gus_audio_speed, (int *)arg); + case SOUND_PCM_READ_RATE: + val = gus_audio_speed; + break; - case SNDCTL_DSP_STEREO: - if (__get_user(val, (int *)arg)) - return -EFAULT; - val = gus_audio_set_channels(val + 1) - 1; - return __put_user(val, (int *)arg); + case SNDCTL_DSP_STEREO: + if (get_user(val, (int *)arg)) + return -EFAULT; + val = gus_audio_set_channels(val + 1) - 1; + break; - case SOUND_PCM_WRITE_CHANNELS: - if (__get_user(val, (int *)arg)) - return -EFAULT; - val = gus_audio_set_channels(val); - return __put_user(val, (int *)arg); + case SOUND_PCM_WRITE_CHANNELS: + if (get_user(val, (int *)arg)) + return -EFAULT; + val = gus_audio_set_channels(val); + break; - case SOUND_PCM_READ_CHANNELS: - return __put_user(gus_audio_channels, (int *)arg); + case SOUND_PCM_READ_CHANNELS: + val = gus_audio_channels; + break; - case SNDCTL_DSP_SETFMT: - if (__get_user(val, (int *)arg)) - return -EFAULT; - val = gus_audio_set_bits(val); - return __put_user(val, (int *)arg); + case SNDCTL_DSP_SETFMT: + if (get_user(val, (int *)arg)) + return -EFAULT; + val = gus_audio_set_bits(val); + break; - case SOUND_PCM_READ_BITS: - return __put_user(gus_audio_bits, (int *)arg); + case SOUND_PCM_READ_BITS: + val = gus_audio_bits; + break; - case SOUND_PCM_WRITE_FILTER: /* NOT POSSIBLE */ - case SOUND_PCM_READ_FILTER: - return __put_user(-EINVAL, (int *)arg); + case SOUND_PCM_WRITE_FILTER: /* NOT POSSIBLE */ + case SOUND_PCM_READ_FILTER: + val = -EINVAL; + break; + default: + return -EINVAL; } - return -EINVAL; + return put_user(val, (int *)arg); } -static void -gus_audio_reset(int dev) +static void gus_audio_reset(int dev) { if (recording_active) - { - gus_write8(0x49, 0x00); /* Halt recording */ - set_input_volumes(); - } + { + gus_write8(0x49, 0x00); /* Halt recording */ + set_input_volumes(); + } } -static int saved_iw_mode; /* A hack hack hack */ +static int saved_iw_mode; /* A hack hack hack */ -static int -gus_audio_open(int dev, int mode) +static int gus_audio_open(int dev, int mode) { if (gus_busy) return -EBUSY; if (gus_pnp_flag && mode & OPEN_READ) - { - printk("GUS: Audio device #%d is playback only.\n", dev); - return -EIO; - } + { +/* printk(KERN_ERR "GUS: Audio device #%d is playback only.\n", dev);*/ + return -EIO; + } gus_initialize(); gus_busy = 1; @@ -2280,19 +2243,19 @@ gus_select_max_voices(14); saved_iw_mode = iw_mode; if (iw_mode) - { - /* There are some problems with audio in enhanced mode so disable it */ - gus_write8(0x19, gus_read8(0x19) & ~0x01); /* Disable enhanced mode */ - iw_mode = 0; - } + { + /* There are some problems with audio in enhanced mode so disable it */ + gus_write8(0x19, gus_read8(0x19) & ~0x01); /* Disable enhanced mode */ + iw_mode = 0; + } pcm_active = 0; dma_active = 0; pcm_opened = 1; if (mode & OPEN_READ) - { - recording_active = 1; - set_input_volumes(); - } + { + recording_active = 1; + set_input_volumes(); + } only_read_access = !(mode & OPEN_WRITE); only_8_bits = mode & OPEN_READ; if (only_8_bits) @@ -2303,8 +2266,7 @@ return 0; } -static void -gus_audio_close(int dev) +static void gus_audio_close(int dev) { iw_mode = saved_iw_mode; gus_reset(); @@ -2313,40 +2275,38 @@ active_device = 0; if (recording_active) - { - gus_write8(0x49, 0x00); /* Halt recording */ - set_input_volumes(); - } + { + gus_write8(0x49, 0x00); /* Halt recording */ + set_input_volumes(); + } recording_active = 0; } -static void -gus_audio_update_volume(void) +static void gus_audio_update_volume(void) { - unsigned long flags; - int voice; + unsigned long flags; + int voice; if (pcm_active && pcm_opened) for (voice = 0; voice < gus_audio_channels; voice++) - { - save_flags(flags); - cli(); - gus_select_voice(voice); - gus_rampoff(); - gus_voice_volume(1530 + (25 * gus_pcm_volume)); - gus_ramp_range(65, 1530 + (25 * gus_pcm_volume)); - restore_flags(flags); - } + { + save_flags(flags); + cli(); + gus_select_voice(voice); + gus_rampoff(); + gus_voice_volume(1530 + (25 * gus_pcm_volume)); + gus_ramp_range(65, 1530 + (25 * gus_pcm_volume)); + restore_flags(flags); + } } -static void -play_next_pcm_block(void) +static void play_next_pcm_block(void) { - unsigned long flags; - int speed = gus_audio_speed; - int this_one, is16bits, chn; - unsigned long dram_loc; - unsigned char mode[2], ramp_mode[2]; + unsigned long flags; + int speed = gus_audio_speed; + int this_one, is16bits, chn; + unsigned long dram_loc; + unsigned char mode[2], ramp_mode[2]; if (!pcm_qlen) return; @@ -2354,95 +2314,91 @@ this_one = pcm_head; for (chn = 0; chn < gus_audio_channels; chn++) - { - mode[chn] = 0x00; - ramp_mode[chn] = 0x03; /* Ramping and rollover off */ - - if (chn == 0) - { - mode[chn] |= 0x20; /* Loop IRQ */ - voices[chn].loop_irq_mode = LMODE_PCM; - } - if (gus_audio_bits != 8) - { - is16bits = 1; - mode[chn] |= 0x04; /* 16 bit data */ - } else - is16bits = 0; - - dram_loc = this_one * pcm_bsize; - dram_loc += chn * pcm_banksize; - - if (this_one == (pcm_nblk - 1)) /* Last fragment of the DRAM buffer */ - { - mode[chn] |= 0x08; /* Enable loop */ - ramp_mode[chn] = 0x03; /* Disable rollover bit */ - } else - { - if (chn == 0) - ramp_mode[chn] = 0x04; /* Enable rollover bit */ - } - - save_flags(flags); - cli(); - gus_select_voice(chn); - gus_voice_freq(speed); - - if (gus_audio_channels == 1) - gus_voice_balance(7); /* mono */ - else if (chn == 0) - gus_voice_balance(0); /* left */ - else - gus_voice_balance(15); /* right */ - - if (!pcm_active) /* Playback not already active */ - { - /* - * The playback was not started yet (or there has been a pause). - * Start the voice (again) and ask for a rollover irq at the end of - * this_one block. If this_one one is last of the buffers, use just - * the normal loop with irq. - */ - - gus_voice_off(); - gus_rampoff(); - gus_voice_volume(1530 + (25 * gus_pcm_volume)); - gus_ramp_range(65, 1530 + (25 * gus_pcm_volume)); + { + mode[chn] = 0x00; + ramp_mode[chn] = 0x03; /* Ramping and rollover off */ - gus_write_addr(0x0a, chn * pcm_banksize, 0, is16bits); /* Starting position */ - gus_write_addr(0x02, chn * pcm_banksize, 0, is16bits); /* Loop start */ + if (chn == 0) + { + mode[chn] |= 0x20; /* Loop IRQ */ + voices[chn].loop_irq_mode = LMODE_PCM; + } + if (gus_audio_bits != 8) + { + is16bits = 1; + mode[chn] |= 0x04; /* 16 bit data */ + } + else + is16bits = 0; - if (chn != 0) - gus_write_addr(0x04, pcm_banksize + (pcm_bsize * pcm_nblk) - 1, - 0, is16bits); /* Loop end location */ - } - if (chn == 0) - gus_write_addr(0x04, dram_loc + pcm_bsize - 1, - 0, is16bits); /* Loop end location */ - else - mode[chn] |= 0x08; /* Enable looping */ + dram_loc = this_one * pcm_bsize; + dram_loc += chn * pcm_banksize; + if (this_one == (pcm_nblk - 1)) /* Last fragment of the DRAM buffer */ + { + mode[chn] |= 0x08; /* Enable loop */ + ramp_mode[chn] = 0x03; /* Disable rollover bit */ + } + else + { + if (chn == 0) + ramp_mode[chn] = 0x04; /* Enable rollover bit */ + } + save_flags(flags); + cli(); + gus_select_voice(chn); + gus_voice_freq(speed); + + if (gus_audio_channels == 1) + gus_voice_balance(7); /* mono */ + else if (chn == 0) + gus_voice_balance(0); /* left */ + else + gus_voice_balance(15); /* right */ - restore_flags(flags); - } + if (!pcm_active) /* Playback not already active */ + { + /* + * The playback was not started yet (or there has been a pause). + * Start the voice (again) and ask for a rollover irq at the end of + * this_one block. If this_one one is last of the buffers, use just + * the normal loop with irq. + */ + + gus_voice_off(); + gus_rampoff(); + gus_voice_volume(1530 + (25 * gus_pcm_volume)); + gus_ramp_range(65, 1530 + (25 * gus_pcm_volume)); - for (chn = 0; chn < gus_audio_channels; chn++) - { - save_flags(flags); - cli(); - gus_select_voice(chn); - gus_write8(0x0d, ramp_mode[chn]); - if (iw_mode) - gus_write8(0x15, 0x00); /* Reset voice deactivate bit of SMSI */ - gus_voice_on(mode[chn]); - restore_flags(flags); - } + gus_write_addr(0x0a, chn * pcm_banksize, 0, is16bits); /* Starting position */ + gus_write_addr(0x02, chn * pcm_banksize, 0, is16bits); /* Loop start */ + if (chn != 0) + gus_write_addr(0x04, pcm_banksize + (pcm_bsize * pcm_nblk) - 1, + 0, is16bits); /* Loop end location */ + } + if (chn == 0) + gus_write_addr(0x04, dram_loc + pcm_bsize - 1, + 0, is16bits); /* Loop end location */ + else + mode[chn] |= 0x08; /* Enable looping */ + restore_flags(flags); + } + for (chn = 0; chn < gus_audio_channels; chn++) + { + save_flags(flags); + cli(); + gus_select_voice(chn); + gus_write8(0x0d, ramp_mode[chn]); + if (iw_mode) + gus_write8(0x15, 0x00); /* Reset voice deactivate bit of SMSI */ + gus_voice_on(mode[chn]); + restore_flags(flags); + } pcm_active = 1; } -static void -gus_transfer_output_block(int dev, unsigned long buf, +static void gus_transfer_output_block(int dev, unsigned long buf, int total_count, int intrflag, int chn) { /* @@ -2454,10 +2410,10 @@ * right data to the area pointed by gus_page_size. */ - int this_one, count; - unsigned long flags; - unsigned char dma_command; - unsigned long address, hold_address; + int this_one, count; + unsigned long flags; + unsigned char dma_command; + unsigned long address, hold_address; save_flags(flags); cli(); @@ -2465,15 +2421,16 @@ count = total_count / gus_audio_channels; if (chn == 0) - { - if (pcm_qlen >= pcm_nblk) - printk("GUS Warning: PCM buffers out of sync\n"); - - this_one = pcm_current_block = pcm_tail; - pcm_qlen++; - pcm_tail = (pcm_tail + 1) % pcm_nblk; - pcm_datasize[this_one] = count; - } else + { + if (pcm_qlen >= pcm_nblk) + printk(KERN_WARNING "GUS Warning: PCM buffers out of sync\n"); + + this_one = pcm_current_block = pcm_tail; + pcm_qlen++; + pcm_tail = (pcm_tail + 1) % pcm_nblk; + pcm_datasize[this_one] = count; + } + else this_one = pcm_current_block; gus_write8(0x41, 0); /* Disable GF1 DMA */ @@ -2483,12 +2440,12 @@ address += chn * pcm_banksize; if (audio_devs[dev]->dmap_out->dma > 3) - { - hold_address = address; - address = address >> 1; - address &= 0x0001ffffL; - address |= (hold_address & 0x000c0000L); - } + { + hold_address = address; + address = address >> 1; + address &= 0x0001ffffL; + address |= (hold_address & 0x000c0000L); + } gus_write16(0x42, (address >> 4) & 0xffff); /* DRAM DMA address */ dma_command = 0x21; /* IRQ enable, DMA start */ @@ -2504,62 +2461,60 @@ gus_write8(0x41, dma_command); /* Kick start */ if (chn == (gus_audio_channels - 1)) /* Last channel */ - { - /* - * Last (right or mono) channel data - */ - dma_active = 1; /* DMA started. There is a unacknowledged buffer */ - active_device = GUS_DEV_PCM_DONE; - if (!pcm_active && (pcm_qlen > 1 || count < pcm_bsize)) - { - play_next_pcm_block(); - } - } else - { - /* - * Left channel data. The right channel - * is transferred after DMA interrupt - */ - active_device = GUS_DEV_PCM_CONTINUE; - } + { + /* + * Last (right or mono) channel data + */ + dma_active = 1; /* DMA started. There is a unacknowledged buffer */ + active_device = GUS_DEV_PCM_DONE; + if (!pcm_active && (pcm_qlen > 1 || count < pcm_bsize)) + { + play_next_pcm_block(); + } + } + else + { + /* + * Left channel data. The right channel + * is transferred after DMA interrupt + */ + active_device = GUS_DEV_PCM_CONTINUE; + } restore_flags(flags); } -static void -gus_uninterleave8(char *buf, int l) +static void gus_uninterleave8(char *buf, int l) { /* This routine uninterleaves 8 bit stereo output (LRLRLR->LLLRRR) */ - int i, p = 0, halfsize = l / 2; - char *buf2 = buf + halfsize, *src = bounce_buf; + int i, p = 0, halfsize = l / 2; + char *buf2 = buf + halfsize, *src = bounce_buf; memcpy(bounce_buf, buf, l); for (i = 0; i < halfsize; i++) - { - buf[i] = src[p++]; /* Left channel */ - buf2[i] = src[p++]; /* Right channel */ - } + { + buf[i] = src[p++]; /* Left channel */ + buf2[i] = src[p++]; /* Right channel */ + } } -static void -gus_uninterleave16(short *buf, int l) +static void gus_uninterleave16(short *buf, int l) { /* This routine uninterleaves 16 bit stereo output (LRLRLR->LLLRRR) */ - int i, p = 0, halfsize = l / 2; - short *buf2 = buf + halfsize, *src = (short *) bounce_buf; + int i, p = 0, halfsize = l / 2; + short *buf2 = buf + halfsize, *src = (short *) bounce_buf; memcpy(bounce_buf, (char *) buf, l * 2); for (i = 0; i < halfsize; i++) - { - buf[i] = src[p++]; /* Left channel */ - buf2[i] = src[p++]; /* Right channel */ - } + { + buf[i] = src[p++]; /* Left channel */ + buf2[i] = src[p++]; /* Right channel */ + } } -static void -gus_audio_output_block(int dev, unsigned long buf, int total_count, +static void gus_audio_output_block(int dev, unsigned long buf, int total_count, int intrflag) { struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; @@ -2571,29 +2526,27 @@ pcm_current_intrflag = intrflag; pcm_current_dev = dev; if (gus_audio_channels == 2) - { - char *b = dmap->raw_buf + (buf - dmap->raw_buf_phys); + { + char *b = dmap->raw_buf + (buf - dmap->raw_buf_phys); - if (gus_audio_bits == 8) - gus_uninterleave8(b, total_count); - else - gus_uninterleave16((short *) b, total_count / 2); - } + if (gus_audio_bits == 8) + gus_uninterleave8(b, total_count); + else + gus_uninterleave16((short *) b, total_count / 2); + } gus_transfer_output_block(dev, buf, total_count, intrflag, 0); } -static void -gus_audio_start_input(int dev, unsigned long buf, int count, +static void gus_audio_start_input(int dev, unsigned long buf, int count, int intrflag) { - unsigned long flags; - unsigned char mode; + unsigned long flags; + unsigned char mode; save_flags(flags); cli(); DMAbuf_start_dma(dev, buf, count, DMA_MODE_READ); - mode = 0xa0; /* DMA IRQ enabled, invert MSB */ if (audio_devs[dev]->dmap_in->dma > 3) @@ -2603,14 +2556,12 @@ mode |= 0x01; /* DMA enable */ gus_write8(0x49, mode); - restore_flags(flags); } -static int -gus_audio_prepare_for_input(int dev, int bsize, int bcount) +static int gus_audio_prepare_for_input(int dev, int bsize, int bcount) { - unsigned int rate; + unsigned int rate; gus_audio_bsize = bsize; audio_devs[dev]->dmap_in->flags |= DMA_NODMA; @@ -2619,19 +2570,18 @@ gus_write8(0x48, rate & 0xff); /* Set sampling rate */ if (gus_audio_bits != 8) - { - printk("GUS Error: 16 bit recording not supported\n"); - return -EINVAL; - } + { +/* printk("GUS Error: 16 bit recording not supported\n");*/ + return -EINVAL; + } return 0; } -static int -gus_audio_prepare_for_output(int dev, int bsize, int bcount) +static int gus_audio_prepare_for_output(int dev, int bsize, int bcount) { - int i; + int i; - long mem_ptr, mem_size; + long mem_ptr, mem_size; audio_devs[dev]->dmap_out->flags |= DMA_NODMA | DMA_NOTIMEOUT; mem_ptr = 0; @@ -2655,12 +2605,10 @@ if (gus_audio_bits != 8 && pcm_banksize == (256 * 1024)) pcm_nblk--; gus_write8(0x41, 0); /* Disable GF1 DMA */ - return 0; } -static int -gus_local_qlen(int dev) +static int gus_local_qlen(int dev) { return pcm_qlen; } @@ -2680,20 +2628,14 @@ NULL }; -static void -guswave_setup_voice(int dev, int voice, int chn) +static void guswave_setup_voice(int dev, int voice, int chn) { - struct channel_info *info = - &synth_devs[dev]->chn_info[chn]; + struct channel_info *info = &synth_devs[dev]->chn_info[chn]; guswave_set_instr(dev, voice, info->pgm_num); - - voices[voice].expression_vol = - info->controllers[CTL_EXPRESSION]; /* Just MSB */ - voices[voice].main_vol = - (info->controllers[CTL_MAIN_VOLUME] * 100) / (unsigned) 128; - voices[voice].panning = - (info->controllers[CTL_PAN] * 2) - 128; + voices[voice].expression_vol = info->controllers[CTL_EXPRESSION]; /* Just MSB */ + voices[voice].main_vol = (info->controllers[CTL_MAIN_VOLUME] * 100) / (unsigned) 128; + voices[voice].panning = (info->controllers[CTL_PAN] * 2) - 128; voices[voice].bender = 0; voices[voice].bender_range = info->bender_range; @@ -2701,15 +2643,13 @@ voices[voice].fixed_pitch = 1; } -static void -guswave_bender(int dev, int voice, int value) +static void guswave_bender(int dev, int voice, int value) { - int freq; + int freq; unsigned long flags; voices[voice].bender = value - 8192; - freq = compute_finetune(voices[voice].orig_freq, value - 8192, - voices[voice].bender_range, 0); + freq = compute_finetune(voices[voice].orig_freq, value - 8192, voices[voice].bender_range, 0); voices[voice].current_freq = freq; save_flags(flags); @@ -2719,45 +2659,43 @@ restore_flags(flags); } -static int -guswave_alloc(int dev, int chn, int note, struct voice_alloc_info *alloc) +static int guswave_alloc(int dev, int chn, int note, struct voice_alloc_info *alloc) { - int i, p, best = -1, best_time = 0x7fffffff; + int i, p, best = -1, best_time = 0x7fffffff; p = alloc->ptr; /* - * First look for a completely stopped voice + * First look for a completely stopped voice */ for (i = 0; i < alloc->max_voice; i++) - { - if (alloc->map[p] == 0) - { - alloc->ptr = p; - return p; - } - if (alloc->alloc_times[p] < best_time) - { - best = p; - best_time = alloc->alloc_times[p]; - } - p = (p + 1) % alloc->max_voice; - } + { + if (alloc->map[p] == 0) + { + alloc->ptr = p; + return p; + } + if (alloc->alloc_times[p] < best_time) + { + best = p; + best_time = alloc->alloc_times[p]; + } + p = (p + 1) % alloc->max_voice; + } /* - * Then look for a releasing voice + * Then look for a releasing voice */ for (i = 0; i < alloc->max_voice; i++) - { - if (alloc->map[p] == 0xffff) - { - alloc->ptr = p; - return p; - } - p = (p + 1) % alloc->max_voice; - } - + { + if (alloc->map[p] == 0xffff) + { + alloc->ptr = p; + return p; + } + p = (p + 1) % alloc->max_voice; + } if (best >= 0) p = best; @@ -2790,11 +2728,10 @@ guswave_setup_voice }; -static void -set_input_volumes(void) +static void set_input_volumes(void) { - unsigned long flags; - unsigned char mask = 0xff & ~0x06; /* Just line out enabled */ + unsigned long flags; + unsigned char mask = 0xff & ~0x06; /* Just line out enabled */ if (have_gus_max) /* Don't disturb GUS MAX */ return; @@ -2813,15 +2750,15 @@ mask |= 0x04; if (recording_active) - { - /* - * Disable channel, if not selected for recording - */ - if (!(gus_recmask & SOUND_MASK_LINE)) - mask |= 0x01; - if (!(gus_recmask & SOUND_MASK_MIC)) - mask &= ~0x04; - } + { + /* + * Disable channel, if not selected for recording + */ + if (!(gus_recmask & SOUND_MASK_LINE)) + mask |= 0x01; + if (!(gus_recmask & SOUND_MASK_MIC)) + mask &= ~0x04; + } mix_image &= ~0x07; mix_image |= mask & 0x07; outb((mix_image), u_Mixer); @@ -2842,115 +2779,119 @@ if (!access_ok(VERIFY_WRITE, (int *)arg, sizeof(int))) return -EFAULT; - if (_SIOC_DIR(cmd) & _SIOC_WRITE) { + if (_SIOC_DIR(cmd) & _SIOC_WRITE) + { if (__get_user(val, (int *) arg)) return -EFAULT; - switch (cmd & 0xff) { - case SOUND_MIXER_RECSRC: - gus_recmask = val & MIX_DEVS; - if (!(gus_recmask & (SOUND_MASK_MIC | SOUND_MASK_LINE))) - gus_recmask = SOUND_MASK_MIC; - /* Note! Input volumes are updated during next open for recording */ - val = gus_recmask; - break; - - case SOUND_MIXER_MIC: - vol = val & 0xff; - if (vol < 0) - vol = 0; - if (vol > 100) - vol = 100; - gus_mic_vol = vol; - set_input_volumes(); - val = vol | (vol << 8); - break; + switch (cmd & 0xff) + { + case SOUND_MIXER_RECSRC: + gus_recmask = val & MIX_DEVS; + if (!(gus_recmask & (SOUND_MASK_MIC | SOUND_MASK_LINE))) + gus_recmask = SOUND_MASK_MIC; + /* Note! Input volumes are updated during next open for recording */ + val = gus_recmask; + break; + + case SOUND_MIXER_MIC: + vol = val & 0xff; + if (vol < 0) + vol = 0; + if (vol > 100) + vol = 100; + gus_mic_vol = vol; + set_input_volumes(); + val = vol | (vol << 8); + break; - case SOUND_MIXER_LINE: - vol = val & 0xff; - if (vol < 0) - vol = 0; - if (vol > 100) - vol = 100; - gus_line_vol = vol; - set_input_volumes(); - val = vol | (vol << 8); - break; - - case SOUND_MIXER_PCM: - gus_pcm_volume = val & 0xff; - if (gus_pcm_volume < 0) - gus_pcm_volume = 0; - if (gus_pcm_volume > 100) - gus_pcm_volume = 100; - gus_audio_update_volume(); - val = gus_pcm_volume | (gus_pcm_volume << 8); - break; - - case SOUND_MIXER_SYNTH: - gus_wave_volume = val & 0xff; - if (gus_wave_volume < 0) - gus_wave_volume = 0; - if (gus_wave_volume > 100) - gus_wave_volume = 100; - if (active_device == GUS_DEV_WAVE) { - int voice; - for (voice = 0; voice < nr_voices; voice++) + case SOUND_MIXER_LINE: + vol = val & 0xff; + if (vol < 0) + vol = 0; + if (vol > 100) + vol = 100; + gus_line_vol = vol; + set_input_volumes(); + val = vol | (vol << 8); + break; + + case SOUND_MIXER_PCM: + gus_pcm_volume = val & 0xff; + if (gus_pcm_volume < 0) + gus_pcm_volume = 0; + if (gus_pcm_volume > 100) + gus_pcm_volume = 100; + gus_audio_update_volume(); + val = gus_pcm_volume | (gus_pcm_volume << 8); + break; + + case SOUND_MIXER_SYNTH: + gus_wave_volume = val & 0xff; + if (gus_wave_volume < 0) + gus_wave_volume = 0; + if (gus_wave_volume > 100) + gus_wave_volume = 100; + if (active_device == GUS_DEV_WAVE) + { + int voice; + for (voice = 0; voice < nr_voices; voice++) dynamic_volume_change(voice); /* Apply the new vol */ - } - val = gus_wave_volume | (gus_wave_volume << 8); - break; + } + val = gus_wave_volume | (gus_wave_volume << 8); + break; - default: - return -EINVAL; + default: + return -EINVAL; } - - } else { - switch (cmd & 0xff) { - /* - * Return parameters - */ - case SOUND_MIXER_RECSRC: - val = gus_recmask; - break; + } + else + { + switch (cmd & 0xff) + { + /* + * Return parameters + */ + case SOUND_MIXER_RECSRC: + val = gus_recmask; + break; - case SOUND_MIXER_DEVMASK: - val = MIX_DEVS; - break; - - case SOUND_MIXER_STEREODEVS: - val = 0; - break; - - case SOUND_MIXER_RECMASK: - val = SOUND_MASK_MIC | SOUND_MASK_LINE; - break; - - case SOUND_MIXER_CAPS: - val = 0; - break; - - case SOUND_MIXER_MIC: - val = gus_mic_vol | (gus_mic_vol << 8); - break; - - case SOUND_MIXER_LINE: - val = gus_line_vol | (gus_line_vol << 8); - break; + case SOUND_MIXER_DEVMASK: + val = MIX_DEVS; + break; + + case SOUND_MIXER_STEREODEVS: + val = 0; + break; + + case SOUND_MIXER_RECMASK: + val = SOUND_MASK_MIC | SOUND_MASK_LINE; + break; + + case SOUND_MIXER_CAPS: + val = 0; + break; + + case SOUND_MIXER_MIC: + val = gus_mic_vol | (gus_mic_vol << 8); + break; + + case SOUND_MIXER_LINE: + val = gus_line_vol | (gus_line_vol << 8); + break; + + case SOUND_MIXER_PCM: + val = gus_pcm_volume | (gus_pcm_volume << 8); + break; + + case SOUND_MIXER_SYNTH: + val = gus_wave_volume | (gus_wave_volume << 8); + break; - case SOUND_MIXER_PCM: - val = gus_pcm_volume | (gus_pcm_volume << 8); - break; - - case SOUND_MIXER_SYNTH: - val = gus_wave_volume | (gus_wave_volume << 8); - break; - - default: - return -EINVAL; + default: + return -EINVAL; } } - return __put_user(val, (int *)arg); } @@ -2961,43 +2902,42 @@ gus_default_mixer_ioctl }; -static int -gus_default_mixer_init(void) +static int gus_default_mixer_init(void) { - int n; + int n; if ((n = sound_alloc_mixerdev()) != -1) - { /* - * Don't install if there is another - * mixer - */ - mixer_devs[n] = &gus_mixer_operations; - } + { + /* + * Don't install if there is another + * mixer + */ + mixer_devs[n] = &gus_mixer_operations; + } if (have_gus_max) - { -/* - * Enable all mixer channels on the GF1 side. Otherwise recording will - * not be possible using GUS MAX. - */ - mix_image &= ~0x07; - mix_image |= 0x04; /* All channels enabled */ - outb((mix_image), u_Mixer); - } + { + /* + * Enable all mixer channels on the GF1 side. Otherwise recording will + * not be possible using GUS MAX. + */ + mix_image &= ~0x07; + mix_image |= 0x04; /* All channels enabled */ + outb((mix_image), u_Mixer); + } return n; } void gus_wave_init(struct address_info *hw_config) { - unsigned long flags; - unsigned char val; - char *model_num = "2.4"; - char tmp[64], tmp2[64]; - int gus_type = 0x24; /* 2.4 */ - - int irq = hw_config->irq, dma = hw_config->dma, - dma2 = hw_config->dma2; - int dev; - int sdev; + unsigned long flags; + unsigned char val; + char *model_num = "2.4"; + char tmp[64], tmp2[64]; + int gus_type = 0x24; /* 2.4 */ + + int irq = hw_config->irq, dma = hw_config->dma, dma2 = hw_config->dma2; + int dev; + int sdev; hw_config->slots[0] = -1; /* No wave */ hw_config->slots[1] = -1; /* No ad1848 */ @@ -3008,14 +2948,14 @@ { if (irq < 0 || irq > 15) { - printk("ERROR! Invalid IRQ#%d. GUS Disabled", irq); + printk(KERN_ERR "ERROR! Invalid IRQ#%d. GUS Disabled", irq); return; } } if (dma < 0 || dma > 7 || dma == 4) { - printk("ERROR! Invalid DMA#%d. GUS Disabled", dma); + printk(KERN_ERR "ERROR! Invalid DMA#%d. GUS Disabled", dma); return; } gus_irq = irq; @@ -3046,7 +2986,7 @@ /* * It has the digital ASIC so the card is at least v3.4. * Next try to detect the true model. - */ + */ if (gus_pnp_flag) /* Hack hack hack */ val = 10; @@ -3124,9 +3064,9 @@ } } else - printk(KERN_WARNING "[Where's the CS4231?]"); + printk(KERN_WARNING "GUS: No CS4231 ??"); #else - printk("\n\n\nGUS MAX support was not compiled in!!!\n\n\n\n"); + printk(KERN_ERR "GUS MAX found, but not compiled in\n"); #endif } } @@ -3291,78 +3231,77 @@ parm = voices[voice].loop_irq_parm; switch (mode) - { + { + case LMODE_FINISH: /* + * Final loop finished, shoot volume down + */ - case LMODE_FINISH: /* - * Final loop finished, shoot volume down - */ + if ((int) (gus_read16(0x09) >> 4) < 100) /* + * Get current volume + */ + { + gus_voice_off(); + gus_rampoff(); + gus_voice_init(voice); + break; + } + gus_ramp_range(65, 4065); + gus_ramp_rate(0, 63); /* + * Fastest possible rate + */ + gus_rampon(0x20 | 0x40); /* + * Ramp down, once, irq + */ + voices[voice].volume_irq_mode = VMODE_HALT; + break; - if ((int) (gus_read16(0x09) >> 4) < 100) /* - * Get current volume - */ - { - gus_voice_off(); - gus_rampoff(); - gus_voice_init(voice); - break; - } - gus_ramp_range(65, 4065); - gus_ramp_rate(0, 63); /* - * Fastest possible rate - */ - gus_rampon(0x20 | 0x40); /* - * Ramp down, once, irq - */ - voices[voice].volume_irq_mode = VMODE_HALT; - break; - - case LMODE_PCM_STOP: - pcm_active = 0; /* Signal to the play_next_pcm_block routine */ - case LMODE_PCM: - { - - pcm_qlen--; - pcm_head = (pcm_head + 1) % pcm_nblk; - if (pcm_qlen && pcm_active) - { - play_next_pcm_block(); - } else - { /* Underrun. Just stop the voice */ - gus_select_voice(0); /* Left channel */ - gus_voice_off(); - gus_rampoff(); - gus_select_voice(1); /* Right channel */ - gus_voice_off(); - gus_rampoff(); - pcm_active = 0; - } - - /* - * If the queue was full before this interrupt, the DMA transfer was - * suspended. Let it continue now. - */ - if (audio_devs[gus_devnum]->dmap_out->qlen > 0) - DMAbuf_outputintr(gus_devnum, 0); - } - break; + case LMODE_PCM_STOP: + pcm_active = 0; /* Signal to the play_next_pcm_block routine */ + case LMODE_PCM: + { + pcm_qlen--; + pcm_head = (pcm_head + 1) % pcm_nblk; + if (pcm_qlen && pcm_active) + { + play_next_pcm_block(); + } + else + { + /* Underrun. Just stop the voice */ + gus_select_voice(0); /* Left channel */ + gus_voice_off(); + gus_rampoff(); + gus_select_voice(1); /* Right channel */ + gus_voice_off(); + gus_rampoff(); + pcm_active = 0; + } - default:; - } + /* + * If the queue was full before this interrupt, the DMA transfer was + * suspended. Let it continue now. + */ + + if (audio_devs[gus_devnum]->dmap_out->qlen > 0) + DMAbuf_outputintr(gus_devnum, 0); + } + break; + + default: + } restore_flags(flags); } -static void -do_volume_irq(int voice) +static void do_volume_irq(int voice) { - unsigned char tmp; - int mode, parm; - unsigned long flags; + unsigned char tmp; + int mode, parm; + unsigned long flags; save_flags(flags); cli(); gus_select_voice(voice); - tmp = gus_read8(0x0d); tmp &= ~0x20; /* * Disable volume ramp IRQ @@ -3374,138 +3313,136 @@ parm = voices[voice].volume_irq_parm; switch (mode) - { - case VMODE_HALT: /* Decay phase finished */ - if (iw_mode) - gus_write8(0x15, 0x02); /* Set voice deactivate bit of SMSI */ - restore_flags(flags); - gus_voice_init(voice); - break; - - case VMODE_ENVELOPE: - gus_rampoff(); - restore_flags(flags); - step_envelope(voice); - break; - - case VMODE_START_NOTE: - restore_flags(flags); - guswave_start_note2(voices[voice].dev_pending, voice, + { + case VMODE_HALT: /* Decay phase finished */ + if (iw_mode) + gus_write8(0x15, 0x02); /* Set voice deactivate bit of SMSI */ + restore_flags(flags); + gus_voice_init(voice); + break; + + case VMODE_ENVELOPE: + gus_rampoff(); + restore_flags(flags); + step_envelope(voice); + break; + + case VMODE_START_NOTE: + restore_flags(flags); + guswave_start_note2(voices[voice].dev_pending, voice, voices[voice].note_pending, voices[voice].volume_pending); - if (voices[voice].kill_pending) - guswave_kill_note(voices[voice].dev_pending, voice, + if (voices[voice].kill_pending) + guswave_kill_note(voices[voice].dev_pending, voice, voices[voice].note_pending, 0); - if (voices[voice].sample_pending >= 0) - { - guswave_set_instr(voices[voice].dev_pending, voice, - voices[voice].sample_pending); - voices[voice].sample_pending = -1; - } - break; + if (voices[voice].sample_pending >= 0) + { + guswave_set_instr(voices[voice].dev_pending, voice, + voices[voice].sample_pending); + voices[voice].sample_pending = -1; + } + break; - default: - restore_flags(flags); - } + default: + restore_flags(flags); + } restore_flags(flags); } -void -gus_voice_irq(void) +void gus_voice_irq(void) { - unsigned long wave_ignore = 0, volume_ignore = 0; - unsigned long voice_bit; + unsigned long wave_ignore = 0, volume_ignore = 0; + unsigned long voice_bit; - unsigned char src, voice; + unsigned char src, voice; while (1) - { - src = gus_read8(0x0f); /* - * Get source info - */ - voice = src & 0x1f; - src &= 0xc0; - - if (src == (0x80 | 0x40)) - return; /* - * No interrupt + { + src = gus_read8(0x0f); /* + * Get source info */ + voice = src & 0x1f; + src &= 0xc0; + + if (src == (0x80 | 0x40)) + return; /* + * No interrupt + */ - voice_bit = 1 << voice; + voice_bit = 1 << voice; - if (!(src & 0x80)) /* + if (!(src & 0x80)) /* * Wave IRQ pending */ - if (!(wave_ignore & voice_bit) && (int) voice < nr_voices) /* - * Not done - * yet + if (!(wave_ignore & voice_bit) && (int) voice < nr_voices) /* + * Not done + * yet */ - { - wave_ignore |= voice_bit; - do_loop_irq(voice); - } - if (!(src & 0x40)) /* + { + wave_ignore |= voice_bit; + do_loop_irq(voice); + } + if (!(src & 0x40)) /* * Volume IRQ pending */ - if (!(volume_ignore & voice_bit) && (int) voice < nr_voices) /* + if (!(volume_ignore & voice_bit) && (int) voice < nr_voices) /* * Not done * yet */ - { - volume_ignore |= voice_bit; - do_volume_irq(voice); - } - } + { + volume_ignore |= voice_bit; + do_volume_irq(voice); + } + } } -void -guswave_dma_irq(void) +void guswave_dma_irq(void) { unsigned char status; status = gus_look8(0x41); /* Get DMA IRQ Status */ if (status & 0x40) /* DMA interrupt pending */ switch (active_device) - { - case GUS_DEV_WAVE: - if ((dram_sleep_flag.opts & WK_SLEEP)) - { - dram_sleep_flag.opts = WK_WAKEUP; - wake_up(&dram_sleeper); - }; - break; - - case GUS_DEV_PCM_CONTINUE: /* Left channel data transferred */ - gus_write8(0x41, 0); /* Disable GF1 DMA */ - gus_transfer_output_block(pcm_current_dev, pcm_current_buf, - pcm_current_count, + { + case GUS_DEV_WAVE: + if ((dram_sleep_flag.opts & WK_SLEEP)) + { + dram_sleep_flag.opts = WK_WAKEUP; + wake_up(&dram_sleeper); + } + break; + + case GUS_DEV_PCM_CONTINUE: /* Left channel data transferred */ + gus_write8(0x41, 0); /* Disable GF1 DMA */ + gus_transfer_output_block(pcm_current_dev, pcm_current_buf, + pcm_current_count, pcm_current_intrflag, 1); - break; + break; - case GUS_DEV_PCM_DONE: /* Right or mono channel data transferred */ - gus_write8(0x41, 0); /* Disable GF1 DMA */ - if (pcm_qlen < pcm_nblk) - { - dma_active = 0; - if (gus_busy) - { - if (audio_devs[gus_devnum]->dmap_out->qlen > 0) - DMAbuf_outputintr(gus_devnum, 0); - } - } - break; + case GUS_DEV_PCM_DONE: /* Right or mono channel data transferred */ + gus_write8(0x41, 0); /* Disable GF1 DMA */ + if (pcm_qlen < pcm_nblk) + { + dma_active = 0; + if (gus_busy) + { + if (audio_devs[gus_devnum]->dmap_out->qlen > 0) + DMAbuf_outputintr(gus_devnum, 0); + } + } + break; - default:; - } + default: + } status = gus_look8(0x49); /* * Get Sampling IRQ Status */ if (status & 0x40) /* * Sampling Irq pending */ - { - DMAbuf_inputintr(gus_devnum); - } + { + DMAbuf_inputintr(gus_devnum); + } } #if defined(CONFIG_SEQUENCER) || defined(MODULE) @@ -3517,10 +3454,9 @@ static volatile int select_addr, data_addr; static volatile int curr_timer = 0; -void -gus_timer_command(unsigned int addr, unsigned int val) +void gus_timer_command(unsigned int addr, unsigned int val) { - int i; + int i; outb(((unsigned char) (addr & 0xff)), select_addr); @@ -3533,59 +3469,54 @@ inb(select_addr); } -static void -arm_timer(int timer, unsigned int interval) +static void arm_timer(int timer, unsigned int interval) { - curr_timer = timer; if (timer == 1) - { - gus_write8(0x46, 256 - interval); /* Set counter for timer 1 */ - gus_write8(0x45, 0x04); /* Enable timer 1 IRQ */ - gus_timer_command(0x04, 0x01); /* Start timer 1 */ - } else - { - gus_write8(0x47, 256 - interval); /* Set counter for timer 2 */ - gus_write8(0x45, 0x08); /* Enable timer 2 IRQ */ - gus_timer_command(0x04, 0x02); /* Start timer 2 */ - } + { + gus_write8(0x46, 256 - interval); /* Set counter for timer 1 */ + gus_write8(0x45, 0x04); /* Enable timer 1 IRQ */ + gus_timer_command(0x04, 0x01); /* Start timer 1 */ + } + else + { + gus_write8(0x47, 256 - interval); /* Set counter for timer 2 */ + gus_write8(0x45, 0x08); /* Enable timer 2 IRQ */ + gus_timer_command(0x04, 0x02); /* Start timer 2 */ + } gus_timer_enabled = 1; } -static unsigned int -gus_tmr_start(int dev, unsigned int usecs_per_tick) +static unsigned int gus_tmr_start(int dev, unsigned int usecs_per_tick) { - int timer_no, resolution; - int divisor; + int timer_no, resolution; + int divisor; if (usecs_per_tick > (256 * 80)) - { - timer_no = 2; - resolution = 320; /* usec */ - } else - { - timer_no = 1; - resolution = 80; /* usec */ - } - + { + timer_no = 2; + resolution = 320; /* usec */ + } + else + { + timer_no = 1; + resolution = 80; /* usec */ + } divisor = (usecs_per_tick + (resolution / 2)) / resolution; - arm_timer(timer_no, divisor); return divisor * resolution; } -static void -gus_tmr_disable(int dev) +static void gus_tmr_disable(int dev) { gus_write8(0x45, 0); /* Disable both timers */ gus_timer_enabled = 0; } -static void -gus_tmr_restart(int dev) +static void gus_tmr_restart(int dev) { if (curr_timer == 1) gus_write8(0x45, 0x04); /* Start timer 1 again */ @@ -3603,8 +3534,7 @@ gus_tmr_restart }; -static void -gus_tmr_install(int io_base) +static void gus_tmr_install(int io_base) { struct sound_lowlev_timer *tmr; diff -u --recursive --new-file v2.1.80/linux/drivers/sound/soundcard.c linux/drivers/sound/soundcard.c --- v2.1.80/linux/drivers/sound/soundcard.c Tue Jan 20 16:44:57 1998 +++ linux/drivers/sound/soundcard.c Thu Jan 22 14:46:41 1998 @@ -1101,8 +1101,7 @@ dmap->buffsize = PAGE_SIZE * (1 << sz); - start_addr = (char *) __get_free_pages(GFP_ATOMIC | GFP_DMA, sz); - if (start_addr == NULL) + if ((start_addr = (char *) __get_free_pages(GFP_ATOMIC|GFP_DMA, sz)) == NULL) dmap->buffsize /= 2; } diff -u --recursive --new-file v2.1.80/linux/fs/dcache.c linux/fs/dcache.c --- v2.1.80/linux/fs/dcache.c Tue Jan 13 20:02:49 1998 +++ linux/fs/dcache.c Wed Jan 21 17:46:55 1998 @@ -68,6 +68,7 @@ if (inode) { dentry->d_inode = NULL; list_del(&dentry->d_alias); + INIT_LIST_HEAD(&dentry->d_alias); if (dentry->d_op && dentry->d_op->d_iput) dentry->d_op->d_iput(dentry, inode); else diff -u --recursive --new-file v2.1.80/linux/fs/fat/buffer.c linux/fs/fat/buffer.c --- v2.1.80/linux/fs/fat/buffer.c Thu Jan 8 14:02:41 1998 +++ linux/fs/fat/buffer.c Wed Jan 21 17:46:56 1998 @@ -30,9 +30,9 @@ * counterproductive or just plain wrong. */ - if(MSDOS_SB(sb)->cvf_format) - if(MSDOS_SB(sb)->cvf_format->cvf_bread) - return MSDOS_SB(sb)->cvf_format->cvf_bread(sb,block); + if(MSDOS_SB(sb)->cvf_format && + MSDOS_SB(sb)->cvf_format->cvf_bread) + return MSDOS_SB(sb)->cvf_format->cvf_bread(sb,block); if (sb->s_blocksize == 512) { ret = bread (sb->s_dev,block,512); @@ -46,37 +46,37 @@ if (real != NULL){ ret = (struct buffer_head *) - kmalloc (sizeof(struct buffer_head), GFP_KERNEL); + kmalloc (sizeof(struct buffer_head), GFP_KERNEL); if (ret != NULL) { /* #Specification: msdos / strategy / special device / dummy blocks - Many special device (Scsi optical disk for one) use - larger hardware sector size. This allows for higher - capacity. - - Most of the time, the MsDOS file system that sit - on this device is totally unaligned. It use logically - 512 bytes sector size, with logical sector starting - in the middle of a hardware block. The bad news is - that a hardware sector may hold data own by two - different files. This means that the hardware sector - must be read, patch and written almost all the time. - - Needless to say that it kills write performance - on all OS. - - Internally the linux msdos fs is using 512 bytes - logical sector. When accessing such a device, we - allocate dummy buffer cache blocks, that we stuff - with the information of a real one (1k large). - - This strategy is used to hide this difference to - the core of the msdos fs. The slowdown is not - hidden though! - */ + * Many special device (Scsi optical disk for one) use + * larger hardware sector size. This allows for higher + * capacity. + + * Most of the time, the MsDOS file system that sit + * on this device is totally unaligned. It use logically + * 512 bytes sector size, with logical sector starting + * in the middle of a hardware block. The bad news is + * that a hardware sector may hold data own by two + * different files. This means that the hardware sector + * must be read, patch and written almost all the time. + + * Needless to say that it kills write performance + * on all OS. + + * Internally the linux msdos fs is using 512 bytes + * logical sector. When accessing such a device, we + * allocate dummy buffer cache blocks, that we stuff + * with the information of a real one (1k large). + + * This strategy is used to hide this difference to + * the core of the msdos fs. The slowdown is not + * hidden though! + */ /* - The memset is there only to catch errors. The msdos - fs is only using b_data - */ + * The memset is there only to catch errors. The msdos + * fs is only using b_data + */ memset (ret,0,sizeof(*ret)); ret->b_data = real->b_data; if (sb->s_blocksize == 2048) { @@ -92,26 +92,26 @@ } return ret; } -struct buffer_head *fat_getblk ( - struct super_block *sb, - int block) + +struct buffer_head *fat_getblk(struct super_block *sb, int block) { struct buffer_head *ret = NULL; PRINTK(("fat_getblk: block=0x%x\n", block)); - if(MSDOS_SB(sb)->cvf_format) - if(MSDOS_SB(sb)->cvf_format->cvf_getblk) - return MSDOS_SB(sb)->cvf_format->cvf_getblk(sb,block); + if (MSDOS_SB(sb)->cvf_format && + MSDOS_SB(sb)->cvf_format->cvf_getblk) + return MSDOS_SB(sb)->cvf_format->cvf_getblk(sb,block); if (sb->s_blocksize == 512){ ret = getblk (sb->s_dev,block,512); - }else{ - /* #Specification: msdos / special device / writing - A write is always preceded by a read of the complete block - (large hardware sector size). This defeat write performance. - There is a possibility to optimize this when writing large - chunk by making sure we are filling large block. Volunteer ? - */ + } else { + /* + * #Specification: msdos / special device / writing + * A write is always preceded by a read of the complete block + * (large hardware sector size). This defeat write performance. + * There is a possibility to optimize this when writing large + * chunk by making sure we are filling large block. Volunteer ? + */ ret = fat_bread (sb,block); } return ret; @@ -121,10 +121,10 @@ struct super_block *sb, struct buffer_head *bh) { - if (bh != NULL){ - if(MSDOS_SB(sb)->cvf_format) - if(MSDOS_SB(sb)->cvf_format->cvf_brelse) - return MSDOS_SB(sb)->cvf_format->cvf_brelse(sb,bh); + if (bh != NULL) { + if (MSDOS_SB(sb)->cvf_format && + MSDOS_SB(sb)->cvf_format->cvf_brelse) + return MSDOS_SB(sb)->cvf_format->cvf_brelse(sb,bh); if (sb->s_blocksize == 512){ brelse (bh); @@ -141,18 +141,18 @@ void fat_mark_buffer_dirty ( struct super_block *sb, struct buffer_head *bh, - int dirty_val) + int dirty) { - if(MSDOS_SB(sb)->cvf_format) - if(MSDOS_SB(sb)->cvf_format->cvf_mark_buffer_dirty) - { MSDOS_SB(sb)->cvf_format->cvf_mark_buffer_dirty(sb,bh,dirty_val); - return; - } + if (MSDOS_SB(sb)->cvf_format && + MSDOS_SB(sb)->cvf_format->cvf_mark_buffer_dirty) { + MSDOS_SB(sb)->cvf_format->cvf_mark_buffer_dirty(sb,bh,dirty); + return; + } if (sb->s_blocksize != 512){ bh = bh->b_next; } - mark_buffer_dirty (bh,dirty_val); + mark_buffer_dirty (bh,dirty); } void fat_set_uptodate ( @@ -160,11 +160,11 @@ struct buffer_head *bh, int val) { - if(MSDOS_SB(sb)->cvf_format) - if(MSDOS_SB(sb)->cvf_format->cvf_set_uptodate) - { MSDOS_SB(sb)->cvf_format->cvf_set_uptodate(sb,bh,val); - return; - } + if (MSDOS_SB(sb)->cvf_format && + MSDOS_SB(sb)->cvf_format->cvf_set_uptodate) { + MSDOS_SB(sb)->cvf_format->cvf_set_uptodate(sb,bh,val); + return; + } if (sb->s_blocksize != 512){ bh = bh->b_next; @@ -175,9 +175,9 @@ struct super_block *sb, struct buffer_head *bh) { - if(MSDOS_SB(sb)->cvf_format) - if(MSDOS_SB(sb)->cvf_format->cvf_is_uptodate) - return MSDOS_SB(sb)->cvf_format->cvf_is_uptodate(sb,bh); + if(MSDOS_SB(sb)->cvf_format && + MSDOS_SB(sb)->cvf_format->cvf_is_uptodate) + return MSDOS_SB(sb)->cvf_format->cvf_is_uptodate(sb,bh); if (sb->s_blocksize != 512){ bh = bh->b_next; @@ -191,11 +191,11 @@ int nbreq, struct buffer_head *bh[32]) { - if(MSDOS_SB(sb)->cvf_format) - if(MSDOS_SB(sb)->cvf_format->cvf_ll_rw_block) - { MSDOS_SB(sb)->cvf_format->cvf_ll_rw_block(sb,opr,nbreq,bh); - return; - } + if (MSDOS_SB(sb)->cvf_format && + MSDOS_SB(sb)->cvf_format->cvf_ll_rw_block) { + MSDOS_SB(sb)->cvf_format->cvf_ll_rw_block(sb,opr,nbreq,bh); + return; + } if (sb->s_blocksize == 512){ ll_rw_block(opr,nbreq,bh); diff -u --recursive --new-file v2.1.80/linux/fs/fat/cache.c linux/fs/fat/cache.c --- v2.1.80/linux/fs/fat/cache.c Tue Jan 13 20:07:28 1998 +++ linux/fs/fat/cache.c Wed Jan 21 17:46:56 1998 @@ -30,9 +30,9 @@ unsigned char *p_first,*p_last; int copy,first,last,next,b; - if(MSDOS_SB(sb)->cvf_format) - if(MSDOS_SB(sb)->cvf_format->fat_access) - return MSDOS_SB(sb)->cvf_format->fat_access(sb,nr,new_value); + if (MSDOS_SB(sb)->cvf_format && + MSDOS_SB(sb)->cvf_format->fat_access) + return MSDOS_SB(sb)->cvf_format->fat_access(sb,nr,new_value); if ((unsigned) (nr-2) >= MSDOS_SB(sb)->clusters) return 0; @@ -267,9 +267,8 @@ int cluster,offset; sb = MSDOS_SB(inode->i_sb); - if(sb->cvf_format) - if(sb->cvf_format->cvf_smap) - return sb->cvf_format->cvf_smap(inode,sector); + if (sb->cvf_format && sb->cvf_format->cvf_smap) + return sb->cvf_format->cvf_smap(inode,sector); if ((sb->fat_bits != 32) && (inode->i_ino == MSDOS_ROOT_INO || (S_ISDIR(inode->i_mode) && !MSDOS_I(inode)->i_start))) { diff -u --recursive --new-file v2.1.80/linux/fs/fat/dir.c linux/fs/fat/dir.c --- v2.1.80/linux/fs/fat/dir.c Tue Jan 13 20:07:28 1998 +++ linux/fs/fat/dir.c Wed Jan 21 17:46:56 1998 @@ -437,10 +437,10 @@ } default: /* forward ioctl to CVF extension */ - if(MSDOS_SB(inode->i_sb)->cvf_format - &&MSDOS_SB(inode->i_sb)->cvf_format->cvf_dir_ioctl) - return MSDOS_SB(inode->i_sb)->cvf_format-> - cvf_dir_ioctl(inode,filp,cmd,arg); + if (MSDOS_SB(inode->i_sb)->cvf_format && + MSDOS_SB(inode->i_sb)->cvf_format->cvf_dir_ioctl) + return MSDOS_SB(inode->i_sb)->cvf_format + ->cvf_dir_ioctl(inode,filp,cmd,arg); return -EINVAL; } diff -u --recursive --new-file v2.1.80/linux/fs/fat/file.c linux/fs/fat/file.c --- v2.1.80/linux/fs/fat/file.c Thu Jan 8 14:02:41 1998 +++ linux/fs/fat/file.c Wed Jan 21 17:46:56 1998 @@ -312,9 +312,10 @@ loff_t *ppos) { struct inode *inode = filp->f_dentry->d_inode; - if(MSDOS_SB(inode->i_sb)->cvf_format) - if(MSDOS_SB(inode->i_sb)->cvf_format->cvf_file_read) - return MSDOS_SB(inode->i_sb)->cvf_format->cvf_file_read(filp,buf,count,ppos); + if (MSDOS_SB(inode->i_sb)->cvf_format && + MSDOS_SB(inode->i_sb)->cvf_format->cvf_file_read) + return MSDOS_SB(inode->i_sb)->cvf_format + ->cvf_file_read(filp,buf,count,ppos); if (!MSDOS_I(inode)->i_binary) return fat_file_read_text(filp, buf, count, ppos); @@ -338,13 +339,16 @@ struct buffer_head *bh; int binary_mode = MSDOS_I(inode)->i_binary; + PRINTK(("fat_file_write: dentry=%p, inode=%p, ino=%ld\n", + filp->f_dentry, inode, inode->i_ino)); if (!inode) { printk("fat_file_write: inode = NULL\n"); return -EINVAL; } - if(MSDOS_SB(sb)->cvf_format) - if(MSDOS_SB(sb)->cvf_format->cvf_file_write) - return MSDOS_SB(sb)->cvf_format->cvf_file_write(filp,buf,count,ppos); + if (MSDOS_SB(sb)->cvf_format && + MSDOS_SB(sb)->cvf_format->cvf_file_write) + return MSDOS_SB(sb)->cvf_format + ->cvf_file_write(filp,buf,count,ppos); /* S_ISLNK allows for UMSDOS. Should never happen for normal MSDOS */ if (!S_ISREG(inode->i_mode) && !S_ISLNK(inode->i_mode)) { diff -u --recursive --new-file v2.1.80/linux/fs/fat/inode.c linux/fs/fat/inode.c --- v2.1.80/linux/fs/fat/inode.c Tue Jan 13 20:07:28 1998 +++ linux/fs/fat/inode.c Wed Jan 21 17:46:56 1998 @@ -29,89 +29,31 @@ #include /* #define FAT_PARANOIA 1 */ +#define DEBUG_LEVEL 0 #ifdef FAT_DEBUG # define PRINTK(x) printk x #else # define PRINTK(x) #endif - -/* - * Free any dependent inodes at the (effective) last use. - */ -static int fat_free_links(struct inode *inode) -{ - struct inode *depend, *linked, *old_inode; - int success = 0; - - /* - * Clear the fields first to avoid races - */ - depend = MSDOS_I(inode)->i_depend; - MSDOS_I(inode)->i_depend = NULL; - linked = MSDOS_I(inode)->i_linked; - MSDOS_I(inode)->i_linked = NULL; - - if (depend) { -#ifdef FAT_PARANOIA -printk("fat_put_inode: depend inode is %ld, i_count=%d\n", -depend->i_ino, depend->i_count); -#endif - old_inode = MSDOS_I(depend)->i_old; - if (old_inode != inode) { - printk("fat_free_link: Invalid depend for inode %ld: " - "expected 0x%p, got 0x%p\n", - depend->i_ino, inode, old_inode); - goto out; - } - MSDOS_I(depend)->i_old = NULL; - iput(depend); - } - - if (linked) { -#ifdef FAT_PARANOIA -printk("fat_put_inode: linked inode is %ld, i_count=%d\n", -linked->i_ino, linked->i_count); +#if (DEBUG_LEVEL >= 1) +# define PRINTK1(x) printk x +#else +# define PRINTK1(x) #endif - old_inode = MSDOS_I(linked)->i_oldlink; - if (old_inode != inode) { - printk("fat_free_link: Invalid link for inode %ld: " - "expected 0x%p, got 0x%p\n", - linked->i_ino, inode, old_inode); - goto out; - } - MSDOS_I(linked)->i_oldlink = NULL; - iput(linked); - } - success = 1; -out: - return success; -} -/* - * This is a little tricky, as we may have links and may be linked - * by other inodes. Also, we're subject to race conditions ... - */ void fat_put_inode(struct inode *inode) { - int last_use = 1; - /* * Check whether we're a dependent of other inodes ... */ - if (MSDOS_I(inode)->i_oldlink) - last_use++; - if (MSDOS_I(inode)->i_old) - last_use++; - - if (inode->i_count <= last_use) { + if (inode->i_count <= 1) { #ifdef FAT_PARANOIA -printk("fat_put_inode: last use for %ld, i_count=%d\n", -inode->i_ino, inode->i_count); +printk("fat_put_inode: last use for (%p,%ld), i_count=%d\n", +inode, inode->i_ino, inode->i_count); #endif if (inode->i_nlink) { if (MSDOS_I(inode)->i_busy) fat_cache_inval_inode(inode); - fat_free_links(inode); } } } @@ -121,18 +63,9 @@ /* * Make sure there are no active dependencies ... */ - if (MSDOS_I(inode)->i_old) - printk("fat_delete_inode: inode %ld, old=%p??\n", - inode->i_ino, MSDOS_I(inode)->i_old); - if (MSDOS_I(inode)->i_oldlink) - printk("fat_delete_inode: inode %ld, oldlink=%p??\n", - inode->i_ino, MSDOS_I(inode)->i_oldlink); - fat_cache_inval_inode(inode); inode->i_size = 0; fat_truncate(inode); - if (!fat_free_links(inode)) - fat_fs_panic(inode->i_sb,"..."); /* is this necessary? */ clear_inode(inode); } @@ -140,9 +73,9 @@ void fat_put_super(struct super_block *sb) { lock_super(sb); - if(MSDOS_SB(sb)->cvf_format) - { MSDOS_SB(sb)->cvf_format->unmount_cvf(sb); - dec_cvf_format_use_count_by_version(MSDOS_SB(sb)->cvf_format->cvf_version); + if (MSDOS_SB(sb)->cvf_format) { + dec_cvf_format_use_count_by_version(MSDOS_SB(sb)->cvf_format->cvf_version); + MSDOS_SB(sb)->cvf_format->unmount_cvf(sb); } if (MSDOS_SB(sb)->fat_bits == 32) { fat_clusters_flush(sb); @@ -175,7 +108,7 @@ static int parse_options(char *options,int *fat, int *blksize, int *debug, struct fat_mount_options *opts, - char* cvf_format, char*cvf_options) + char *cvf_format, char *cvf_options) { char *this_char,*value,save,*savep; char *p; @@ -355,10 +288,10 @@ char cvf_format[21]; char cvf_options[101]; - cvf_format[0]='\0'; - cvf_options[0]='\0'; - MSDOS_SB(sb)->cvf_format=NULL; - MSDOS_SB(sb)->private_data=NULL; + cvf_format[0] = '\0'; + cvf_options[0] = '\0'; + MSDOS_SB(sb)->cvf_format = NULL; + MSDOS_SB(sb)->private_data = NULL; MOD_INC_USE_COUNT; if (hardsect_size[MAJOR(sb->s_dev)] != NULL){ @@ -484,9 +417,12 @@ /* because clusters (DOS) are often aligned */ /* on odd sectors. */ sb->s_blocksize_bits = blksize == 512 ? 9 : (blksize == 1024 ? 10 : 11); - if(!strcmp(cvf_format,"none"))i=-1; - else i=detect_cvf(sb,cvf_format); - if(i>=0)error=cvf_formats[i]->mount_cvf(sb,cvf_options); + if (!strcmp(cvf_format,"none")) + i = -1; + else + i = detect_cvf(sb,cvf_format); + if (i >= 0) + error = cvf_formats[i]->mount_cvf(sb,cvf_options); if (error || debug) { /* The MSDOS_CAN_BMAP is obsolete, but left just to remember */ printk("[MS-DOS FS Rel. 12,FAT %d,check=%c,conv=%c," @@ -546,9 +482,9 @@ sb->s_root = d_alloc_root(root_inode, NULL); if (!sb->s_root) goto out_no_root; - if(i>=0) - { MSDOS_SB(sb)->cvf_format=cvf_formats[i]; - ++cvf_format_use_count[i]; + if(i>=0) { + MSDOS_SB(sb)->cvf_format = cvf_formats[i]; + ++cvf_format_use_count[i]; } return sb; @@ -585,9 +521,9 @@ int free,nr; struct statfs tmp; - if(MSDOS_SB(sb)->cvf_format) - if(MSDOS_SB(sb)->cvf_format->cvf_statfs) - return MSDOS_SB(sb)->cvf_format->cvf_statfs(sb,buf,bufsiz); + if (MSDOS_SB(sb)->cvf_format && + MSDOS_SB(sb)->cvf_format->cvf_statfs) + return MSDOS_SB(sb)->cvf_format->cvf_statfs(sb,buf,bufsiz); lock_fat(sb); if (MSDOS_SB(sb)->free_clusters != -1) @@ -617,9 +553,9 @@ int cluster,offset; sb = MSDOS_SB(inode->i_sb); - if(sb->cvf_format) - if(sb->cvf_format->cvf_bmap) - return sb->cvf_format->cvf_bmap(inode,block); + if (sb->cvf_format && + sb->cvf_format->cvf_bmap) + return sb->cvf_format->cvf_bmap(inode,block); if ((inode->i_ino == MSDOS_ROOT_INO) && (sb->fat_bits != 32)) { return sb->dir_start + block; } @@ -646,11 +582,9 @@ struct msdos_dir_entry *raw_entry; int nr; - PRINTK(("fat_read_inode: inode=%p, sb->dir_start=0x%x\n", - inode, MSDOS_SB(sb)->dir_start)); + PRINTK1(("fat_read_inode: inode=%p, ino=%ld, sb->dir_start=0x%x\n", + inode, inode->i_ino, MSDOS_SB(sb)->dir_start)); MSDOS_I(inode)->i_busy = 0; - MSDOS_I(inode)->i_depend = MSDOS_I(inode)->i_old = NULL; - MSDOS_I(inode)->i_linked = MSDOS_I(inode)->i_oldlink = NULL; MSDOS_I(inode)->i_binary = 1; inode->i_uid = MSDOS_SB(sb)->options.fs_uid; inode->i_gid = MSDOS_SB(sb)->options.fs_gid; @@ -684,6 +618,7 @@ MSDOS_I(inode)->i_attrs = 0; inode->i_mtime = inode->i_atime = inode->i_ctime = 0; + MSDOS_I(inode)->i_ctime_ms = 0; inode->i_nlink = fat_subdirs(inode)+2; /* subdirs (neither . nor ..) plus . and "self" */ return; @@ -732,10 +667,10 @@ !is_exec(raw_entry->ext))) ? S_IRUGO|S_IWUGO : S_IRWXUGO) & ~MSDOS_SB(sb)->options.fs_umask) | S_IFREG; - if(MSDOS_SB(sb)->cvf_format) - inode->i_op = (MSDOS_SB(sb)->cvf_format->flags&CVF_USE_READPAGE) - ? &fat_file_inode_operations_readpage - : &fat_file_inode_operations_1024; + if (MSDOS_SB(sb)->cvf_format) + inode->i_op = (MSDOS_SB(sb)->cvf_format->flags & CVF_USE_READPAGE) + ? &fat_file_inode_operations_readpage + : &fat_file_inode_operations_1024; else inode->i_op = (sb->s_blocksize == 1024 || sb->s_blocksize == 2048) ? &fat_file_inode_operations_1024 @@ -765,6 +700,7 @@ MSDOS_SB(sb)->options.isvfat ? date_dos2unix(CF_LE_W(raw_entry->ctime),CF_LE_W(raw_entry->cdate)) : inode->i_mtime; + MSDOS_I(inode)->i_ctime_ms = raw_entry->ctime_ms; fat_brelse(sb, bh); } @@ -774,29 +710,6 @@ struct super_block *sb = inode->i_sb; struct buffer_head *bh; struct msdos_dir_entry *raw_entry; - struct inode *linked; - - linked = MSDOS_I(inode)->i_linked; - if (linked) { - if (MSDOS_I(linked)->i_oldlink != inode) { - printk("Invalid link (0x%p): expected 0x%p, got 0x%p\n", - linked, inode, MSDOS_I(linked)->i_oldlink); - fat_fs_panic(sb,"..."); - return; - } - linked->i_version = ++event; - linked->i_mode = inode->i_mode; - linked->i_uid = inode->i_uid; - linked->i_gid = inode->i_gid; - linked->i_size = inode->i_size; - linked->i_atime = inode->i_atime; - linked->i_mtime = inode->i_mtime; - linked->i_ctime = inode->i_ctime; - linked->i_blocks = inode->i_blocks; - linked->i_atime = inode->i_atime; - MSDOS_I(linked)->i_attrs = MSDOS_I(inode)->i_attrs; - mark_inode_dirty(linked); - } if (inode->i_ino == MSDOS_ROOT_INO || !inode->i_nlink) return; if (!(bh = fat_bread(sb, inode->i_ino >> MSDOS_DPB_BITS))) { @@ -823,6 +736,7 @@ raw_entry->date = CT_LE_W(raw_entry->date); if (MSDOS_SB(sb)->options.isvfat) { fat_date_unix2dos(inode->i_ctime,&raw_entry->ctime,&raw_entry->cdate); + raw_entry->ctime_ms = MSDOS_I(inode)->i_ctime_ms; raw_entry->ctime = CT_LE_W(raw_entry->ctime); raw_entry->cdate = CT_LE_W(raw_entry->cdate); } diff -u --recursive --new-file v2.1.80/linux/fs/fat/misc.c linux/fs/fat/misc.c --- v2.1.80/linux/fs/fat/misc.c Tue Jan 13 20:07:28 1998 +++ linux/fs/fat/misc.c Wed Jan 21 17:46:56 1998 @@ -221,9 +221,9 @@ #endif sector = MSDOS_SB(sb)->data_start+(nr-2)*cluster_size; last_sector = sector + cluster_size; - if(MSDOS_SB(sb)->cvf_format&& - MSDOS_SB(sb)->cvf_format->zero_out_cluster) - MSDOS_SB(sb)->cvf_format->zero_out_cluster(inode,nr); + if (MSDOS_SB(sb)->cvf_format && + MSDOS_SB(sb)->cvf_format->zero_out_cluster) + MSDOS_SB(sb)->cvf_format->zero_out_cluster(inode,nr); else for ( ; sector < last_sector; sector++) { #ifdef DEBUG diff -u --recursive --new-file v2.1.80/linux/fs/fat/mmap.c linux/fs/fat/mmap.c --- v2.1.80/linux/fs/fat/mmap.c Tue Jan 13 20:07:28 1998 +++ linux/fs/fat/mmap.c Wed Jan 21 17:46:56 1998 @@ -97,9 +97,9 @@ int fat_mmap(struct file * file, struct vm_area_struct * vma) { struct inode *inode = file->f_dentry->d_inode; - if(MSDOS_SB(inode->i_sb)->cvf_format) - if(MSDOS_SB(inode->i_sb)->cvf_format->cvf_mmap) - return MSDOS_SB(inode->i_sb)->cvf_format->cvf_mmap(file,vma); + if (MSDOS_SB(inode->i_sb)->cvf_format && + MSDOS_SB(inode->i_sb)->cvf_format->cvf_mmap) + return MSDOS_SB(inode->i_sb)->cvf_format->cvf_mmap(file,vma); if (vma->vm_flags & VM_SHARED) /* only PAGE_COW or read-only supported now */ return -EINVAL; @@ -121,10 +121,9 @@ int fat_readpage(struct dentry * dentry, struct page * page) { struct inode * inode = dentry->d_inode; - if(MSDOS_SB(inode->i_sb)->cvf_format) - if(MSDOS_SB(inode->i_sb)->cvf_format->cvf_readpage) - return MSDOS_SB(inode->i_sb)->cvf_format - ->cvf_readpage(inode,page); + if (MSDOS_SB(inode->i_sb)->cvf_format && + MSDOS_SB(inode->i_sb)->cvf_format->cvf_readpage) + return MSDOS_SB(inode->i_sb)->cvf_format->cvf_readpage(inode,page); printk("fat_readpage called with no handler (shouldn't happen)\n"); return -1; diff -u --recursive --new-file v2.1.80/linux/fs/minix/inode.c linux/fs/minix/inode.c --- v2.1.80/linux/fs/minix/inode.c Fri Jul 18 12:42:29 1997 +++ linux/fs/minix/inode.c Wed Jan 21 14:27:57 1998 @@ -12,9 +12,9 @@ #include #include -#include #include #include +#include #include #include #include @@ -24,6 +24,8 @@ #include #include +#include + static void minix_delete_inode(struct inode *inode) { inode->i_size = 0; @@ -62,12 +64,13 @@ sb->u.minix_sb.s_ms->s_state = sb->u.minix_sb.s_mount_state; mark_buffer_dirty(sb->u.minix_sb.s_sbh, 1); } - sb->s_dev = 0; for(i = 0 ; i < MINIX_I_MAP_SLOTS ; i++) brelse(sb->u.minix_sb.s_imap[i]); for(i = 0 ; i < MINIX_Z_MAP_SLOTS ; i++) brelse(sb->u.minix_sb.s_zmap[i]); brelse (sb->u.minix_sb.s_sbh); + kfree(sb->u.minix_sb.s_imap); + sb->s_dev = 0; unlock_super(sb); MOD_DEC_USE_COUNT; return; @@ -161,30 +164,29 @@ return errmsg; } -struct super_block *minix_read_super(struct super_block *s,void *data, +struct super_block *minix_read_super(struct super_block *s, void *data, int silent) { struct buffer_head *bh; + struct buffer_head **map; struct minix_super_block *ms; int i, block; kdev_t dev = s->s_dev; const char * errmsg; struct inode *root_inode; + /* N.B. These should be compile-time tests */ if (32 != sizeof (struct minix_inode)) panic("bad V1 i-node size"); if (64 != sizeof(struct minix2_inode)) panic("bad V2 i-node size"); + MOD_INC_USE_COUNT; lock_super(s); set_blocksize(dev, BLOCK_SIZE); - if (!(bh = bread(dev,1,BLOCK_SIZE))) { - s->s_dev = 0; - unlock_super(s); - printk("MINIX-fs: unable to read superblock\n"); - MOD_DEC_USE_COUNT; - return NULL; - } + if (!(bh = bread(dev,1,BLOCK_SIZE))) + goto out_bad_sb; + ms = (struct minix_super_block *) bh->b_data; s->u.minix_sb.s_ms = ms; s->u.minix_sb.s_sbh = bh; @@ -192,6 +194,7 @@ s->s_blocksize = 1024; s->s_blocksize_bits = 10; s->u.minix_sb.s_ninodes = ms->s_ninodes; + s->u.minix_sb.s_nzones = ms->s_nzones; s->u.minix_sb.s_imap_blocks = ms->s_imap_blocks; s->u.minix_sb.s_zmap_blocks = ms->s_zmap_blocks; s->u.minix_sb.s_firstdatazone = ms->s_firstdatazone; @@ -200,103 +203,74 @@ s->s_magic = ms->s_magic; if (s->s_magic == MINIX_SUPER_MAGIC) { s->u.minix_sb.s_version = MINIX_V1; - s->u.minix_sb.s_nzones = ms->s_nzones; s->u.minix_sb.s_dirsize = 16; s->u.minix_sb.s_namelen = 14; } else if (s->s_magic == MINIX_SUPER_MAGIC2) { s->u.minix_sb.s_version = MINIX_V1; - s->u.minix_sb.s_nzones = ms->s_nzones; s->u.minix_sb.s_dirsize = 32; s->u.minix_sb.s_namelen = 30; } else if (s->s_magic == MINIX2_SUPER_MAGIC) { s->u.minix_sb.s_version = MINIX_V2; - s->u.minix_sb.s_nzones = ms->s_zones; s->u.minix_sb.s_dirsize = 16; s->u.minix_sb.s_namelen = 14; } else if (s->s_magic == MINIX2_SUPER_MAGIC2) { s->u.minix_sb.s_version = MINIX_V2; - s->u.minix_sb.s_nzones = ms->s_zones; s->u.minix_sb.s_dirsize = 32; s->u.minix_sb.s_namelen = 30; - } else { - s->s_dev = 0; - unlock_super(s); - brelse(bh); - if (!silent) - printk("VFS: Can't find a minix or minix V2 filesystem on dev " - "%s.\n", kdevname(dev)); - MOD_DEC_USE_COUNT; - return NULL; - } - for (i=0;i < MINIX_I_MAP_SLOTS;i++) - s->u.minix_sb.s_imap[i] = NULL; - for (i=0;i < MINIX_Z_MAP_SLOTS;i++) - s->u.minix_sb.s_zmap[i] = NULL; - if (s->u.minix_sb.s_zmap_blocks > MINIX_Z_MAP_SLOTS) { - s->s_dev = 0; - unlock_super (s); - brelse (bh); - if (!silent) - printk ("MINIX-fs: filesystem too big\n"); - MOD_DEC_USE_COUNT; - return NULL; - } + } else + goto out_no_fs; + + if (s->u.minix_sb.s_zmap_blocks > MINIX_Z_MAP_SLOTS) + goto out_too_big; + /* + * Allocate the buffer map to keep the superblock small. + */ + i = (MINIX_I_MAP_SLOTS + MINIX_Z_MAP_SLOTS) * sizeof(bh); + map = kmalloc(i, GFP_KERNEL); + if (!map) + goto out_no_map; + memset(map, 0, i); + s->u.minix_sb.s_imap = &map[0]; + s->u.minix_sb.s_zmap = &map[MINIX_I_MAP_SLOTS]; + block=2; - for (i=0 ; i < s->u.minix_sb.s_imap_blocks ; i++) - if ((s->u.minix_sb.s_imap[i]=bread(dev,block,BLOCK_SIZE)) != NULL) - block++; - else - break; - for (i=0 ; i < s->u.minix_sb.s_zmap_blocks ; i++) - if ((s->u.minix_sb.s_zmap[i]=bread(dev,block,BLOCK_SIZE)) != NULL) - block++; - else - break; - if (block != 2+s->u.minix_sb.s_imap_blocks+s->u.minix_sb.s_zmap_blocks) { - for(i=0;iu.minix_sb.s_imap[i]); - for(i=0;iu.minix_sb.s_zmap[i]); - s->s_dev = 0; - unlock_super(s); - brelse(bh); - printk("MINIX-fs: bad superblock or unable to read bitmaps\n"); - MOD_DEC_USE_COUNT; - return NULL; + for (i=0 ; i < s->u.minix_sb.s_imap_blocks ; i++) { + if (!(s->u.minix_sb.s_imap[i]=bread(dev,block,BLOCK_SIZE))) + goto out_no_bitmap; + block++; + } + for (i=0 ; i < s->u.minix_sb.s_zmap_blocks ; i++) { + if (!(s->u.minix_sb.s_zmap[i]=bread(dev,block,BLOCK_SIZE))) + goto out_no_bitmap; + block++; } + if (block != 2+s->u.minix_sb.s_imap_blocks+s->u.minix_sb.s_zmap_blocks) + goto out_no_bitmap; + minix_set_bit(0,s->u.minix_sb.s_imap[0]->b_data); minix_set_bit(0,s->u.minix_sb.s_zmap[0]->b_data); - unlock_super(s); /* set up enough so that it can read an inode */ - s->s_dev = dev; s->s_op = &minix_sops; - root_inode = iget(s,MINIX_ROOT_INO); - s->s_root = d_alloc_root(root_inode, NULL); - if (!s->s_root) { - s->s_dev = 0; - brelse(bh); - if (!silent) - printk("MINIX-fs: get root inode failed\n"); - MOD_DEC_USE_COUNT; - return NULL; - } - + root_inode = iget(s, MINIX_ROOT_INO); + if (!root_inode) + goto out_no_root; + /* + * Check the fs before we get the root dentry ... + */ errmsg = minix_checkroot(s, root_inode); - if (errmsg) { - if (!silent) - printk("MINIX-fs: %s\n", errmsg); - d_delete(s->s_root); /* XXX Is this enough? */ - s->s_dev = 0; - brelse (bh); - MOD_DEC_USE_COUNT; - return NULL; - } + if (errmsg) + goto out_bad_root; + + s->s_root = d_alloc_root(root_inode, NULL); + if (!s->s_root) + goto out_iput; if (!(s->s_flags & MS_RDONLY)) { ms->s_state &= ~MINIX_VALID_FS; mark_buffer_dirty(bh, 1); s->s_dirt = 1; } + unlock_super(s); if (!(s->u.minix_sb.s_mount_state & MINIX_VALID_FS)) printk ("MINIX-fs: mounting unchecked file system, " "running fsck is recommended.\n"); @@ -304,6 +278,54 @@ printk ("MINIX-fs: mounting file system with errors, " "running fsck is recommended.\n"); return s; + +out_bad_root: + if (!silent) + printk("MINIX-fs: %s\n", errmsg); +out_iput: + iput(root_inode); + goto out_freemap; + +out_no_root: + if (!silent) + printk("MINIX-fs: get root inode failed\n"); + goto out_freemap; + +out_no_bitmap: + printk("MINIX-fs: bad superblock or unable to read bitmaps\n"); + out_freemap: + for(i=0;iu.minix_sb.s_imap[i]); + for(i=0;iu.minix_sb.s_zmap[i]); + kfree(s->u.minix_sb.s_imap); + goto out_release; + +out_no_map: + if (!silent) + printk ("MINIX-fs: can't allocate map\n"); + goto out_release; + +out_too_big: + if (!silent) + printk ("MINIX-fs: filesystem too big\n"); + goto out_release; + +out_no_fs: + if (!silent) + printk("VFS: Can't find a minix or minix V2 filesystem on dev " + "%s.\n", kdevname(dev)); + out_release: + brelse(bh); + goto out_unlock; + +out_bad_sb: + printk("MINIX-fs: unable to read superblock\n"); + out_unlock: + s->s_dev = 0; + unlock_super(s); + MOD_DEC_USE_COUNT; + return NULL; } int minix_statfs(struct super_block *sb, struct statfs *buf, int bufsiz) diff -u --recursive --new-file v2.1.80/linux/fs/msdos/namei.c linux/fs/msdos/namei.c --- v2.1.80/linux/fs/msdos/namei.c Wed Dec 10 09:13:24 1997 +++ linux/fs/msdos/namei.c Wed Jan 21 17:46:56 1998 @@ -21,8 +21,7 @@ #include "../fat/msbuffer.h" -#define MSDOS_PARANOIA 1 -/* #define MSDOS_DEBUG 1 */ +#define MSDOS_DEBUG 0 #define PRINTK(x) /* MS-DOS "device special files" */ @@ -257,7 +256,7 @@ int ino,res; struct msdos_dir_entry *de; struct buffer_head *bh; - struct inode *next, *inode; + struct inode *inode; PRINTK (("msdos_lookup\n")); @@ -294,20 +293,8 @@ return 0; } PRINTK (("msdos_lookup 6\n")); - while (MSDOS_I(inode)->i_old) { - next = MSDOS_I(inode)->i_old; -#ifdef MSDOS_PARANOIA -printk("msdos_lookup: ino %ld, old ino=%ld\n", inode->i_ino, next->i_ino); -if (MSDOS_I(next)->i_depend != inode) -printk("msdos_lookup: depend=%p, inode=%p??\n", MSDOS_I(next)->i_depend, inode); -#endif - next->i_count++; - iput(inode); - inode = next; - } - PRINTK (("msdos_lookup 7\n")); d_add(dentry, inode); - PRINTK (("msdos_lookup 8\n")); + PRINTK (("msdos_lookup 7\n")); return 0; } @@ -428,6 +415,9 @@ pos = 0; bh = NULL; while (fat_get_entry(dir,&pos,&bh,&de) > -1) { + /* Ignore vfat longname entries */ + if (de->attr == ATTR_EXT) + continue; if (!IS_FREE(de->name) && strncmp(de->name,MSDOS_DOT , MSDOS_NAME) && strncmp(de->name,MSDOS_DOTDOT, MSDOS_NAME)) { @@ -471,7 +461,7 @@ res = -EBUSY; if (dentry->d_count > 1) { #ifdef MSDOS_DEBUG -printk("rename_diff_dir: %s/%s busy, d_count=%d\n", +printk("msdos_rmdir: %s/%s busy, d_count=%d\n", dentry->d_parent->d_name.name, dentry->d_name.name, dentry->d_count); #endif goto rmdir_done; @@ -744,53 +734,31 @@ mark_inode_dirty(new_dir); } msdos_read_inode(free_inode); - /* - * Check whether there's already a linked inode ... - */ - if (MSDOS_I(old_inode)->i_linked) { - struct inode *linked = MSDOS_I(old_inode)->i_linked; -#ifdef MSDOS_PARANOIA -printk("rename_diff_dir: inode %ld already has link %ld, freeing it\n", -old_inode->i_ino, linked->i_ino); -#endif - MSDOS_I(old_inode)->i_linked = NULL; - MSDOS_I(linked)->i_oldlink = NULL; - iput(linked); - } - MSDOS_I(old_inode)->i_busy = 1; - MSDOS_I(old_inode)->i_linked = free_inode; - MSDOS_I(free_inode)->i_oldlink = old_inode; -#ifdef MSDOS_DEBUG -printk("rename_diff_dir: inode %ld added as link of %ld\n", -free_inode->i_ino, old_inode->i_ino); -#endif + + free_inode->i_mode = old_inode->i_mode; + free_inode->i_size = old_inode->i_size; + free_inode->i_blocks = old_inode->i_blocks; + free_inode->i_mtime = old_inode->i_mtime; + free_inode->i_atime = old_inode->i_atime; + free_inode->i_ctime = old_inode->i_ctime; + MSDOS_I(free_inode)->i_ctime_ms = MSDOS_I(old_inode)->i_ctime_ms; + + MSDOS_I(free_inode)->i_start = MSDOS_I(old_inode)->i_start; + MSDOS_I(free_inode)->i_logstart = MSDOS_I(old_inode)->i_logstart; + MSDOS_I(free_inode)->i_attrs = MSDOS_I(old_inode)->i_attrs; + + /* Detach d_alias from old inode and attach to new inode */ + list_del(&old_dentry->d_alias); + d_instantiate(old_dentry, free_inode); + iput(old_inode); + fat_cache_inval_inode(old_inode); mark_inode_dirty(old_inode); old_de->name[0] = DELETED_FLAG; fat_mark_buffer_dirty(sb, old_bh, 1); fat_mark_buffer_dirty(sb, free_bh, 1); + if (exists) { - /* - * Check whether there's already a depend inode ... - */ - if (MSDOS_I(new_inode)->i_depend) { - struct inode *depend = MSDOS_I(new_inode)->i_depend; -#ifdef MSDOS_PARANOIA -printk("rename_diff_dir: inode %ld already has depend %ld, freeing it\n", -new_inode->i_ino, depend->i_ino); -#endif - MSDOS_I(new_inode)->i_depend = NULL; - MSDOS_I(depend)->i_old = NULL; - iput(depend); - } - MSDOS_I(new_inode)->i_depend = free_inode; - MSDOS_I(free_inode)->i_old = new_inode; - /* Two references now exist to free_inode so increase count */ - free_inode->i_count++; -#ifdef MSDOS_DEBUG -printk("rename_diff_dir: inode %ld added as depend of %ld\n", -free_inode->i_ino, new_inode->i_ino); -#endif /* free_inode is put after putting new_inode and old_inode */ fat_brelse(sb, new_bh); } @@ -815,6 +783,7 @@ iput(dotdot_inode); fat_brelse(sb, dotdot_bh); } + /* Update the dcache */ d_move(old_dentry, new_dentry); error = 0; diff -u --recursive --new-file v2.1.80/linux/fs/nfsd/export.c linux/fs/nfsd/export.c --- v2.1.80/linux/fs/nfsd/export.c Wed Nov 26 13:08:38 1997 +++ linux/fs/nfsd/export.c Fri Jan 23 16:35:35 1998 @@ -433,19 +433,37 @@ int exp_writelock(void) { + /* fast track */ + if (!hash_count && !hash_lock) { + lock_it: + hash_lock = 1; + return 0; + } + + current->sigpending = 0; want_lock++; - while (hash_count || hash_lock) + while (hash_count || hash_lock) { interruptible_sleep_on(&hash_wait); + if (signal_pending(current)) + break; + } want_lock--; - if (signal_pending(current)) - return -EINTR; - hash_lock = 1; - return 0; + + /* restore the task's signals */ + spin_lock_irq(¤t->sigmask_lock); + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + + if (!hash_count && !hash_lock) + goto lock_it; + return -EINTR; } void exp_unlock(void) { + if (!hash_count && !hash_lock) + printk(KERN_WARNING "exp_unlock: not locked!\n"); if (hash_count) hash_count--; else diff -u --recursive --new-file v2.1.80/linux/fs/nfsd/nfsfh.c linux/fs/nfsd/nfsfh.c --- v2.1.80/linux/fs/nfsd/nfsfh.c Mon Jan 12 14:39:48 1998 +++ linux/fs/nfsd/nfsfh.c Fri Jan 23 16:35:35 1998 @@ -999,21 +999,19 @@ u32 fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) { + struct knfs_fh *fh = &fhp->fh_handle; struct svc_export *exp; struct dentry *dentry; struct inode *inode; - struct knfs_fh *fh = &fhp->fh_handle; u32 error = 0; - if(fhp->fh_dverified) - goto out; - - dprintk("nfsd: fh_lookup(exp %x/%ld fh %p)\n", - fh->fh_xdev, fh->fh_xino, fh->fh_dcookie); + dprintk("nfsd: fh_verify(exp %x/%ld cookie %p)\n", + fh->fh_xdev, fh->fh_xino, fh->fh_dcookie); + if(fhp->fh_dverified) + goto check_type; /* * Look up the export entry. - * N.B. We need to lock this while in use ... */ error = nfserr_stale; exp = exp_get(rqstp->rq_client, fh->fh_xdev, fh->fh_xino); @@ -1057,6 +1055,8 @@ * spec says this is incorrect (implementation notes for the * write call). */ +check_type: + dentry = fhp->fh_dentry; inode = dentry->d_inode; if (type > 0 && (inode->i_mode & S_IFMT) != type) { error = (type == S_IFDIR)? nfserr_notdir : nfserr_isdir; @@ -1069,9 +1069,11 @@ /* Finally, check access permissions. */ error = nfsd_permission(fhp->fh_export, dentry, access); +#ifdef NFSD_PARANOIA if (error) printk("fh_verify: %s/%s permission failure, acc=%x, error=%d\n", dentry->d_parent->d_name.name, dentry->d_name.name, access, error); +#endif out: return error; diff -u --recursive --new-file v2.1.80/linux/fs/nfsd/nfssvc.c linux/fs/nfsd/nfssvc.c --- v2.1.80/linux/fs/nfsd/nfssvc.c Fri Dec 19 10:54:10 1997 +++ linux/fs/nfsd/nfssvc.c Fri Jan 23 16:35:35 1998 @@ -42,6 +42,7 @@ extern struct svc_program nfsd_program; static void nfsd(struct svc_rqst *rqstp); struct timeval nfssvc_boot = { 0, 0 }; +static int nfsd_active = 0; int nfsd_svc(unsigned short port, int nrservs) @@ -97,6 +98,7 @@ oldumask = current->fs->umask; /* Set umask to 0. */ current->fs->umask = 0; nfssvc_boot = xtime; /* record boot time */ + nfsd_active++; lockd_up(); /* start lockd */ /* @@ -160,6 +162,11 @@ /* Release lockd */ lockd_down(); + if (!--nfsd_active) { + printk("nfsd: last server exiting\n"); + /* revoke all exports */ + nfsd_export_shutdown(); + } /* Destroy the thread */ svc_exit_thread(rqstp); diff -u --recursive --new-file v2.1.80/linux/fs/ntfs/fs.c linux/fs/ntfs/fs.c --- v2.1.80/linux/fs/ntfs/fs.c Fri Jan 2 01:42:59 1998 +++ linux/fs/ntfs/fs.c Fri Jan 23 17:38:05 1998 @@ -881,8 +881,8 @@ ntfs_read_super_vol: #ifndef NTFS_IN_LINUX_KERNEL ntfs_free(vol); - #endif ntfs_read_super_dec: + #endif ntfs_debug(DEBUG_OTHER, "read_super: done\n"); MOD_DEC_USE_COUNT; return NULL; diff -u --recursive --new-file v2.1.80/linux/fs/open.c linux/fs/open.c --- v2.1.80/linux/fs/open.c Sun Jan 4 00:53:41 1998 +++ linux/fs/open.c Fri Jan 23 16:23:21 1998 @@ -546,6 +546,23 @@ int error; lock_kernel(); + dentry = namei(filename); + + error = PTR_ERR(dentry); + if (!IS_ERR(dentry)) { + error = chown_common(dentry, user, group); + dput(dentry); + } + unlock_kernel(); + return error; +} + +asmlinkage int sys_lchown(const char * filename, uid_t user, gid_t group) +{ + struct dentry * dentry; + int error; + + lock_kernel(); dentry = lnamei(filename); error = PTR_ERR(dentry); diff -u --recursive --new-file v2.1.80/linux/fs/proc/array.c linux/fs/proc/array.c --- v2.1.80/linux/fs/proc/array.c Tue Jan 20 12:52:08 1998 +++ linux/fs/proc/array.c Wed Jan 21 12:04:44 1998 @@ -221,20 +221,14 @@ static int get_kstat(char * buffer) { - int i, j, len; + int i, len; unsigned sum = 0; extern unsigned long total_forks; unsigned long ticks; ticks = jiffies * smp_num_cpus; -#ifndef __SMP__ for (i = 0 ; i < NR_IRQS ; i++) - sum += kstat.interrupts[0][i]; -#else - for (j = 0 ; j < smp_num_cpus ; j++) - for (i = 0 ; i < NR_IRQS ; i++) - sum += kstat.interrupts[cpu_logical_map[j]][i]; -#endif + sum += kstat_irqs(i); #ifdef __SMP__ len = sprintf(buffer, @@ -246,12 +240,12 @@ for (i = 0 ; i < smp_num_cpus; i++) len += sprintf(buffer + len, "cpu%d %u %u %u %lu\n", i, - kstat.per_cpu_user[cpu_logical_map[i]], - kstat.per_cpu_nice[cpu_logical_map[i]], - kstat.per_cpu_system[cpu_logical_map[i]], - jiffies - ( kstat.per_cpu_user[cpu_logical_map[i]] \ - + kstat.per_cpu_nice[cpu_logical_map[i]] \ - + kstat.per_cpu_system[cpu_logical_map[i]])); + kstat.per_cpu_user[cpu_logical_map(i)], + kstat.per_cpu_nice[cpu_logical_map(i)], + kstat.per_cpu_system[cpu_logical_map(i)], + jiffies - ( kstat.per_cpu_user[cpu_logical_map(i)] \ + + kstat.per_cpu_nice[cpu_logical_map(i)] \ + + kstat.per_cpu_system[cpu_logical_map(i)])); len += sprintf(buffer + len, "disk %u %u %u %u\n" "disk_rio %u %u %u %u\n" @@ -292,17 +286,8 @@ kstat.pswpin, kstat.pswpout, sum); - for (i = 0 ; i < NR_IRQS ; i++) { -#ifndef __SMP__ - len += sprintf(buffer + len, " %u", kstat.interrupts[0][i]); -#else - int sum=0; - - for (j = 0 ; j < smp_num_cpus ; j++) - sum += kstat.interrupts[cpu_logical_map[j]][i]; - len += sprintf(buffer + len, " %u", sum); -#endif - } + for (i = 0 ; i < NR_IRQS ; i++) + len += sprintf(buffer + len, " %u", kstat_irqs(i)); len += sprintf(buffer + len, "\nctxt %u\n" "btime %lu\n" @@ -1147,8 +1132,8 @@ for (i = 0 ; i < smp_num_cpus; i++) len += sprintf(buffer + len, "cpu%d %lu %lu\n", i, - tsk->per_cpu_utime[cpu_logical_map[i]], - tsk->per_cpu_stime[cpu_logical_map[i]]); + tsk->per_cpu_utime[cpu_logical_map(i)], + tsk->per_cpu_stime[cpu_logical_map(i)]); return len; } diff -u --recursive --new-file v2.1.80/linux/fs/proc/root.c linux/fs/proc/root.c --- v2.1.80/linux/fs/proc/root.c Tue Jan 20 12:52:08 1998 +++ linux/fs/proc/root.c Fri Jan 23 16:46:45 1998 @@ -342,11 +342,6 @@ if (dp->ops == NULL) dp->ops = &proc_file_inode_operations; } - /* - * kludge until we fixup the md device driver - */ - if (dp->low_ino == PROC_MD) - dp->ops = &proc_array_inode_operations; return 0; } diff -u --recursive --new-file v2.1.80/linux/fs/smbfs/dir.c linux/fs/smbfs/dir.c --- v2.1.80/linux/fs/smbfs/dir.c Sun Jan 4 00:53:42 1998 +++ linux/fs/smbfs/dir.c Wed Jan 21 10:09:31 1998 @@ -351,8 +351,6 @@ inode = smb_iget(dir->i_sb, &finfo); if (inode) { - /* cache the dentry pointer */ - inode->u.smbfs_i.dentry = dentry; add_entry: dentry->d_op = &smbfs_dentry_operations; d_add(dentry, inode); @@ -372,8 +370,8 @@ { struct smb_sb_info *server = server_from_dentry(dentry); struct inode *inode; - struct smb_fattr fattr; int error; + struct smb_fattr fattr; #ifdef SMBFS_DEBUG_VERBOSE printk("smb_instantiate: file %s/%s, fileid=%u\n", @@ -395,8 +393,6 @@ inode->u.smbfs_i.access = SMB_O_RDWR; inode->u.smbfs_i.open = server->generation; } - /* cache the dentry pointer */ - inode->u.smbfs_i.dentry = dentry; d_instantiate(dentry, inode); out: return error; diff -u --recursive --new-file v2.1.80/linux/fs/smbfs/file.c linux/fs/smbfs/file.c --- v2.1.80/linux/fs/smbfs/file.c Sun Jan 4 00:53:42 1998 +++ linux/fs/smbfs/file.c Wed Jan 21 10:09:31 1998 @@ -54,10 +54,9 @@ static int smb_readpage_sync(struct dentry *dentry, struct page *page) { - struct inode *inode = dentry->d_inode; char *buffer = (char *) page_address(page); unsigned long offset = page->offset; - int rsize = smb_get_rsize(SMB_SERVER(inode)); + int rsize = smb_get_rsize(server_from_dentry(dentry)); int count = PAGE_SIZE; int result; @@ -81,14 +80,14 @@ if (count < rsize) rsize = count; - result = smb_proc_read(inode, offset, rsize, buffer); + result = smb_proc_read(dentry, offset, rsize, buffer); if (result < 0) goto io_error; count -= result; offset += result; buffer += result; - inode->i_atime = CURRENT_TIME; + dentry->d_inode->i_atime = CURRENT_TIME; if (result < rsize) break; } while (count); @@ -129,7 +128,7 @@ { struct inode *inode = dentry->d_inode; u8 *buffer = (u8 *) page_address(page) + offset; - int wsize = smb_get_wsize(SMB_SERVER(inode)); + int wsize = smb_get_wsize(server_from_dentry(dentry)); int result, written = 0; offset += page->offset; @@ -142,7 +141,7 @@ if (count < wsize) wsize = count; - result = smb_proc_write(inode, offset, wsize, buffer); + result = smb_proc_write(dentry, offset, wsize, buffer); if (result < 0) goto io_error; /* N.B. what if result < wsize?? */ diff -u --recursive --new-file v2.1.80/linux/fs/smbfs/inode.c linux/fs/smbfs/inode.c --- v2.1.80/linux/fs/smbfs/inode.c Sun Jan 4 00:53:42 1998 +++ linux/fs/smbfs/inode.c Wed Jan 21 10:09:31 1998 @@ -181,6 +181,59 @@ } /* + * This is called to update the inode attributes after + * we've made changes to a file or directory. + */ +static int +smb_refresh_inode(struct dentry *dentry) +{ + struct inode *inode = dentry->d_inode; + int error; + struct smb_fattr fattr; + + error = smb_proc_getattr(dentry, &fattr); + if (!error) + { + smb_renew_times(dentry); + /* + * Check whether the type part of the mode changed, + * and don't update the attributes if it did. + */ + if ((inode->i_mode & S_IFMT) == (fattr.f_mode & S_IFMT)) + smb_set_inode_attr(inode, &fattr); + else + { + /* + * Big trouble! The inode has become a new object, + * so any operations attempted on it are invalid. + * + * To limit damage, mark the inode as bad so that + * subsequent lookup validations will fail. + */ +#ifdef SMBFS_PARANOIA +printk("smb_refresh_inode: %s/%s changed mode, %07o to %07o\n", +dentry->d_parent->d_name.name, dentry->d_name.name, +inode->i_mode, fattr.f_mode); +#endif + fattr.f_mode = inode->i_mode; /* save mode */ + make_bad_inode(inode); + inode->i_mode = fattr.f_mode; /* restore mode */ + /* + * No need to worry about unhashing the dentry: the + * lookup validation will see that the inode is bad. + * But we do want to invalidate the caches ... + */ + if (!S_ISDIR(inode->i_mode)) + invalidate_inode_pages(inode); + else + smb_invalid_dir_cache(inode); + error = -EIO; + } + } + return error; +} + +/* * This is called when we want to check whether the inode * has changed on the server. If it has changed, we must * invalidate our local caches. @@ -220,7 +273,7 @@ * (Note: a size change should have a different mtime.) */ last_time = inode->i_mtime; - error = smb_refresh_inode(inode); + error = smb_refresh_inode(dentry); if (error || inode->i_mtime != last_time) { #ifdef SMBFS_DEBUG_VERBOSE @@ -238,99 +291,15 @@ } /* - * This is called to update the inode attributes after - * we've made changes to a file or directory. - */ -int -smb_refresh_inode(struct inode *inode) -{ - struct dentry * dentry = inode->u.smbfs_i.dentry; - struct smb_fattr fattr; - int error; - - pr_debug("smb_refresh_inode\n"); - if (!dentry) - { - printk("smb_refresh_inode: no dentry, can't refresh\n"); - error = -EIO; - goto out; - } - - error = smb_proc_getattr(dentry, &fattr); - if (!error) - { - smb_renew_times(dentry); - /* - * Check whether the type part of the mode changed, - * and don't update the attributes if it did. - */ - if ((inode->i_mode & S_IFMT) == (fattr.f_mode & S_IFMT)) - smb_set_inode_attr(inode, &fattr); - else - { - /* - * Big trouble! The inode has become a new object, - * so any operations attempted on it are invalid. - * - * To limit damage, mark the inode as bad so that - * subsequent lookup validations will fail. - */ -#ifdef SMBFS_PARANOIA -printk("smb_refresh_inode: %s/%s changed mode, %07o to %07o\n", -dentry->d_parent->d_name.name, dentry->d_name.name, -inode->i_mode, fattr.f_mode); -#endif - fattr.f_mode = inode->i_mode; /* save mode */ - make_bad_inode(inode); - inode->i_mode = fattr.f_mode; /* restore mode */ - /* - * No need to worry about unhashing the dentry: the - * lookup validation will see that the inode is bad. - * But we do want to invalidate the caches ... - */ - if (!S_ISDIR(inode->i_mode)) - invalidate_inode_pages(inode); - else - smb_invalid_dir_cache(inode); - error = -EIO; - } - } -out: - return error; - -} - -/* - * This routine is called for every iput(). + * This routine is called for every iput(). We clear i_nlink + * on the last use to force a call to delete_inode. */ static void smb_put_inode(struct inode *ino) { pr_debug("smb_put_inode: count = %d\n", ino->i_count); - - if (ino->i_count > 1) { - struct dentry * dentry; - /* - * Check whether the dentry still holds this inode. - * This looks scary, but should work ... if this is - * the last use, d_inode == NULL or d_count == 0. - */ - dentry = (struct dentry *) ino->u.smbfs_i.dentry; - if (dentry && (dentry->d_inode != ino || dentry->d_count == 0)) - { - ino->u.smbfs_i.dentry = NULL; -#ifdef SMBFS_DEBUG_VERBOSE -printk("smb_put_inode: cleared dentry for %s/%s (%ld), count=%d\n", -dentry->d_parent->d_name.name, dentry->d_name.name, ino->i_ino, ino->i_count); -#endif - } - } else { - /* - * Last use ... clear i_nlink to force - * smb_delete_inode to be called. - */ + if (ino->i_count == 1) ino->i_nlink = 0; - } } /* @@ -379,7 +348,6 @@ { struct smb_mount_data *mnt; struct inode *root_inode; - struct dentry *dentry; struct smb_fattr root; MOD_INC_USE_COUNT; @@ -435,6 +403,8 @@ printk("SMBFS: Win 95 bug fixes enabled\n"); if (mnt->version & SMB_FIX_OLDATTR) printk("SMBFS: Using core getattr (Win 95 speedup)\n"); + else if (mnt->version & SMB_FIX_DIRATTR) + printk("SMBFS: Using dir ff getattr\n"); /* * Keep the super block locked while we get the root inode. @@ -444,11 +414,9 @@ if (!root_inode) goto out_no_root; - dentry = d_alloc_root(root_inode, NULL); - if (!dentry) + sb->s_root = d_alloc_root(root_inode, NULL); + if (!sb->s_root) goto out_no_root; - root_inode->u.smbfs_i.dentry = dentry; - sb->s_root = dentry; unlock_super(sb); return sb; @@ -465,7 +433,7 @@ unlock_super(sb); goto out_fail; out_wrong_data: - printk("smb_read_super: need mount version %d\n", SMB_MOUNT_VERSION); + printk(KERN_ERR "SMBFS: need mount version %d\n", SMB_MOUNT_VERSION); goto out_fail; out_no_data: printk("smb_read_super: missing data argument\n"); @@ -609,7 +577,7 @@ out: if (refresh) - smb_refresh_inode(inode); + smb_refresh_inode(dentry); return error; } diff -u --recursive --new-file v2.1.80/linux/fs/smbfs/proc.c linux/fs/smbfs/proc.c --- v2.1.80/linux/fs/smbfs/proc.c Fri Dec 19 10:53:29 1997 +++ linux/fs/smbfs/proc.c Wed Jan 21 10:09:31 1998 @@ -531,7 +531,8 @@ if (server->state == CONN_VALID) { #ifdef SMBFS_PARANOIA -printk("smb_retry: new connection pid=%d\n", server->conn_pid); +printk("smb_retry: new pid=%d, generation=%d\n", +server->conn_pid, server->generation); #endif result = 1; } @@ -643,25 +644,17 @@ } server->conn_pid = current->pid; -#ifdef SMBFS_PARANOIA -if (server->sock_file) -printk("smb_newconn: old socket not closed!\n"); -#endif - filp->f_count += 1; server->sock_file = filp; smb_catch_keepalive(server); server->opt = *opt; -#ifdef SMBFS_DEBUG_VERBOSE -printk("smb_newconn: protocol=%d, max_xmit=%d\n", -server->opt.protocol, server->opt.max_xmit); -#endif server->generation += 1; server->state = CONN_VALID; -#ifdef SMBFS_PARANOIA -printk("smb_newconn: state valid, pid=%d\n", server->conn_pid); -#endif error = 0; +#ifdef SMBFS_DEBUG_VERBOSE +printk("smb_newconn: protocol=%d, max_xmit=%d, pid=%d\n", +server->opt.protocol, server->opt.max_xmit, server->conn_pid); +#endif out: wake_up_interruptible(&server->wait); @@ -987,9 +980,9 @@ file-id would not be valid after a reconnection. */ int -smb_proc_read(struct inode *ino, off_t offset, int count, char *data) +smb_proc_read(struct dentry *dentry, off_t offset, int count, char *data) { - struct smb_sb_info *server = SMB_SERVER(ino); + struct smb_sb_info *server = server_from_dentry(dentry); __u16 returned_count, data_len; char *buf; int result; @@ -997,7 +990,7 @@ smb_lock_server(server); smb_setup_header(server, SMBread, 5, 0); buf = server->packet; - WSET(buf, smb_vwv0, ino->u.smbfs_i.fileid); + WSET(buf, smb_vwv0, dentry->d_inode->u.smbfs_i.fileid); WSET(buf, smb_vwv1, count); DSET(buf, smb_vwv2, offset); WSET(buf, smb_vwv4, 0); @@ -1022,29 +1015,27 @@ out: #ifdef SMBFS_DEBUG_VERBOSE printk("smb_proc_read: file %s/%s, count=%d, result=%d\n", -((struct dentry *) ino->u.smbfs_i.dentry)->d_parent->d_name.name, -((struct dentry *) ino->u.smbfs_i.dentry)->d_name.name, count, result); +dentry->d_parent->d_name.name, dentry->d_name.name, count, result); #endif smb_unlock_server(server); return result; } int -smb_proc_write(struct inode *ino, off_t offset, int count, const char *data) +smb_proc_write(struct dentry *dentry, off_t offset, int count, const char *data) { - struct smb_sb_info *server = SMB_SERVER(ino); + struct smb_sb_info *server = server_from_dentry(dentry); int result; __u8 *p; - smb_lock_server(server); #if SMBFS_DEBUG_VERBOSE printk("smb_proc_write: file %s/%s, count=%d@%ld, packet_size=%d\n", -((struct dentry *)ino->u.smbfs_i.dentry)->d_parent->d_name.name, -((struct dentry *)ino->u.smbfs_i.dentry)->d_name.name, +dentry->d_parent->d_name.name, dentry->d_name.name, count, offset, server->packet_size); #endif + smb_lock_server(server); p = smb_setup_header(server, SMBwrite, 5, count + 3); - WSET(server->packet, smb_vwv0, ino->u.smbfs_i.fileid); + WSET(server->packet, smb_vwv0, dentry->d_inode->u.smbfs_i.fileid); WSET(server->packet, smb_vwv1, count); DSET(server->packet, smb_vwv2, offset); WSET(server->packet, smb_vwv4, 0); @@ -1544,9 +1535,10 @@ * Check whether to change the info level. There appears to be * a bug in Win NT 4.0's handling of info level 1, whereby it * truncates the directory scan for certain patterns of files. - * Hence we use level 259 for NT. (And Win 95 as well ...) + * Hence we use level 259 for NT. */ - if (server->opt.protocol >= SMB_PROTOCOL_NT1) + if (server->opt.protocol >= SMB_PROTOCOL_NT1 && + !(server->mnt->version & SMB_FIX_WIN95)) info_level = 259; smb_lock_server(server); @@ -1639,8 +1631,8 @@ if (server->rcls != 0) { #ifdef SMBFS_PARANOIA -printk("smb_proc_readdir_long: rcls=%d, err=%d, breaking\n", -server->rcls, server->err); +printk("smb_proc_readdir_long: name=%s, entries=%d, rcls=%d, err=%d\n", +mask, entries, server->rcls, server->err); #endif entries = -smb_errno(server); break; @@ -1750,6 +1742,94 @@ } /* + * This version uses the trans2 TRANSACT2_FINDFIRST message + * to get the attribute data. + * Note: called with the server locked. + * + * Bugs Noted: + */ +static int +smb_proc_getattr_ff(struct smb_sb_info *server, struct dentry *dentry, + struct smb_fattr *fattr) +{ + char *param = server->temp_buf, *mask = param + 12; + __u16 date, time; + unsigned char *resp_data = NULL; + unsigned char *resp_param = NULL; + int resp_data_len = 0; + int resp_param_len = 0; + int mask_len, result; + +retry: + mask_len = smb_encode_path(server, mask, dentry, NULL) - mask; +#ifdef SMBFS_DEBUG_VERBOSE +printk("smb_proc_getattr_ff: name=%s, len=%d\n", mask, mask_len); +#endif + WSET(param, 0, aSYSTEM | aHIDDEN | aDIR); + WSET(param, 2, 1); /* max count */ + WSET(param, 4, 1); /* close after this call */ + WSET(param, 6, 1); /* info_level */ + DSET(param, 8, 0); + + result = smb_trans2_request(server, TRANSACT2_FINDFIRST, + 0, NULL, 12 + mask_len + 1, param, + &resp_data_len, &resp_data, + &resp_param_len, &resp_param); + if (result < 0) + { + if (smb_retry(server)) + goto retry; + goto out; + } + if (server->rcls != 0) + { + result = -smb_errno(server); +#ifdef SMBFS_PARANOIA +if (result != -ENOENT) +printk("smb_proc_getattr_ff: error for %s, rcls=%d, err=%d\n", +mask, server->rcls, server->err); +#endif + goto out; + } + /* Make sure we got enough data ... */ + result = -EINVAL; + if (resp_data_len < 22 || WVAL(resp_param, 2) != 1) + { +#ifdef SMBFS_PARANOIA +printk("smb_proc_getattr_ff: bad result for %s, len=%d, count=%d\n", +mask, resp_data_len, WVAL(resp_param, 2)); +#endif + goto out; + } + + /* + * Decode the response into the fattr ... + */ + date = WVAL(resp_data, 0); + time = WVAL(resp_data, 2); + fattr->f_ctime = date_dos2unix(date, time); + + date = WVAL(resp_data, 4); + time = WVAL(resp_data, 6); + fattr->f_atime = date_dos2unix(date, time); + + date = WVAL(resp_data, 8); + time = WVAL(resp_data, 10); + fattr->f_mtime = date_dos2unix(date, time); +#ifdef SMBFS_DEBUG_VERBOSE +printk("smb_proc_getattr_ff: name=%s, date=%x, time=%x, mtime=%ld\n", +mask, date, time, fattr->f_mtime); +#endif + fattr->f_size = DVAL(resp_data, 12); + /* ULONG allocation size */ + fattr->attr = WVAL(resp_data, 20); + result = 0; + +out: + return result; +} + +/* * Note: called with the server locked. */ static int @@ -1883,11 +1963,17 @@ * Win 95 is painfully slow at returning trans2 getattr info, * so we provide the SMB_FIX_OLDATTR option switch. */ - if (server->opt.protocol >= SMB_PROTOCOL_LANMAN2 && - !(server->mnt->version & SMB_FIX_OLDATTR)) - result = smb_proc_getattr_trans2(server, dir, fattr); - else + if (server->opt.protocol >= SMB_PROTOCOL_LANMAN2) { + if (server->mnt->version & SMB_FIX_OLDATTR) + goto core_attr; + if (server->mnt->version & SMB_FIX_DIRATTR) + result = smb_proc_getattr_ff(server, dir, fattr); + else + result = smb_proc_getattr_trans2(server, dir, fattr); + } else { + core_attr: result = smb_proc_getattr_core(server, dir, fattr); + } smb_finish_dirent(server, fattr); diff -u --recursive --new-file v2.1.80/linux/fs/super.c linux/fs/super.c --- v2.1.80/linux/fs/super.c Mon Jan 12 15:12:00 1998 +++ linux/fs/super.c Wed Jan 21 14:29:34 1998 @@ -95,28 +95,37 @@ /* NOTREACHED */ } -struct vfsmount *add_vfsmnt(kdev_t dev, const char *dev_name, const char *dir_name) +static struct vfsmount *add_vfsmnt(struct super_block *sb, + const char *dev_name, const char *dir_name) { struct vfsmount *lptr; - char *tmp; + char *tmp, *name; lptr = (struct vfsmount *)kmalloc(sizeof(struct vfsmount), GFP_KERNEL); - if (!lptr) - return NULL; + if (!lptr) + goto out; memset(lptr, 0, sizeof(struct vfsmount)); - lptr->mnt_dev = dev; + lptr->mnt_sb = sb; + lptr->mnt_dev = sb->s_dev; + lptr->mnt_flags = sb->s_flags; sema_init(&lptr->mnt_sem, 1); + + /* N.B. Is it really OK to have a vfsmount without names? */ if (dev_name && !IS_ERR(tmp = getname(dev_name))) { - if ((lptr->mnt_devname = - (char *) kmalloc(strlen(tmp)+1, GFP_KERNEL)) != (char *)NULL) - strcpy(lptr->mnt_devname, tmp); + name = (char *) kmalloc(strlen(tmp)+1, GFP_KERNEL); + if (name) { + strcpy(name, tmp); + lptr->mnt_devname = name; + } putname(tmp); } if (dir_name && !IS_ERR(tmp = getname(dir_name))) { - if ((lptr->mnt_dirname = - (char *) kmalloc(strlen(tmp)+1, GFP_KERNEL)) != (char *)NULL) - strcpy(lptr->mnt_dirname, tmp); + name = (char *) kmalloc(strlen(tmp)+1, GFP_KERNEL); + if (name) { + strcpy(name, tmp); + lptr->mnt_dirname = name; + } putname(tmp); } @@ -126,10 +135,11 @@ vfsmnttail->mnt_next = lptr; vfsmnttail = lptr; } - return (lptr); +out: + return lptr; } -void remove_vfsmnt(kdev_t dev) +static void remove_vfsmnt(kdev_t dev) { struct vfsmount *lptr, *tofree; @@ -496,6 +506,23 @@ return err; } +/* + * Find a super_block with no device assigned. + */ +static struct super_block *get_empty_super(void) +{ + struct super_block *s = 0+super_blocks; + + for (; s < NR_SUPER+super_blocks; s++) { + if (s->s_dev) + continue; + if (!s->s_lock) + return s; + printk("VFS: empty superblock %p locked!\n", s); + } + return NULL; +} + static struct super_block * read_super(kdev_t dev,const char *name,int flags, void *data, int silent) { @@ -503,44 +530,39 @@ struct file_system_type *type; if (!dev) - goto out_fail; + goto out_null; check_disk_change(dev); s = get_super(dev); if (s) - return s; + goto out; + type = get_fs_type(name); if (!type) { printk("VFS: on device %s: get_fs_type(%s) failed\n", kdevname(dev), name); - goto out_fail; - } - for (s = 0+super_blocks ;; s++) { - if (s >= NR_SUPER+super_blocks) - goto out_fail; - if (s->s_dev) - continue; - if (s->s_lock) { - printk("VFS: empty superblock %p locked!\n", s); - continue; - } - break; + goto out; } + s = get_empty_super(); + if (!s) + goto out; s->s_dev = dev; s->s_flags = flags; s->s_dirt = 0; /* N.B. Should lock superblock now ... */ - if (!type->read_super(s,data, silent)) - goto fail; + if (!type->read_super(s, data, silent)) + goto out_fail; s->s_dev = dev; /* N.B. why do this again?? */ s->s_rd_only = 0; s->s_type = type; +out: return s; /* N.B. s_dev should be cleared in type->read_super */ -fail: - s->s_dev = 0; out_fail: - return NULL; + s->s_dev = 0; +out_null: + s = NULL; + goto out; } /* @@ -603,17 +625,16 @@ dentry->d_covers = covered; } -static int do_umount(kdev_t dev,int unmount_root) +static int do_umount(kdev_t dev, int unmount_root) { struct super_block * sb; int retval; + retval = -ENOENT; sb = get_super(dev); - if (!sb) - return -ENOENT; + if (!sb || !sb->s_root) + goto out; - if (!sb->s_root) - return -ENOENT; /* * Before checking whether the filesystem is still busy, * make sure the kernel doesn't hold any quotafiles open @@ -659,7 +680,6 @@ sb->s_op->put_super(sb); } remove_vfsmnt(dev); - retval = 0; out: return retval; } @@ -781,7 +801,7 @@ int do_mount(kdev_t dev, const char * dev_name, const char * dir_name, const char * type, int flags, void * data) { - struct dentry * dir_d = NULL; + struct dentry * dir_d; struct super_block * sb; struct vfsmount *vfsmnt; int error; @@ -806,15 +826,13 @@ goto dput_and_out; /* - * Check whether to read the super block + * Note: If the superblock already exists, + * read_super just does a get_super(). */ - sb = get_super(dev); - if (!sb || !sb->s_root) { - error = -EINVAL; - sb = read_super(dev,type,flags,data,0); - if (!sb) - goto dput_and_out; - } + error = -EINVAL; + sb = read_super(dev, type, flags, data, 0); + if (!sb) + goto dput_and_out; /* * We may have slept while reading the super block, @@ -825,20 +843,19 @@ goto dput_and_out; error = -ENOMEM; - vfsmnt = add_vfsmnt(dev, dev_name, dir_name); - if (vfsmnt) { - vfsmnt->mnt_sb = sb; - vfsmnt->mnt_flags = flags; - d_mount(dir_d, sb->s_root); - error = 0; - goto out; /* we don't dput(dir) - see umount */ - } + vfsmnt = add_vfsmnt(sb, dev_name, dir_name); + if (!vfsmnt) + goto dput_and_out; + d_mount(dir_d, sb->s_root); + error = 0; /* we don't dput(dir_d) - see umount */ -dput_and_out: - dput(dir_d); out: up(&mount_sem); return error; + +dput_and_out: + dput(dir_d); + goto out; } @@ -1063,14 +1080,11 @@ if (MAJOR(ROOT_DEV) == UNNAMED_MAJOR) { ROOT_DEV = 0; if ((fs_type = get_fs_type("nfs"))) { - if ((vfsmnt = add_vfsmnt(ROOT_DEV, "/dev/root", "/"))) { - - sb = &super_blocks[0]; - while (sb->s_dev) sb++; - vfsmnt->mnt_sb = sb; - - sb->s_dev = get_unnamed_dev(); - sb->s_flags = root_mountflags & ~MS_RDONLY; + sb = get_empty_super(); /* "can't fail" */ + sb->s_dev = get_unnamed_dev(); + sb->s_flags = root_mountflags & ~MS_RDONLY; + vfsmnt = add_vfsmnt(sb, "/dev/root", "/"); + if (vfsmnt) { if (nfs_root_mount(sb) >= 0) { sb->s_rd_only = 0; sb->s_dirt = 0; @@ -1081,9 +1095,10 @@ printk (KERN_NOTICE "VFS: Mounted root (nfs filesystem).\n"); return; } - sb->s_dev = 0; - put_unnamed_dev(sb->s_dev); + remove_vfsmnt(sb->s_dev); } + put_unnamed_dev(sb->s_dev); + sb->s_dev = 0; } if (!ROOT_DEV) { printk(KERN_ERR "VFS: Unable to mount root fs via NFS, trying floppy.\n"); @@ -1136,12 +1151,10 @@ printk ("VFS: Mounted root (%s filesystem)%s.\n", fs_type->name, (sb->s_flags & MS_RDONLY) ? " readonly" : ""); - vfsmnt = add_vfsmnt(ROOT_DEV, "/dev/root", "/"); - if (!vfsmnt) - panic("VFS: add_vfsmnt failed for root fs"); - vfsmnt->mnt_sb = sb; - vfsmnt->mnt_flags = root_mountflags; - return; + vfsmnt = add_vfsmnt(sb, "/dev/root", "/"); + if (vfsmnt) + return; + panic("VFS: add_vfsmnt failed for root fs"); } } panic("VFS: Unable to mount root fs on %s", @@ -1225,10 +1238,8 @@ return error; } remove_vfsmnt(old_root_dev); - vfsmnt = add_vfsmnt(old_root_dev,"/dev/root.old",put_old); + vfsmnt = add_vfsmnt(old_root->d_sb, "/dev/root.old", put_old); if (vfsmnt) { - vfsmnt->mnt_sb = old_root->d_inode->i_sb; - vfsmnt->mnt_flags = vfsmnt->mnt_sb->s_flags; d_mount(dir_d,old_root); return 0; } diff -u --recursive --new-file v2.1.80/linux/fs/vfat/namei.c linux/fs/vfat/namei.c --- v2.1.80/linux/fs/vfat/namei.c Tue Jan 13 20:07:28 1998 +++ linux/fs/vfat/namei.c Wed Jan 21 17:46:56 1998 @@ -27,10 +27,21 @@ #include "../fat/msbuffer.h" -#if 0 -# define PRINTK(x) printk x +#define DEBUG_LEVEL 0 +#if (DEBUG_LEVEL >= 1) +# define PRINTK1(x) printk x +#else +# define PRINTK1(x) +#endif +#if (DEBUG_LEVEL >= 2) +# define PRINTK2(x) printk x #else -# define PRINTK(x) +# define PRINTK2(x) +#endif +#if (DEBUG_LEVEL >= 3) +# define PRINTK3(x) printk x +#else +# define PRINTK3(x) #endif #ifndef DEBUG @@ -114,6 +125,7 @@ static int vfat_revalidate(struct dentry *dentry) { + PRINTK1(("vfat_revalidate: %s\n", dentry->d_name.name)); if (dentry->d_time == dentry->d_parent->d_inode->i_version) { return 1; } @@ -309,6 +321,9 @@ MOD_DEC_USE_COUNT; } else { MSDOS_SB(sb)->options.dotsOK = 0; + if (MSDOS_SB(sb)->options.posixfs) { + MSDOS_SB(sb)->options.name_check = 's'; + } if (MSDOS_SB(sb)->options.name_check != 's') { sb->s_root->d_op = &vfat_dentry_ops[0]; } else { @@ -600,7 +615,7 @@ const char *name_start; struct qstr qname; - PRINTK(("Entering vfat_create_shortname: name=%s, len=%d\n", name, len)); + PRINTK2(("Entering vfat_create_shortname: name=%s, len=%d\n", name, len)); sz = 0; /* Make compiler happy */ if (len && name[len-1]==' ') return -EINVAL; if (len <= 12) { @@ -625,17 +640,17 @@ res = vfat_format_name(msdos_name, len, name_res, 1, utf8); } if (res > -1) { - PRINTK(("vfat_create_shortname 1\n")); + PRINTK3(("vfat_create_shortname 1\n")); qname.name=msdos_name; qname.len=len; res = vfat_find(dir, &qname, 0, 0, 0, &sinfo); - PRINTK(("vfat_create_shortname 2\n")); + PRINTK3(("vfat_create_shortname 2\n")); if (res > -1) return -EEXIST; return 0; } } - PRINTK(("vfat_create_shortname 3\n")); + PRINTK3(("vfat_create_shortname 3\n")); /* Now, we need to create a shortname from the long name */ ext_start = end = &name[len]; while (--ext_start >= name) { @@ -793,7 +808,7 @@ int res; int added; - PRINTK(("vfat_find_free_slots: find %d free slots\n", slots)); + PRINTK2(("vfat_find_free_slots: find %d free slots\n", slots)); offset = curr = 0; bh = NULL; row = 0; @@ -807,7 +822,7 @@ if (inode) { /* Directory slots of busy deleted files aren't available yet. */ done = !MSDOS_I(inode)->i_busy; - /* PRINTK(("inode %d still busy\n", ino)); */ + /* PRINTK3(("inode %d still busy\n", ino)); */ iput(inode); } } @@ -934,18 +949,18 @@ for (cksum = i = 0; i < 11; i++) { cksum = (((cksum&1)<<7)|((cksum&0xfe)>>1)) + msdos_name[i]; } - PRINTK(("vfat_fill_long_slots 3: slots=%d\n",*slots)); + PRINTK3(("vfat_fill_long_slots 3: slots=%d\n",*slots)); for (ps = ds, slot = *slots; slot > 0; slot--, ps++) { int end, j; - PRINTK(("vfat_fill_long_slots 4\n")); + PRINTK3(("vfat_fill_long_slots 4\n")); ps->id = slot; ps->attr = ATTR_EXT; ps->reserved = 0; ps->alias_checksum = cksum; ps->start = 0; - PRINTK(("vfat_fill_long_slots 5: uniname=%s\n",uniname)); + PRINTK3(("vfat_fill_long_slots 5: uniname=%s\n",uniname)); offset = (slot - 1) * 26; ip = &uniname[offset]; j = offset; @@ -954,22 +969,22 @@ ps->name0_4[i] = *ip++; ps->name0_4[i+1] = *ip++; } - PRINTK(("vfat_fill_long_slots 6\n")); + PRINTK3(("vfat_fill_long_slots 6\n")); for (i = 0; i < 12; i += 2) { ps->name5_10[i] = *ip++; ps->name5_10[i+1] = *ip++; } - PRINTK(("vfat_fill_long_slots 7\n")); + PRINTK3(("vfat_fill_long_slots 7\n")); for (i = 0; i < 4; i += 2) { ps->name11_12[i] = *ip++; ps->name11_12[i+1] = *ip++; } } - PRINTK(("vfat_fill_long_slots 8\n")); + PRINTK3(("vfat_fill_long_slots 8\n")); ds[0].id |= 0x40; de = (struct msdos_dir_entry *) ps; - PRINTK(("vfat_fill_long_slots 9\n")); + PRINTK3(("vfat_fill_long_slots 9\n")); strncpy(de->name, msdos_name, MSDOS_NAME); free_page(page); @@ -984,7 +999,7 @@ int res, xlate, utf8; struct nls_table *nls; - PRINTK(("Entering vfat_build_slots: name=%s, len=%d\n", name, len)); + PRINTK2(("Entering vfat_build_slots: name=%s, len=%d\n", name, len)); de = (struct msdos_dir_entry *) ds; xlate = MSDOS_SB(dir->i_sb)->options.unicode_xlate; utf8 = MSDOS_SB(dir->i_sb)->options.utf8; @@ -997,12 +1012,12 @@ } else if (len == 2 && name[0] == '.' && name[1] == '.') { strncpy(de->name, MSDOS_DOT, MSDOS_NAME); } else { - PRINTK(("vfat_build_slots 4\n")); + PRINTK3(("vfat_build_slots 4\n")); res = vfat_valid_shortname(name, len, 1, utf8); if (res > -1) { - PRINTK(("vfat_build_slots 5a\n")); + PRINTK3(("vfat_build_slots 5a\n")); res = vfat_format_name(name, len, de->name, 1, utf8); - PRINTK(("vfat_build_slots 5b\n")); + PRINTK3(("vfat_build_slots 5b\n")); } else { res = vfat_create_shortname(dir, name, len, msdos_name, utf8); if (res < 0) { @@ -1082,7 +1097,7 @@ int slots, slot; int res; - PRINTK(("Entering vfat_find\n")); + PRINTK2(("Entering vfat_find\n")); ds = (struct msdos_dir_slot *) kmalloc(sizeof(struct msdos_dir_slot)*MSDOS_SLOTS, GFP_KERNEL); @@ -1096,7 +1111,7 @@ vf.posix = MSDOS_SB(sb)->options.posixfs; vf.anycase = (MSDOS_SB(sb)->options.name_check != 's'); res = fat_readdirx(dir,&fil,(void *)&vf,vfat_readdir_cb,NULL,1,find_long,0); - PRINTK(("vfat_find: Debug 1\n")); + PRINTK3(("vfat_find: Debug 1\n")); if (res < 0) goto cleanup; if (vf.found) { if (new_filename) { @@ -1110,12 +1125,12 @@ sinfo_out->total_slots = vf.long_slots + 1; sinfo_out->ino = vf.ino; - PRINTK(("vfat_find: Debug 2\n")); + PRINTK3(("vfat_find: Debug 2\n")); res = 0; goto cleanup; } - PRINTK(("vfat_find: Debug 3\n")); + PRINTK3(("vfat_find: Debug 3\n")); if (!vf.found && !new_filename) { res = -ENOENT; goto cleanup; @@ -1129,7 +1144,7 @@ bh = NULL; if (new_filename) { - PRINTK(("vfat_find: create file 1\n")); + PRINTK3(("vfat_find: create file 1\n")); if (is_long) slots++; offset = vfat_find_free_slots(dir, slots); if (offset < 0) { @@ -1137,14 +1152,14 @@ goto cleanup; } - PRINTK(("vfat_find: create file 2\n")); + PRINTK3(("vfat_find: create file 2\n")); /* Now create the new entry */ bh = NULL; for (slot = 0, ps = ds; slot < slots; slot++, ps++) { - PRINTK(("vfat_find: create file 3, slot=%d\n",slot)); + PRINTK3(("vfat_find: create file 3, slot=%d\n",slot)); sinfo_out->ino = fat_get_entry(dir,&offset,&bh,&de); if (sinfo_out->ino < 0) { - PRINTK(("vfat_find: problem\n")); + PRINTK3(("vfat_find: problem\n")); res = sinfo_out->ino; goto cleanup; } @@ -1152,11 +1167,11 @@ fat_mark_buffer_dirty(sb, bh, 1); } - PRINTK(("vfat_find: create file 4\n")); + PRINTK3(("vfat_find: create file 4\n")); dir->i_ctime = dir->i_mtime = dir->i_atime = CURRENT_TIME; mark_inode_dirty(dir); - PRINTK(("vfat_find: create file 5\n")); + PRINTK3(("vfat_find: create file 5\n")); fat_date_unix2dos(dir->i_mtime,&de->time,&de->date); de->ctime_ms = 0; @@ -1198,7 +1213,7 @@ struct inode *result; int table; - PRINTK (("vfat_lookup: name=%s, len=%d\n", + PRINTK2(("vfat_lookup: name=%s, len=%d\n", dentry->d_name.name, dentry->d_name.len)); table = (MSDOS_SB(dir->i_sb)->options.name_check == 's') ? 2 : 0; @@ -1210,17 +1225,17 @@ table++; goto error; } - PRINTK (("vfat_lookup 4.5\n")); + PRINTK3(("vfat_lookup 4.5\n")); if (!(result = iget(dir->i_sb,sinfo.ino))) return -EACCES; - PRINTK (("vfat_lookup 5\n")); + PRINTK3(("vfat_lookup 5\n")); if (MSDOS_I(result)->i_busy) { /* mkdir in progress */ iput(result); result = NULL; table++; goto error; } - PRINTK (("vfat_lookup 6\n")); + PRINTK3(("vfat_lookup 6\n")); error: dentry->d_op = &vfat_dentry_ops[table]; dentry->d_time = dentry->d_parent->d_inode->i_version; @@ -1240,7 +1255,7 @@ struct vfat_slot_info sinfo; *result=0; - PRINTK(("vfat_create_entry 1\n")); + PRINTK1(("vfat_create_entry: Entering\n")); res = vfat_find(dir, qname, 1, 1, is_dir, &sinfo); if (res < 0) { return res; @@ -1248,16 +1263,16 @@ offset = sinfo.shortname_offset; - PRINTK(("vfat_create_entry 2\n")); + PRINTK3(("vfat_create_entry 2\n")); bh = NULL; ino = fat_get_entry(dir, &offset, &bh, &de); if (ino < 0) { - PRINTK(("vfat_mkdir problem\n")); + PRINTK3(("vfat_mkdir problem\n")); if (bh) fat_brelse(sb, bh); return ino; } - PRINTK(("vfat_create_entry 3\n")); + PRINTK3(("vfat_create_entry 3\n")); if ((*result = iget(dir->i_sb,ino)) != NULL) vfat_read_inode(*result); @@ -1283,7 +1298,7 @@ res = vfat_create_entry(dir,&dentry->d_name,0,&result); fat_unlock_creation(); if (res < 0) { - PRINTK(("vfat_create: unable to get new entry\n")); + PRINTK3(("vfat_create: unable to get new entry\n")); } else { dentry->d_time = dentry->d_parent->d_inode->i_version; d_instantiate(dentry,result); @@ -1298,7 +1313,7 @@ struct super_block *sb = dir->i_sb; struct inode *dot; - PRINTK(("vfat_create_a_dotdir 1\n")); + PRINTK2(("vfat_create_a_dotdir: Entering\n")); /* * XXX all times should be set by caller upon successful completion. @@ -1336,7 +1351,7 @@ iput(dot); - PRINTK(("vfat_create_a_dotdir 2\n")); + PRINTK3(("vfat_create_a_dotdir 2\n")); return 0; } @@ -1348,31 +1363,31 @@ struct msdos_dir_entry *de; loff_t offset; - PRINTK(("vfat_create_dotdirs 1\n")); + PRINTK2(("vfat_create_dotdirs: Entering\n")); if ((res = fat_add_cluster(dir)) < 0) return res; - PRINTK(("vfat_create_dotdirs 2\n")); + PRINTK3(("vfat_create_dotdirs 2\n")); offset = 0; bh = NULL; if ((res = fat_get_entry(dir,&offset,&bh,&de)) < 0) return res; - PRINTK(("vfat_create_dotdirs 3\n")); + PRINTK3(("vfat_create_dotdirs 3\n")); res = vfat_create_a_dotdir(dir, parent, bh, de, res, MSDOS_DOT, 1); - PRINTK(("vfat_create_dotdirs 4\n")); + PRINTK3(("vfat_create_dotdirs 4\n")); if (res < 0) { fat_brelse(sb, bh); return res; } - PRINTK(("vfat_create_dotdirs 5\n")); + PRINTK3(("vfat_create_dotdirs 5\n")); if ((res = fat_get_entry(dir,&offset,&bh,&de)) < 0) { fat_brelse(sb, bh); return res; } - PRINTK(("vfat_create_dotdirs 6\n")); + PRINTK3(("vfat_create_dotdirs 6\n")); res = vfat_create_a_dotdir(dir, parent, bh, de, res, MSDOS_DOTDOT, 0); - PRINTK(("vfat_create_dotdirs 7\n")); + PRINTK3(("vfat_create_dotdirs 7\n")); fat_brelse(sb, bh); return res; @@ -1386,12 +1401,6 @@ struct buffer_head *bh; struct msdos_dir_entry *de; - /* - * Prune any child dentries, then verify that - * the directory is empty and not in use. - */ - shrink_dcache_sb(sb); /* should be child prune */ - if (dir->i_count > 1) { return -EBUSY; } @@ -1427,6 +1436,7 @@ if (dir->i_dev != dentry->d_inode->i_dev || dir == dentry->d_inode) { return -EBUSY; } + res = vfat_empty(dentry->d_inode); if (res) { return res; @@ -1498,11 +1508,13 @@ return 0; } -static void vfat_delete_dentries(struct dentry *dentry) +/* Replace inodes in alias dentries and drop all but the initial dentry */ +static void drop_replace_inodes(struct dentry *dentry, struct inode *inode) { struct list_head *head, *next, *tmp; struct dentry *alias; + PRINTK1(("drop_replace_inodes: dentry=%p, inode=%p\n", dentry, inode)); head = &dentry->d_inode->i_dentry; if (dentry->d_inode) { next = dentry->d_inode->i_dentry.next; @@ -1510,10 +1522,19 @@ tmp = next; next = tmp->next; alias = list_entry(tmp, struct dentry, d_alias); - d_delete(alias); + if (inode) { + list_del(&alias->d_alias); + iput(alias->d_inode); + d_instantiate(alias, inode); + /* dentry is already accounted for */ + if (alias != dentry) { + inode->i_count++; + } + } + if (alias != dentry) { + d_drop(alias); + } } - } else { - d_delete(dentry); } } @@ -1524,6 +1545,7 @@ struct buffer_head *bh; struct vfat_slot_info sinfo; + PRINTK1(("vfat_rmdirx: dentry=%p\n", dentry)); res = vfat_find(dir,&dentry->d_name,1,0,0,&sinfo); if (res >= 0 && sinfo.total_slots > 0) { @@ -1542,9 +1564,11 @@ int vfat_rmdir(struct inode *dir,struct dentry* dentry) { int res; + PRINTK1(("vfat_rmdir: dentry=%p, inode=%p\n", dentry, dentry->d_inode)); res = vfat_rmdirx(dir, dentry); if (res >= 0) { - vfat_delete_dentries(dentry); + drop_replace_inodes(dentry, NULL); + d_delete(dentry); } return res; } @@ -1559,6 +1583,7 @@ struct buffer_head *bh; struct vfat_slot_info sinfo; + PRINTK1(("vfat_unlinkx: dentry=%p, inode=%p\n", dentry, dentry->d_inode)); bh = NULL; res = vfat_find(dir,&dentry->d_name,1,0,0,&sinfo); @@ -1579,6 +1604,7 @@ struct inode *inode; int res; + PRINTK1(("vfat_mkdir: dentry=%p, inode=%p\n", dentry, dentry->d_inode)); fat_lock_creation(); if ((res = vfat_create_entry(dir,&dentry->d_name,1,&inode)) < 0) { fat_unlock_creation(); @@ -1606,9 +1632,11 @@ { int res; + PRINTK1(("vfat_unlink: dentry=%p, inode=%p\n", dentry, dentry->d_inode)); res = vfat_unlinkx (dir,dentry,1); if (res >= 0) { - vfat_delete_dentries(dentry); + drop_replace_inodes(dentry, NULL); + d_delete(dentry); } return res; } @@ -1636,8 +1664,12 @@ int res, is_dir, i; int locked = 0; struct vfat_slot_info sinfo; + int put_new_inode = 0; - PRINTK(("vfat_rename 1\n")); + PRINTK1(("vfat_rename: Entering: old_dentry=%p, old_inode=%p, old ino=%ld, new_dentry=%p, new_inode=%p, new ino=%ld\n", + old_dentry, old_dentry->d_inode, old_dentry->d_inode->i_ino, + new_dentry, new_dentry->d_inode, + new_dentry->d_inode ? new_dentry->d_inode->i_ino : 0)); if (old_dir == new_dir && old_dentry->d_name.len == new_dentry->d_name.len && strncmp(old_dentry->d_name.name, new_dentry->d_name.name, @@ -1647,7 +1679,7 @@ old_bh = new_bh = NULL; old_inode = new_inode = NULL; res = vfat_find(old_dir,&old_dentry->d_name,1,0,0,&sinfo); - PRINTK(("vfat_rename 2\n")); + PRINTK3(("vfat_rename 2\n")); if (res < 0) goto rename_done; old_slots = sinfo.total_slots; @@ -1655,7 +1687,7 @@ old_offset = sinfo.shortname_offset; old_ino = sinfo.ino; res = fat_get_entry(old_dir, &old_offset, &old_bh, &old_de); - PRINTK(("vfat_rename 3\n")); + PRINTK3(("vfat_rename 3\n")); if (res < 0) goto rename_done; res = -ENOENT; @@ -1678,15 +1710,15 @@ res = vfat_find(new_dir,&new_dentry->d_name,1,0,is_dir,&sinfo); - PRINTK(("vfat_rename 4\n")); + PRINTK3(("vfat_rename 4\n")); if (res > -1) { int new_is_dir; - PRINTK(("vfat_rename 5\n")); + PRINTK3(("vfat_rename 5\n")); /* Filename currently exists. Need to delete it */ new_offset = sinfo.shortname_offset; res = fat_get_entry(new_dir, &new_offset, &new_bh, &new_de); - PRINTK(("vfat_rename 6\n")); + PRINTK3(("vfat_rename 6\n")); if (res < 0) goto rename_done; if (!(new_inode = iget(new_dir->i_sb,res))) @@ -1694,82 +1726,67 @@ new_is_dir = S_ISDIR(new_inode->i_mode); iput(new_inode); if (new_is_dir) { - PRINTK(("vfat_rename 7\n")); + PRINTK3(("vfat_rename 7\n")); res = vfat_rmdirx(new_dir,new_dentry); - PRINTK(("vfat_rename 8\n")); + PRINTK3(("vfat_rename 8\n")); if (res < 0) goto rename_done; } else { /* Is this the same file, different case? */ if (new_inode != old_inode) { - PRINTK(("vfat_rename 9\n")); + PRINTK3(("vfat_rename 9\n")); res = vfat_unlink(new_dir,new_dentry); - PRINTK(("vfat_rename 10\n")); + PRINTK3(("vfat_rename 10\n")); if (res < 0) goto rename_done; } } } - PRINTK(("vfat_rename 11\n")); + PRINTK3(("vfat_rename 11\n")); fat_lock_creation(); locked = 1; res = vfat_find(new_dir,&new_dentry->d_name,1,1,is_dir,&sinfo); - PRINTK(("vfat_rename 12\n")); + PRINTK3(("vfat_rename 12\n")); if (res < 0) goto rename_done; new_offset = sinfo.shortname_offset; new_ino = sinfo.ino; - res = fat_get_entry(new_dir, &new_offset, &new_bh, &new_de); - PRINTK(("vfat_rename 13\n")); - if (res < 0) goto rename_done; - - new_de->attr = old_de->attr; - new_de->time = old_de->time; - new_de->date = old_de->date; - new_de->ctime_ms = old_de->ctime_ms; - new_de->cdate = old_de->cdate; - new_de->adate = old_de->adate; - new_de->start = old_de->start; - new_de->starthi = old_de->starthi; - new_de->size = old_de->size; + PRINTK3(("vfat_rename 13: new_ino=%d\n", new_ino)); if (!(new_inode = iget(new_dir->i_sb,new_ino))) goto rename_done; - PRINTK(("vfat_rename 14\n")); + put_new_inode = 1; - /* At this point, we have the inodes of the old file and the - * new file. We need to transfer all information from the old - * inode to the new inode and then delete the slots of the old - * entry - */ + new_inode->i_mode = old_inode->i_mode; + new_inode->i_size = old_inode->i_size; + new_inode->i_blocks = old_inode->i_blocks; + new_inode->i_mtime = old_inode->i_mtime; + new_inode->i_atime = old_inode->i_atime; + new_inode->i_ctime = old_inode->i_ctime; + MSDOS_I(new_inode)->i_ctime_ms = MSDOS_I(old_inode)->i_ctime_ms; + + MSDOS_I(new_inode)->i_start = MSDOS_I(old_inode)->i_start; + MSDOS_I(new_inode)->i_logstart = MSDOS_I(old_inode)->i_logstart; + MSDOS_I(new_inode)->i_attrs = MSDOS_I(old_inode)->i_attrs; + + mark_inode_dirty(new_inode); - vfat_read_inode(new_inode); - MSDOS_I(old_inode)->i_busy = 1; - MSDOS_I(old_inode)->i_linked = new_inode; - MSDOS_I(new_inode)->i_oldlink = old_inode; - fat_cache_inval_inode(old_inode); - PRINTK(("vfat_rename 15: old_slots=%d\n",old_slots)); - mark_inode_dirty(old_inode); old_dir->i_version = ++event; + new_dir->i_version = ++event; + + PRINTK3(("vfat_rename 14: old_slots=%d\n",old_slots)); /* remove the old entry */ for (i = old_slots; i > 0; --i) { res = fat_get_entry(old_dir, &old_longname_offset, &old_bh, &old_de); if (res < 0) { - printk("vfat_unlinkx: problem 1\n"); + printk("vfat_rename: problem 1\n"); continue; } old_de->name[0] = DELETED_FLAG; old_de->attr = 0; fat_mark_buffer_dirty(sb, old_bh, 1); } - PRINTK(("vfat_rename 15b\n")); - - fat_mark_buffer_dirty(sb, new_bh, 1); + PRINTK3(("vfat_rename 15b\n")); - /* XXX: There is some code in the original MSDOS rename that - * is not duplicated here and it might cause a problem in - * certain circumstances. - */ - if (S_ISDIR(old_inode->i_mode)) { if ((res = fat_scan(old_inode,MSDOS_DOTDOT,&dotdot_bh, &dotdot_de,&dotdot_ino,SCAN_ANY)) < 0) goto rename_done; @@ -1793,8 +1810,11 @@ } if (res > 0) res = 0; + if (res == 0) { + drop_replace_inodes(old_dentry, new_inode); d_move(old_dentry, new_dentry); + put_new_inode = 0; } rename_done: @@ -1804,6 +1824,8 @@ fat_brelse(sb, old_bh); if (new_bh) fat_brelse(sb, new_bh); + if (put_new_inode) + iput(new_inode); return res; } diff -u --recursive --new-file v2.1.80/linux/include/asm-i386/hardirq.h linux/include/asm-i386/hardirq.h --- v2.1.80/linux/include/asm-i386/hardirq.h Tue Jan 20 12:52:08 1998 +++ linux/include/asm-i386/hardirq.h Fri Jan 23 13:08:54 1998 @@ -15,7 +15,6 @@ #define hardirq_exit(cpu) (local_irq_count[cpu]--) #define synchronize_irq() do { } while (0) -#define synchronize_one_irq(x) do { } while (0) #else @@ -30,7 +29,7 @@ /* if we didn't own the irq lock, just ignore.. */ if (global_irq_holder == (unsigned char) cpu) { global_irq_holder = NO_PROC_ID; - global_irq_lock = 0; + clear_bit(0,&global_irq_lock); } } @@ -70,7 +69,6 @@ } extern void synchronize_irq(void); -extern void synchronize_one_irq(unsigned int irq); #endif /* __SMP__ */ diff -u --recursive --new-file v2.1.80/linux/include/asm-i386/smp.h linux/include/asm-i386/smp.h --- v2.1.80/linux/include/asm-i386/smp.h Sun Dec 21 17:27:18 1997 +++ linux/include/asm-i386/smp.h Wed Jan 21 12:04:45 1998 @@ -159,7 +159,6 @@ extern unsigned char boot_cpu_id; extern unsigned long cpu_present_map; extern volatile int cpu_number_map[NR_CPUS]; -extern volatile int cpu_logical_map[NR_CPUS]; extern volatile unsigned long smp_invalidate_needed; extern void smp_flush_tlb(void); extern volatile unsigned long kernel_flag, kernel_counter; @@ -171,6 +170,11 @@ extern void smp_invalidate_rcv(void); /* Process an NMI */ extern void smp_local_timer_interrupt(struct pt_regs * regs); extern void setup_APIC_clock (void); +extern volatile int __cpu_logical_map[NR_CPUS]; +extern inline int cpu_logical_map(int cpu) +{ + return __cpu_logical_map[cpu]; +} /* @@ -235,5 +239,12 @@ #define SMP_FROM_INT 1 #define SMP_FROM_SYSCALL 2 +#else +#ifndef ASSEMBLY +extern inline int cpu_logical_map(int cpu) +{ + return cpu; +} +#endif #endif #endif diff -u --recursive --new-file v2.1.80/linux/include/asm-i386/softirq.h linux/include/asm-i386/softirq.h --- v2.1.80/linux/include/asm-i386/softirq.h Tue Jan 20 12:57:40 1998 +++ linux/include/asm-i386/softirq.h Fri Jan 23 13:39:52 1998 @@ -4,6 +4,9 @@ #include #include +extern unsigned int local_bh_count[NR_CPUS]; +#define in_bh() (local_bh_count[smp_processor_id()] != 0) + #define get_active_bhs() (bh_mask & bh_active) #define clear_active_bhs(x) atomic_clear_mask((x),&bh_active) @@ -25,23 +28,6 @@ set_bit(nr, &bh_active); } -/* - * These use a mask count to correctly handle - * nested disable/enable calls - */ -extern inline void disable_bh(int nr) -{ - bh_mask &= ~(1 << nr); - bh_mask_count[nr]++; - synchronize_irq(); -} - -extern inline void enable_bh(int nr) -{ - if (!--bh_mask_count[nr]) - bh_mask |= 1 << nr; -} - #ifdef __SMP__ /* @@ -49,52 +35,83 @@ * is entirely private to an implementation, it should not be * referenced at all outside of this file. */ -extern atomic_t __intel_bh_counter; +extern atomic_t global_bh_lock; +extern atomic_t global_bh_count; -extern inline void start_bh_atomic(void) +extern void synchronize_bh(void); + +static inline void start_bh_atomic(void) { - atomic_inc(&__intel_bh_counter); - synchronize_irq(); + atomic_inc(&global_bh_lock); + synchronize_bh(); } -extern inline void end_bh_atomic(void) +static inline void end_bh_atomic(void) { - atomic_dec(&__intel_bh_counter); + atomic_dec(&global_bh_lock); } /* These are for the irq's testing the lock */ -static inline int softirq_trylock(void) +static inline int softirq_trylock(int cpu) { - atomic_inc(&__intel_bh_counter); - if (atomic_read(&__intel_bh_counter) != 1) { - atomic_dec(&__intel_bh_counter); + unsigned long flags; + + __save_flags(flags); + __cli(); + atomic_inc(&global_bh_count); + if (atomic_read(&global_bh_count) != 1 || atomic_read(&global_bh_lock) != 0) { + atomic_dec(&global_bh_count); + __restore_flags(flags); return 0; } + ++local_bh_count[cpu]; return 1; } -#define softirq_endlock() atomic_dec(&__intel_bh_counter) +static inline void softirq_endlock(int cpu) +{ + __cli(); + atomic_dec(&global_bh_count); + local_bh_count[cpu]--; + __sti(); +} #else -extern int __intel_bh_counter; - extern inline void start_bh_atomic(void) { - __intel_bh_counter++; + local_bh_count[smp_processor_id()]++; barrier(); } extern inline void end_bh_atomic(void) { barrier(); - __intel_bh_counter--; + local_bh_count[smp_processor_id()]--; } /* These are for the irq's testing the lock */ -#define softirq_trylock() (__intel_bh_counter ? 0 : (__intel_bh_counter=1)) -#define softirq_endlock() (__intel_bh_counter = 0) +#define softirq_trylock() (in_bh ? 0 : (local_bh_count[smp_processor_id()]=1)) +#define softirq_endlock() (local_bh_count[smp_processor_id()] = 0) +#define synchronize_bh() do { } while (0) #endif /* SMP */ + +/* + * These use a mask count to correctly handle + * nested disable/enable calls + */ +extern inline void disable_bh(int nr) +{ + bh_mask &= ~(1 << nr); + bh_mask_count[nr]++; + synchronize_bh(); +} + +extern inline void enable_bh(int nr) +{ + if (!--bh_mask_count[nr]) + bh_mask |= 1 << nr; +} #endif /* __ASM_SOFTIRQ_H */ diff -u --recursive --new-file v2.1.80/linux/include/asm-i386/uaccess.h linux/include/asm-i386/uaccess.h --- v2.1.80/linux/include/asm-i386/uaccess.h Tue Jan 20 16:51:57 1998 +++ linux/include/asm-i386/uaccess.h Fri Jan 23 17:18:35 1998 @@ -263,7 +263,7 @@ " .long 0b,3b\n" \ " .long 1b,2b\n" \ ".previous" \ - : "=c"(size) \ + : "=&c"(size) \ : "r"(size & 3), "0"(size / 4), "D"(to), "S"(from) \ : "di", "si", "memory") diff -u --recursive --new-file v2.1.80/linux/include/asm-i386/unistd.h linux/include/asm-i386/unistd.h --- v2.1.80/linux/include/asm-i386/unistd.h Mon Dec 1 11:16:19 1997 +++ linux/include/asm-i386/unistd.h Fri Jan 23 16:24:01 1998 @@ -187,6 +187,7 @@ #define __NR_rt_sigsuspend 179 #define __NR_pread 180 #define __NR_pwrite 181 +#define __NR_lchown 182 /* user-visible error numbers are in the range -1 - -122: see */ diff -u --recursive --new-file v2.1.80/linux/include/asm-mips/ioctls.h linux/include/asm-mips/ioctls.h --- v2.1.80/linux/include/asm-mips/ioctls.h Tue Dec 16 12:46:07 1997 +++ linux/include/asm-mips/ioctls.h Fri Jan 23 16:39:04 1998 @@ -98,6 +98,7 @@ #define TIOCTTYGSTRUCT 0x5487 /* For debugging only */ #define TIOCSBRK 0x5427 /* BSD compatibility */ #define TIOCCBRK 0x5428 /* BSD compatibility */ +#define TIOCGSID 0x5429 /* Return the session ID of FD */ #define TIOCSERCONFIG 0x5488 #define TIOCSERGWILD 0x5489 diff -u --recursive --new-file v2.1.80/linux/include/linux/blk.h linux/include/linux/blk.h --- v2.1.80/linux/include/linux/blk.h Tue Jan 20 16:51:57 1998 +++ linux/include/linux/blk.h Fri Jan 23 17:38:05 1998 @@ -39,6 +39,9 @@ #ifdef CONFIG_CDROM extern int cdrom_init(void); #endif CONFIG_CDROM +#ifdef CONFIG_ISP16_CDI +extern int isp16_init(void); +#endif CONFIG_ISP16_CDI #ifdef CONFIG_CDU31A extern int cdu31a_init(void); #endif CONFIG_CDU31A diff -u --recursive --new-file v2.1.80/linux/include/linux/kernel_stat.h linux/include/linux/kernel_stat.h --- v2.1.80/linux/include/linux/kernel_stat.h Tue Jan 20 12:57:40 1998 +++ linux/include/linux/kernel_stat.h Wed Jan 21 12:13:57 1998 @@ -2,6 +2,7 @@ #define _LINUX_KERNEL_STAT_H #include +#include #include #include @@ -25,7 +26,7 @@ unsigned int dk_drive_wblk[DK_NDRIVE]; unsigned int pgpgin, pgpgout; unsigned int pswpin, pswpout; - unsigned int interrupts[NR_CPUS][NR_IRQS]; + unsigned int irqs[NR_CPUS][NR_IRQS]; unsigned int ipackets, opackets; unsigned int ierrors, oerrors; unsigned int collisions; @@ -33,5 +34,18 @@ }; extern struct kernel_stat kstat; + +/* + * Number of interrupts per specific IRQ source, since bootup + */ +extern inline int kstat_irqs (int irq) +{ + int i, sum=0; + + for (i = 0 ; i < smp_num_cpus ; i++) + sum += kstat.irqs[cpu_logical_map(i)][irq]; + + return sum; +} #endif /* _LINUX_KERNEL_STAT_H */ diff -u --recursive --new-file v2.1.80/linux/include/linux/minix_fs_sb.h linux/include/linux/minix_fs_sb.h --- v2.1.80/linux/include/linux/minix_fs_sb.h Thu Jan 4 04:07:58 1996 +++ linux/include/linux/minix_fs_sb.h Wed Jan 21 14:27:57 1998 @@ -12,10 +12,10 @@ unsigned long s_firstdatazone; unsigned long s_log_zone_size; unsigned long s_max_size; - struct buffer_head * s_imap[8]; - struct buffer_head * s_zmap[64]; unsigned long s_dirsize; unsigned long s_namelen; + struct buffer_head ** s_imap; + struct buffer_head ** s_zmap; struct buffer_head * s_sbh; struct minix_super_block * s_ms; unsigned short s_mount_state; diff -u --recursive --new-file v2.1.80/linux/include/linux/msdos_fs_i.h linux/include/linux/msdos_fs_i.h --- v2.1.80/linux/include/linux/msdos_fs_i.h Thu Oct 23 14:00:15 1997 +++ linux/include/linux/msdos_fs_i.h Wed Jan 21 17:46:56 1998 @@ -28,16 +28,9 @@ int i_start; /* first cluster or 0 */ int i_logstart; /* logical first cluster */ int i_attrs; /* unused attribute bits */ + int i_ctime_ms; /* unused change time in milliseconds */ int i_busy; /* file is either deleted but still open, or inconsistent (mkdir) */ - struct inode *i_depend; /* pointer to inode that depends on the - current inode */ - struct inode *i_old; /* pointer to the old inode this inode - depends on */ - struct inode *i_linked; /* pointer to inode linked to the current one, - happens when an open file is moved */ - struct inode *i_oldlink;/* pointer to open inode that references - the same file */ int i_binary; /* file contains non-text data */ }; diff -u --recursive --new-file v2.1.80/linux/include/linux/nfsd/nfsfh.h linux/include/linux/nfsd/nfsfh.h --- v2.1.80/linux/include/linux/nfsd/nfsfh.h Tue Jan 20 16:53:27 1998 +++ linux/include/linux/nfsd/nfsfh.h Fri Jan 23 17:20:30 1998 @@ -116,12 +116,16 @@ dfprintk(FILEOP, "nfsd: fh_lock(%x/%ld) locked = %d\n", SVCFH_DEV(fhp), SVCFH_INO(fhp), fhp->fh_locked); */ - if (!fhp->fh_locked) { - down(&inode->i_sem); - if (!fhp->fh_pre_mtime) - fhp->fh_pre_mtime = inode->i_mtime; - fhp->fh_locked = 1; + if (fhp->fh_locked) { + printk(KERN_WARNING "fh_lock: %s/%s already locked!\n", + fhp->fh_dentry->d_parent->d_name.name, + fhp->fh_dentry->d_name.name); + return; } + down(&inode->i_sem); + if (!fhp->fh_pre_mtime) + fhp->fh_pre_mtime = inode->i_mtime; + fhp->fh_locked = 1; } /* @@ -130,9 +134,8 @@ static inline void fh_unlock(struct svc_fh *fhp) { - struct inode *inode = fhp->fh_dentry->d_inode; - if (fhp->fh_locked) { + struct inode *inode = fhp->fh_dentry->d_inode; if (!fhp->fh_post_version) fhp->fh_post_version = inode->i_version; fhp->fh_locked = 0; diff -u --recursive --new-file v2.1.80/linux/include/linux/signal.h linux/include/linux/signal.h --- v2.1.80/linux/include/linux/signal.h Tue Dec 9 09:31:46 1997 +++ linux/include/linux/signal.h Fri Jan 23 17:38:05 1998 @@ -174,6 +174,11 @@ set->sig[0] &= ~mask; } +extern inline int sigtestsetmask(sigset_t *set, unsigned long mask) +{ + return (set->sig[0] & mask) != 0; +} + extern inline void siginitset(sigset_t *set, unsigned long mask) { set->sig[0] = mask; diff -u --recursive --new-file v2.1.80/linux/include/linux/smb_fs.h linux/include/linux/smb_fs.h --- v2.1.80/linux/include/linux/smb_fs.h Tue Jan 20 16:53:52 1998 +++ linux/include/linux/smb_fs.h Fri Jan 23 17:21:03 1998 @@ -76,6 +76,7 @@ */ #define SMB_FIX_WIN95 0x0001 /* Win 95 server */ #define SMB_FIX_OLDATTR 0x0002 /* Use core getattr (Win 95 speedup) */ +#define SMB_FIX_DIRATTR 0x0004 /* Use find_first for getattr */ /* linux/fs/smbfs/mmap.c */ int smb_mmap(struct file *, struct vm_area_struct *); @@ -95,7 +96,6 @@ void smb_get_inode_attr(struct inode *, struct smb_fattr *); void smb_invalidate_inodes(struct smb_sb_info *); int smb_revalidate_inode(struct dentry *); -int smb_refresh_inode(struct inode *); int smb_notify_change(struct dentry *, struct iattr *); unsigned long smb_invent_inos(unsigned long); struct inode *smb_iget(struct super_block *, struct smb_fattr *); @@ -112,8 +112,8 @@ void smb_close_dentry(struct dentry *); int smb_close_fileid(struct dentry *, __u16); int smb_open(struct dentry *, int); -int smb_proc_read(struct inode *, off_t, int, char *); -int smb_proc_write(struct inode *, off_t, int, const char *); +int smb_proc_read(struct dentry *, off_t, int, char *); +int smb_proc_write(struct dentry *, off_t, int, const char *); int smb_proc_create(struct dentry *, __u16, time_t, __u16 *); int smb_proc_mv(struct dentry *, struct dentry *); int smb_proc_mkdir(struct dentry *); diff -u --recursive --new-file v2.1.80/linux/include/linux/smb_fs_i.h linux/include/linux/smb_fs_i.h --- v2.1.80/linux/include/linux/smb_fs_i.h Tue Dec 9 00:07:19 1997 +++ linux/include/linux/smb_fs_i.h Wed Jan 21 10:09:31 1998 @@ -21,15 +21,14 @@ * file handles are local to a connection. A file is open if * (open == generation). */ - unsigned int open; + unsigned int open; /* open generation */ __u16 fileid; /* What id to handle a file with? */ __u16 attr; /* Attribute fields, DOS value */ - __u16 access; /* Access bits. */ + __u16 access; /* Access mode */ __u16 cache_valid; /* dircache valid? */ unsigned long oldmtime; /* last time refreshed */ unsigned long closed; /* timestamp when closed */ - void * dentry; /* The dentry we were opened with */ }; #endif diff -u --recursive --new-file v2.1.80/linux/include/linux/smp.h linux/include/linux/smp.h --- v2.1.80/linux/include/linux/smp.h Tue Jan 20 12:52:08 1998 +++ linux/include/linux/smp.h Wed Jan 21 12:10:52 1998 @@ -61,5 +61,6 @@ #define smp_message_pass(t,m,d,w) #define smp_threads_ready 1 #define kernel_lock() + #endif #endif diff -u --recursive --new-file v2.1.80/linux/include/linux/tty.h linux/include/linux/tty.h --- v2.1.80/linux/include/linux/tty.h Tue Jan 20 16:51:56 1998 +++ linux/include/linux/tty.h Fri Jan 23 17:38:05 1998 @@ -303,6 +303,7 @@ extern int pcxe_init(void); extern int pc_init(void); extern int vcs_init(void); +extern int rp_init(void); extern int cy_init(void); extern int stl_init(void); extern int stli_init(void); @@ -351,10 +352,6 @@ /* pcxx.c */ extern int pcxe_open(struct tty_struct *tty, struct file *filp); - -/* epca.c */ - -extern int pc_open(struct tty_struct *tty, struct file *filp); /* console.c */ diff -u --recursive --new-file v2.1.80/linux/include/linux/videodev.h linux/include/linux/videodev.h --- v2.1.80/linux/include/linux/videodev.h Mon Jan 12 14:48:22 1998 +++ linux/include/linux/videodev.h Fri Jan 23 17:38:05 1998 @@ -173,4 +173,14 @@ #define VID_HARDWARE_PMS 3 #define VID_HARDWARE_QCAM_C 4 +/* + * Initialiser list + */ + +struct video_init +{ + char *name; + int (*init)(struct video_init *); +}; + #endif diff -u --recursive --new-file v2.1.80/linux/init/main.c linux/init/main.c --- v2.1.80/linux/init/main.c Tue Jan 20 12:52:08 1998 +++ linux/init/main.c Wed Jan 21 13:00:05 1998 @@ -927,8 +927,6 @@ #else -extern void setup_IO_APIC(void); - /* * Multiprocessor idle thread is in arch/... */ @@ -1051,7 +1049,6 @@ printk("POSIX conformance testing by UNIFIX\n"); #ifdef __SMP__ smp_init(); - setup_IO_APIC(); #endif #ifdef CONFIG_SYSCTL sysctl_init(); diff -u --recursive --new-file v2.1.80/linux/kernel/acct.c linux/kernel/acct.c --- v2.1.80/linux/kernel/acct.c Mon Dec 1 10:34:12 1997 +++ linux/kernel/acct.c Fri Jan 23 17:38:05 1998 @@ -268,8 +268,8 @@ /* - * Fill the accounting struct with the needed info as recorded by the different - * kernel functions. + * Fill the accounting struct with the needed info as recorded + * by the different kernel functions. */ memset((caddr_t)&ac, 0, sizeof(struct acct)); @@ -304,7 +304,7 @@ } vsize = vsize / 1024; ac.ac_mem = encode_comp_t(vsize); - ac.ac_io = encode_comp_t(current->io_usage); + ac.ac_io = encode_comp_t(current->io_usage); /* %% */ ac.ac_rw = encode_comp_t(ac.ac_io / 1024); ac.ac_minflt = encode_comp_t(current->min_flt); ac.ac_majflt = encode_comp_t(current->maj_flt); diff -u --recursive --new-file v2.1.80/linux/kernel/fork.c linux/kernel/fork.c --- v2.1.80/linux/kernel/fork.c Wed Jan 14 13:21:14 1998 +++ linux/kernel/fork.c Wed Jan 21 10:06:56 1998 @@ -437,7 +437,6 @@ */ int do_fork(unsigned long clone_flags, unsigned long usp, struct pt_regs *regs) { - int i; int nr; int error = -ENOMEM; struct task_struct *p; @@ -483,11 +482,14 @@ p->times.tms_utime = p->times.tms_stime = 0; p->times.tms_cutime = p->times.tms_cstime = 0; #ifdef __SMP__ - p->has_cpu = 0; - p->processor = NO_PROC_ID; - /* ?? should we just memset this ?? */ - for(i = 0; i < smp_num_cpus; i++) - p->per_cpu_utime[i] = p->per_cpu_stime[i] = 0; + { + int i; + p->has_cpu = 0; + p->processor = NO_PROC_ID; + /* ?? should we just memset this ?? */ + for(i = 0; i < smp_num_cpus; i++) + p->per_cpu_utime[i] = p->per_cpu_stime[i] = 0; + } #endif p->lock_depth = 0; p->start_time = jiffies; diff -u --recursive --new-file v2.1.80/linux/kernel/printk.c linux/kernel/printk.c --- v2.1.80/linux/kernel/printk.c Tue Jan 20 16:45:08 1998 +++ linux/kernel/printk.c Fri Jan 23 16:53:00 1998 @@ -229,9 +229,7 @@ static signed char msg_level = -1; long flags; - __save_flags(flags); - __cli(); - spin_lock(&console_lock); + spin_lock_irqsave(&console_lock, flags); va_start(args, fmt); i = vsprintf(buf + 3, fmt, args); /* hopefully i < sizeof(buf)-4 */ buf_end = buf + 3 + i; @@ -279,9 +277,8 @@ if (line_feed) msg_level = -1; } - spin_unlock(&console_lock); - __restore_flags(flags); -/* wake_up_interruptible(&log_wait);*/ + spin_unlock_irqrestore(&console_lock, flags); + wake_up_interruptible(&log_wait); return i; } diff -u --recursive --new-file v2.1.80/linux/kernel/softirq.c linux/kernel/softirq.c --- v2.1.80/linux/kernel/softirq.c Tue May 13 22:41:20 1997 +++ linux/kernel/softirq.c Fri Jan 23 15:38:20 1998 @@ -62,14 +62,14 @@ asmlinkage void do_bottom_half(void) { - if (softirq_trylock()) { - int cpu = smp_processor_id(); + int cpu = smp_processor_id(); + if (softirq_trylock(cpu)) { if (hardirq_trylock(cpu)) { __sti(); run_bottom_halves(); hardirq_endlock(cpu); } - softirq_endlock(); + softirq_endlock(cpu); } } diff -u --recursive --new-file v2.1.80/linux/net/ipv4/arp.c linux/net/ipv4/arp.c --- v2.1.80/linux/net/ipv4/arp.c Mon Jan 12 15:28:25 1998 +++ linux/net/ipv4/arp.c Wed Jan 21 10:11:32 1998 @@ -392,7 +392,9 @@ /* END OF OBSOLETE FUNCTIONS */ - +/* + * Note: requires bh_atomic locking. + */ int arp_bind_neighbour(struct dst_entry *dst) { struct device *dev = dst->dev; @@ -734,11 +736,9 @@ start_bh_atomic(); neigh = __neigh_lookup(&arp_tbl, &ip, dev, 1); if (neigh) { - unsigned state = 0; - if (r->arp_flags&ATF_PERM) + unsigned state = NUD_STALE; + if (r->arp_flags & ATF_PERM) state = NUD_PERMANENT; - else - state = NUD_STALE; err = neigh_update(neigh, (r->arp_flags&ATF_COM) ? r->arp_ha.sa_data : NULL, state, 1, 0); neigh_release(neigh); @@ -764,16 +764,21 @@ static int arp_req_get(struct arpreq *r, struct device *dev) { u32 ip = ((struct sockaddr_in *) &r->arp_pa)->sin_addr.s_addr; - struct neighbour *neigh = neigh_lookup(&arp_tbl, &ip, dev); + struct neighbour *neigh; + int err = -ENXIO; + + start_bh_atomic(); + neigh = __neigh_lookup(&arp_tbl, &ip, dev, 0); if (neigh) { memcpy(r->arp_ha.sa_data, neigh->ha, dev->addr_len); r->arp_ha.sa_family = dev->type; strncpy(r->arp_dev, dev->name, sizeof(r->arp_dev)); r->arp_flags = arp_state_to_flags(neigh); neigh_release(neigh); - return 0; + err = 0; } - return -ENXIO; + end_bh_atomic(); + return err; } int arp_req_delete(struct arpreq *r, struct device * dev) @@ -802,7 +807,7 @@ err = -ENXIO; start_bh_atomic(); - neigh = neigh_lookup(&arp_tbl, &ip, dev); + neigh = __neigh_lookup(&arp_tbl, &ip, dev, 0); if (neigh) { err = neigh_update(neigh, NULL, NUD_FAILED, 1, 0); neigh_release(neigh); @@ -856,6 +861,11 @@ err = -EINVAL; if ((r.arp_flags & ATF_COM) && r.arp_ha.sa_family != dev->type) goto out; + } else if (cmd != SIOCSARP) { + /* dev has not been set ... */ + printk(KERN_ERR "arp_ioctl: invalid, null device\n"); + err = -EINVAL; + goto out; } switch(cmd) { @@ -863,6 +873,7 @@ err = arp_req_delete(&r, dev); break; case SIOCSARP: + /* This checks for dev == NULL */ err = arp_req_set(&r, dev); break; case SIOCGARP: diff -u --recursive --new-file v2.1.80/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c --- v2.1.80/linux/net/ipv4/tcp.c Sun Jan 18 12:28:34 1998 +++ linux/net/ipv4/tcp.c Wed Jan 21 09:41:19 1998 @@ -614,7 +614,7 @@ mask |= POLLIN | POLLRDNORM; #if 1 /* This needs benchmarking and real world tests */ - space = sk->dst_cache->pmtu + 128; + space = (sk->dst_cache ? sk->dst_cache->pmtu : sk->mss) + 128; if (space < 2048) /* XXX */ space = 2048; #else /* 2.0 way */ @@ -663,7 +663,7 @@ return put_user(amount, (int *)arg); } default: - return(-EINVAL); + return(-ENOIOCTLCMD); }; } diff -u --recursive --new-file v2.1.80/linux/scripts/Menuconfig linux/scripts/Menuconfig --- v2.1.80/linux/scripts/Menuconfig Mon Jan 5 01:41:01 1998 +++ linux/scripts/Menuconfig Wed Jan 21 17:51:41 1998 @@ -40,6 +40,9 @@ # # 221297 Michael Chastain (mec@shout.net) - make define_bool actually # define its arguments so that later tests on them work right. +# +# 160198 Michael Chastain (mec@shout.net) - fix bug with 'c' command +# (complement existing value) when used on virgin uninitialized variables. #---------------------------------------------------------------------------- @@ -349,6 +352,7 @@ case $x in y) eval $1=n ;; n) eval $1=y ;; + *) eval $1=y ;; esac ;; *) eval $1=n ;; esac @@ -392,6 +396,7 @@ case $x in m) eval $1=n ;; n) eval $1=m ;; + *) eval $1=m ;; esac ;; *) eval $1=n ;; esac @@ -416,6 +421,7 @@ y) eval $1=n ;; n) eval $1=m ;; m) eval $1=y ;; + *) eval $1=y ;; esac ;; *) eval $1=n ;; esac