From f0e2d94970b2334593662b469d467eebe1c186a9 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 23 Nov 2007 15:14:34 -0500 Subject: [PATCH] Import 2.1.81 --- Documentation/00-INDEX | 2 + Documentation/binfmt_misc.txt | 73 +- Documentation/java.txt | 230 +- Documentation/smart-config.txt | 103 + Makefile | 4 +- arch/alpha/kernel/irq.c | 7 +- arch/alpha/lib/csum_partial_copy.c | 2 +- arch/i386/kernel/entry.S | 3 +- arch/i386/kernel/i386_ksyms.c | 2 +- arch/i386/kernel/irq.c | 439 +- arch/i386/kernel/irq.h | 2 + arch/i386/lib/usercopy.c | 2 +- drivers/block/floppy.c | 5 +- drivers/block/genhd.c | 2 + drivers/block/md.c | 3 +- drivers/block/ps2esdi.c | 28 +- drivers/cdrom/cdu31a.c | 2 + drivers/char/bttv.c | 29 +- drivers/char/busmouse.c | 1 - drivers/char/bw-qcam.c | 3 +- drivers/char/c-qcam.c | 1 + drivers/char/ftape/lowlevel/fdc-io.c | 19 +- drivers/char/ftape/lowlevel/ftape-ctl.c | 4 +- drivers/char/ftape/lowlevel/ftape-init.h | 9 +- drivers/char/ftape/lowlevel/ftape-rw.c | 9 +- drivers/char/ftape/lowlevel/ftape-tracing.h | 2 +- drivers/char/ftape/zftape/zftape-init.c | 29 +- drivers/char/mem.c | 7 +- drivers/char/misc.c | 3 + drivers/char/pms.c | 2 +- drivers/char/tpqic02.c | 18 +- drivers/char/videodev.c | 22 +- drivers/isdn/hisax/avm_a1.c | 8 +- drivers/isdn/hisax/elsa.c | 6 +- drivers/isdn/hisax/ix1_micro.c | 8 +- drivers/isdn/hisax/teles0.c | 8 +- drivers/isdn/hisax/teles3.c | 8 +- drivers/misc/parport_init.c | 2 - drivers/net/3c59x.c | 2 + drivers/net/dgrs.c | 2 +- drivers/net/lance.c | 4 +- drivers/net/sdla_fr.c | 2 +- drivers/scsi/53c7,8xx.c | 2 +- drivers/scsi/Makefile | 8 + drivers/scsi/NCR5380.c | 2 +- drivers/scsi/NCR53c406a.c | 2 +- drivers/scsi/advansys.c | 20675 ++++++++++++++++---------- drivers/scsi/advansys.h | 149 +- drivers/scsi/pci2000.h | 2 +- drivers/scsi/pci2220i.h | 2 +- drivers/scsi/pluto.c | 313 + drivers/scsi/pluto.h | 59 + drivers/scsi/psi240i.h | 2 +- drivers/scsi/scsi.c | 12 +- drivers/scsi/t128.c | 12 +- drivers/sound/audio.c | 2 +- drivers/sound/dev_table.c | 2 +- drivers/sound/gus_card.c | 105 +- drivers/sound/gus_midi.c | 171 +- drivers/sound/gus_vol.c | 37 +- drivers/sound/gus_wave.c | 3262 ++-- drivers/sound/soundcard.c | 3 +- fs/dcache.c | 1 + fs/fat/buffer.c | 136 +- fs/fat/cache.c | 11 +- fs/fat/dir.c | 8 +- fs/fat/file.c | 16 +- fs/fat/inode.c | 166 +- fs/fat/misc.c | 6 +- fs/fat/mmap.c | 13 +- fs/msdos/namei.c | 85 +- fs/nfsd/export.c | 28 +- fs/nfsd/nfsfh.c | 16 +- fs/nfsd/nfssvc.c | 7 + fs/ntfs/fs.c | 2 +- fs/open.c | 17 + fs/proc/root.c | 5 - fs/vfat/namei.c | 236 +- include/asm-i386/hardirq.h | 4 +- include/asm-i386/softirq.h | 85 +- include/asm-i386/uaccess.h | 2 +- include/asm-i386/unistd.h | 1 + include/asm-mips/ioctls.h | 1 + include/linux/blk.h | 3 + include/linux/msdos_fs_i.h | 9 +- include/linux/nfsd/nfsfh.h | 17 +- include/linux/signal.h | 5 + include/linux/tty.h | 5 +- include/linux/videodev.h | 10 + kernel/acct.c | 6 +- kernel/printk.c | 9 +- kernel/softirq.c | 6 +- scripts/Menuconfig | 6 + 93 files changed, 16023 insertions(+), 10838 deletions(-) rewrite Documentation/java.txt (83%) create mode 100644 Documentation/smart-config.txt create mode 100644 drivers/scsi/pluto.c create mode 100644 drivers/scsi/pluto.h diff --git a/Documentation/00-INDEX b/Documentation/00-INDEX index d4727eae0..7408fb62c 100644 --- a/Documentation/00-INDEX +++ b/Documentation/00-INDEX @@ -80,6 +80,8 @@ rtc.txt - 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 --git a/Documentation/binfmt_misc.txt b/Documentation/binfmt_misc.txt index 0adcf7185..6a8b87aff 100644 --- a/Documentation/binfmt_misc.txt +++ b/Documentation/binfmt_misc.txt @@ -54,10 +54,10 @@ A few examples (assumed you are in /proc/sys/fs/binfmt_misc): - 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 @@ You can remove one entry or all entries by echoing -1 to /proc/.../the_name 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 --git a/Documentation/java.txt b/Documentation/java.txt dissimilarity index 83% index f5205b1a4..a5439f730 100644 --- a/Documentation/java.txt +++ b/Documentation/java.txt @@ -1,111 +1,119 @@ - Java(tm) Binary Kernel Support for Linux v1.02 - ---------------------------------------------- - -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: - - 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": - - class HelloWorld { - public static void main(String args[]) { - System.out.println("Hello World!"); - } - } - - -Now compile the application with: - - /usr/local/java/bin/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. - - -Brian A. Lantz -brian@lantz.com -(/proc/sys/kernel/java-* support by Mike Shaver (shaver@ingenia.com)) - + Java(tm) Binary Kernel Support for Linux v1.02 + ---------------------------------------------- + +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 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. + + +To test your new setup, enter in the following simple Java app, and name +it "HelloWorld.java": + + class HelloWorld { + public static void main(String args[]) { + System.out.println("Hello World!"); + } + } + +Now compile the application with: + javac HelloWorld.java + +Set the executable permissions of the binary file, with: + chmod 755 HelloWorld.class + +And then execute it: + ./HelloWorld.class + + +To execute Java Applets, simple chmod the *.html files to include +the execution bit, then just do + ./Applet.html + + +originally by Brian A. Lantz, brian@lantz.com +heavily edited for binfmt_misc by Richard Günther. diff --git a/Documentation/smart-config.txt b/Documentation/smart-config.txt new file mode 100644 index 000000000..eda5c3dfa --- /dev/null +++ b/Documentation/smart-config.txt @@ -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 --git a/Makefile b/Makefile index 8ab1b6a9b..cbd647787 100644 --- a/Makefile +++ b/Makefile @@ -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/) @@ -346,7 +346,6 @@ clean: archclean 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 core `find . -size 0` rm -f vmlinux System.map rm -f .tmp* rm -f drivers/char/consolemap_deftbl.c drivers/char/conmakehash @@ -371,6 +370,7 @@ mrproper: clean 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 --git a/arch/alpha/kernel/irq.c b/arch/alpha/kernel/irq.c index ea3522f93..f94915bb2 100644 --- a/arch/alpha/kernel/irq.c +++ b/arch/alpha/kernel/irq.c @@ -373,7 +373,7 @@ int get_irq_list(char *buf) 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 @@ static inline void handle_irq(int irq, struct pt_regs * regs) 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 @@ static inline void device_interrupt(int irq, int ack, struct pt_regs * regs) } 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 @@ unsigned long probe_irq_on(void) */ int probe_irq_off(unsigned long irqs) { - unsigned long delay; int i; irqs &= irq_mask; diff --git a/arch/alpha/lib/csum_partial_copy.c b/arch/alpha/lib/csum_partial_copy.c index 24a45e7aa..1328eeaba 100644 --- a/arch/alpha/lib/csum_partial_copy.c +++ b/arch/alpha/lib/csum_partial_copy.c @@ -112,7 +112,7 @@ csum_partial_cfu_aligned(const unsigned long *src, unsigned long *dst, * 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 --git a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S index fd71492ad..a13a96dab 100644 --- a/arch/i386/kernel/entry.S +++ b/arch/i386/kernel/entry.S @@ -532,7 +532,8 @@ ENTRY(sys_call_table) .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 --git a/arch/i386/kernel/i386_ksyms.c b/arch/i386/kernel/i386_ksyms.c index 393b070aa..ab85b2df4 100644 --- a/arch/i386/kernel/i386_ksyms.c +++ b/arch/i386/kernel/i386_ksyms.c @@ -39,7 +39,7 @@ EXPORT_SYMBOL(local_irq_count); 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 --git a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c index 67f24e734..ac83e4c7d 100644 --- a/arch/i386/kernel/irq.c +++ b/arch/i386/kernel/irq.c @@ -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; @@ -129,53 +125,27 @@ static int irq_owner [NR_IRQS] = { NO_PROC_ID, }; * - explicitly use irq 16-19 depending on which PCI irq * line your PCI controller uses. */ - unsigned int io_apic_irqs = 0xFF0000; + 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); + cached_irq_mask |= 1 << irq; + if (irq & 8) { + outb(cached_A1,0xA1); + } else { + outb(cached_21,0x21); } +} - 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); - } +static inline void unmask_8259A(int irq) +{ + 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) @@ -393,8 +363,8 @@ unsigned char global_irq_holder = NO_PROC_ID; unsigned volatile int global_irq_lock; atomic_t global_irq_count; -#define irq_active(cpu) \ - (global_irq_count != local_irq_count[cpu]) +atomic_t global_bh_count; +atomic_t global_bh_lock; /* * "global_cli()" is a special case, in that it can hold the @@ -412,35 +382,56 @@ static inline void check_smp_invalidate(int cpu) } } -static unsigned long previous_irqholder; +static void show(char * str) +{ + int i; + unsigned long *stack; + int cpu = smp_processor_id(); + + printk("\n%s, CPU %d:\n", str, cpu); + printk("irq: %d [%d %d]\n", + atomic_read(&global_irq_count), local_irq_count[0], local_irq_count[1]); + printk("bh: %d [%d %d]\n", + atomic_read(&global_bh_count), local_bh_count[0], local_bh_count[1]); + stack = (unsigned long *) &str; + for (i = 40; i ; i--) { + unsigned long x = *++stack; + if (x > (unsigned long) &init_task_union && x < (unsigned long) &vsprintf) { + printk("<[%08lx]> ", x); + } + } +} + + +#define MAXCOUNT 100000000 -static inline void wait_on_irq(int cpu, unsigned long where) +static inline void wait_on_bh(void) { - int local_count = local_irq_count[cpu]; - - /* 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. - */ + 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); + 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; @@ -449,8 +440,24 @@ static inline void wait_on_irq(int cpu, unsigned long where) 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(); + } } } @@ -460,37 +467,15 @@ static inline void wait_on_irq(int cpu, unsigned long where) * 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(); @@ -618,23 +571,7 @@ again: __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; } @@ -644,94 +581,103 @@ again: */ 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); + } - handle_IRQ_event(irq,®s); - __restore_flags(flags); - return; + ack_APIC_irq(); + + spin_unlock(&irq_controller_lock); + + if (should_handle_irq) { +again: + if (!handle_IRQ_event(irq, regs)) + disabled_irq[irq] = 1; + + } + + 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; } - spin_unlock_irqrestore(&irq_controller_lock,flags); + + irq_owner[irq] = NO_PROC_ID; + hardirq_exit(cpu); + spin_unlock(&irq_controller_lock); + + enable_IO_APIC_irq(irq); } /* @@ -749,7 +695,9 @@ void enable_irq(unsigned int irq) * 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 @@ -761,16 +709,15 @@ asmlinkage void do_IRQ(struct pt_regs regs) * 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 diff --git a/arch/i386/kernel/irq.h b/arch/i386/kernel/irq.h index b7a4dc472..f1e2edea5 100644 --- a/arch/i386/kernel/irq.h +++ b/arch/i386/kernel/irq.h @@ -42,6 +42,8 @@ extern spinlock_t irq_controller_lock; /* #ifdef __SMP__ +#include + static inline void irq_enter(int cpu, int irq) { hardirq_enter(cpu); diff --git a/arch/i386/lib/usercopy.c b/arch/i386/lib/usercopy.c index 24b080f73..6b313d99c 100644 --- a/arch/i386/lib/usercopy.c +++ b/arch/i386/lib/usercopy.c @@ -89,7 +89,7 @@ strncpy_from_user(char *dst, const char *src, long count) " .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 --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 6628aa99e..94b90dd94 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -1710,10 +1710,11 @@ void floppy_interrupt(int irq, void *dev_id, struct pt_regs * regs) } 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 --git a/drivers/block/genhd.c b/drivers/block/genhd.c index 6b39919f2..966a4031e 100644 --- a/drivers/block/genhd.c +++ b/drivers/block/genhd.c @@ -776,7 +776,9 @@ static int mac_partition(struct gendisk *hd, kdev_t dev, unsigned long fsec) 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 --git a/drivers/block/md.c b/drivers/block/md.c index 789b8e04d..8c592c751 100644 --- a/drivers/block/md.c +++ b/drivers/block/md.c @@ -493,7 +493,7 @@ static int do_md_stop (int minor, struct inode *inode) /* * 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 @@ EXPORT_SYMBOL(md_do_sync); 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 --git a/drivers/block/ps2esdi.c b/drivers/block/ps2esdi.c index b4d5146de..b109192fb 100644 --- a/drivers/block/ps2esdi.c +++ b/drivers/block/ps2esdi.c @@ -1038,14 +1038,9 @@ static void dump_cmd_complete_status(u_int int_ret_code) } - 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_open(struct inode *inode, struct file *file) 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 @@ static int ps2esdi_ioctl(struct inode *inode, { 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_ioctl(struct inode *inode, 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 @@ static int ps2esdi_reread_partitions(int dev) 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 --git a/drivers/cdrom/cdu31a.c b/drivers/cdrom/cdu31a.c index 743424258..9a7b26871 100644 --- a/drivers/cdrom/cdu31a.c +++ b/drivers/cdrom/cdu31a.c @@ -1242,6 +1242,7 @@ size_to_buf(unsigned int size, 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 @@ static int scd_disc_status(struct cdrom_device_info *cdi) } 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 --git a/drivers/char/bttv.c b/drivers/char/bttv.c index 414918727..cd821406f 100644 --- a/drivers/char/bttv.c +++ b/drivers/char/bttv.c @@ -129,16 +129,22 @@ static int I2CRead(struct bttv *btv, int addr) 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 @@ static int I2CWrite(struct bttv *btv, unchar addr, unchar b1, 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 @@ static void write_risc_data(struct bttv *btv, struct video_clip *vp, int count) /* * 32bit depth frame buffers need extra flags setting */ - + if (depth==4) mask=BT848_RISC_BYTE3; else @@ -1093,13 +1102,13 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg) 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 --git a/drivers/char/busmouse.c b/drivers/char/busmouse.c index a33a6a8c2..82a8765fa 100644 --- a/drivers/char/busmouse.c +++ b/drivers/char/busmouse.c @@ -109,7 +109,6 @@ static void mouse_interrupt(int irq, void *dev_id, struct pt_regs *regs) 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 --git a/drivers/char/bw-qcam.c b/drivers/char/bw-qcam.c index a64b98a24..0ba7df6b7 100644 --- a/drivers/char/bw-qcam.c +++ b/drivers/char/bw-qcam.c @@ -923,11 +923,12 @@ void cleanup_module(void) 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 --git a/drivers/char/c-qcam.c b/drivers/char/c-qcam.c index c2eb77040..df12a3413 100644 --- a/drivers/char/c-qcam.c +++ b/drivers/char/c-qcam.c @@ -771,5 +771,6 @@ __initfunc(int init_colour_qcams(struct video_init *unused)) for (port = parport_enumerate(); port; port=port->next) init_cqcam(port); + return 0; } #endif diff --git a/drivers/char/ftape/lowlevel/fdc-io.c b/drivers/char/ftape/lowlevel/fdc-io.c index 47229c5b4..fd1ac0cd7 100644 --- a/drivers/char/ftape/lowlevel/fdc-io.c +++ b/drivers/char/ftape/lowlevel/fdc-io.c @@ -385,7 +385,7 @@ int fdc_issue_command(const __u8 * out_data, int out_count, 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 @@ int fdc_interrupt_wait(unsigned int time) /* 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 --git a/drivers/char/ftape/lowlevel/ftape-ctl.c b/drivers/char/ftape/lowlevel/ftape-ctl.c index 1ce4c2843..05f1f6146 100644 --- a/drivers/char/ftape/lowlevel/ftape-ctl.c +++ b/drivers/char/ftape/lowlevel/ftape-ctl.c @@ -794,8 +794,8 @@ void ftape_disable(void) 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 --git a/drivers/char/ftape/lowlevel/ftape-init.h b/drivers/char/ftape/lowlevel/ftape-init.h index eae86b3dc..35ae7f94d 100644 --- a/drivers/char/ftape/lowlevel/ftape-init.h +++ b/drivers/char/ftape/lowlevel/ftape-init.h @@ -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 --git a/drivers/char/ftape/lowlevel/ftape-rw.c b/drivers/char/ftape/lowlevel/ftape-rw.c index e3e0243f0..2ae96344e 100644 --- a/drivers/char/ftape/lowlevel/ftape-rw.c +++ b/drivers/char/ftape/lowlevel/ftape-rw.c @@ -432,7 +432,8 @@ int ftape_dumb_stop(void) */ 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 @@ static int seek_forward(int segment_id, int fast) * 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 @@ static int skip_reverse(int segment_id, int *pstatus) 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 @@ int ftape_start_tape(int segment_id, int sector_offset) 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 --git a/drivers/char/ftape/lowlevel/ftape-tracing.h b/drivers/char/ftape/lowlevel/ftape-tracing.h index ac675568a..7f93942a5 100644 --- a/drivers/char/ftape/lowlevel/ftape-tracing.h +++ b/drivers/char/ftape/lowlevel/ftape-tracing.h @@ -171,7 +171,7 @@ extern void ftape_trace_log (const char *file, const char *name); * 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 --git a/drivers/char/ftape/zftape/zftape-init.c b/drivers/char/ftape/zftape/zftape-init.c index c6a4f4506..0cb9f018f 100644 --- a/drivers/char/ftape/zftape/zftape-init.c +++ b/drivers/char/ftape/zftape/zftape-init.c @@ -73,7 +73,7 @@ const ftape_info *zft_status; /* 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 @@ static int zft_open(struct inode *ino, struct file *filep) 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 @@ static int zft_open(struct inode *ino, struct file *filep) /* 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 @@ static void zft_close(struct inode *ino, struct file *filep) 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 @@ static int zft_ioctl(struct inode *ino, struct file *filep, 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 @@ static int zft_ioctl(struct inode *ino, struct file *filep, "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 @@ static int zft_mmap(struct inode *ino, #endif { int result = -EIO; - int old_sigmask; + sigset_t old_sigmask; TRACE_FUN(ft_t_flow); if (!busy_flag || @@ -276,7 +273,7 @@ static int zft_mmap(struct inode *ino, "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 @@ static int zft_read(struct inode *ino, struct file *fp, char *buff, #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 @@ static int zft_read(struct inode *ino, struct file *fp, char *buff, "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 @@ static int zft_write(struct inode *ino, struct file *fp, char *buff, #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 @@ static int zft_write(struct inode *ino, struct file *fp, char *buff, "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 --git a/drivers/char/mem.c b/drivers/char/mem.c index 3b9f3bf5a..5aacad357 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -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 --git a/drivers/char/misc.c b/drivers/char/misc.c index fed2005cd..98b74551c 100644 --- a/drivers/char/misc.c +++ b/drivers/char/misc.c @@ -78,6 +78,9 @@ extern int dsp56k_init(void); 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 --git a/drivers/char/pms.c b/drivers/char/pms.c index d87e436a6..2ef2f5ccb 100644 --- a/drivers/char/pms.c +++ b/drivers/char/pms.c @@ -610,7 +610,7 @@ static int pms_capture(struct pms_device *dev, char *buf, int rgb555, int count) { 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 --git a/drivers/char/tpqic02.c b/drivers/char/tpqic02.c index df4dff23f..461e58165 100644 --- a/drivers/char/tpqic02.c +++ b/drivers/char/tpqic02.c @@ -1766,8 +1766,10 @@ static ssize_t qic02_tape_read(struct file * filp, char * buf, size_t count, lof 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 @@ static ssize_t qic02_tape_write( struct file * filp, const char * buf, 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 @@ static ssize_t qic02_tape_write( struct file * filp, const char * buf, 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 @@ static int qic02_get_resources(void) return 0; } /* qic02_get_resources */ -__initfunc(static int qic02_tape_init(void)) +__initfunc(int qic02_tape_init(void)) { if (TPSTATSIZE != 6) { diff --git a/drivers/char/videodev.c b/drivers/char/videodev.c index c5a15294e..9fd8b17f1 100644 --- a/drivers/char/videodev.c +++ b/drivers/char/videodev.c @@ -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 @@ static struct video_init video_init_list[]={ {"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 struct video_init video_init_list[]={ 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_read(struct file *file, 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 --git a/drivers/isdn/hisax/avm_a1.c b/drivers/isdn/hisax/avm_a1.c index 8b5bea45d..a35d1c71f 100644 --- a/drivers/isdn/hisax/avm_a1.c +++ b/drivers/isdn/hisax/avm_a1.c @@ -772,7 +772,7 @@ initavm_a1(struct IsdnCardState *sp) 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 @@ initavm_a1(struct IsdnCardState *sp) /* 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 --git a/drivers/isdn/hisax/elsa.c b/drivers/isdn/hisax/elsa.c index 28db33235..430d2409c 100644 --- a/drivers/isdn/hisax/elsa.c +++ b/drivers/isdn/hisax/elsa.c @@ -1180,7 +1180,7 @@ initelsa(struct IsdnCardState *sp) 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 @@ initelsa(struct IsdnCardState *sp) } #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 --git a/drivers/isdn/hisax/ix1_micro.c b/drivers/isdn/hisax/ix1_micro.c index 707635261..bd595d0c8 100644 --- a/drivers/isdn/hisax/ix1_micro.c +++ b/drivers/isdn/hisax/ix1_micro.c @@ -841,7 +841,7 @@ initix1micro(struct IsdnCardState *sp) 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 @@ initix1micro(struct IsdnCardState *sp) /* 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 --git a/drivers/isdn/hisax/teles0.c b/drivers/isdn/hisax/teles0.c index 0560eff88..e14c01c09 100644 --- a/drivers/isdn/hisax/teles0.c +++ b/drivers/isdn/hisax/teles0.c @@ -802,7 +802,7 @@ initteles0(struct IsdnCardState *sp) 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 @@ initteles0(struct IsdnCardState *sp) /* 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 --git a/drivers/isdn/hisax/teles3.c b/drivers/isdn/hisax/teles3.c index c83a00958..22254604c 100644 --- a/drivers/isdn/hisax/teles3.c +++ b/drivers/isdn/hisax/teles3.c @@ -801,7 +801,7 @@ initteles3(struct IsdnCardState *sp) 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 @@ initteles3(struct IsdnCardState *sp) /* 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 --git a/drivers/misc/parport_init.c b/drivers/misc/parport_init.c index dbe4dd354..1ccb67d32 100644 --- a/drivers/misc/parport_init.c +++ b/drivers/misc/parport_init.c @@ -68,8 +68,6 @@ void cleanup_module(void) #else __initfunc(int parport_init(void)) { - struct parport *pb; - if (io[0] == PARPORT_DISABLE) return 1; diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index efcaf39cd..65d6f8b6b 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -482,9 +482,11 @@ static void set_multicast_list(struct device *dev, int num_addrs, void *addrs); /* 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 --git a/drivers/net/dgrs.c b/drivers/net/dgrs.c index 1b0d3aae2..4e29cb6ab 100644 --- a/drivers/net/dgrs.c +++ b/drivers/net/dgrs.c @@ -1250,12 +1250,12 @@ dgrs_found_device( )) { 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 --git a/drivers/net/lance.c b/drivers/net/lance.c index 97d0f27d6..f7df41bb5 100644 --- a/drivers/net/lance.c +++ b/drivers/net/lance.c @@ -611,7 +611,7 @@ __initfunc(void lance_probe1(int ioaddr)) 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 @@ lance_open(struct device *dev) /* 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 --git a/drivers/net/sdla_fr.c b/drivers/net/sdla_fr.c index d11e088b7..77e338537 100644 --- a/drivers/net/sdla_fr.c +++ b/drivers/net/sdla_fr.c @@ -1,4 +1,4 @@ - +/**************************************************************************** * sdla_fr.c WANPIPE(tm) Multiprotocol WAN Link Driver. Frame relay module. * * Author(s): Gene Kozin diff --git a/drivers/scsi/53c7,8xx.c b/drivers/scsi/53c7,8xx.c index 5f1a4d8da..092b8500a 100644 --- a/drivers/scsi/53c7,8xx.c +++ b/drivers/scsi/53c7,8xx.c @@ -5958,7 +5958,7 @@ print_queues (struct Scsi_Host *host) { 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 --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index 36e04de28..11e0b203a 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -430,6 +430,14 @@ else 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 --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c index 6ecc0f1aa..6eccb24c7 100644 --- a/drivers/scsi/NCR5380.c +++ b/drivers/scsi/NCR5380.c @@ -625,7 +625,7 @@ static inline void NCR5380_all_init (void) { */ -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 --git a/drivers/scsi/NCR53c406a.c b/drivers/scsi/NCR53c406a.c index e29af7ad8..d2529b17e 100644 --- a/drivers/scsi/NCR53c406a.c +++ b/drivers/scsi/NCR53c406a.c @@ -1012,7 +1012,7 @@ static void chip_init() 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 --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c index 667b21482..ff07954d8 100644 --- a/drivers/scsi/advansys.c +++ b/drivers/scsi/advansys.c @@ -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 @@ typedef unsigned char uchar; #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 @@ typedef unsigned char uchar; #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 @@ AscMemWordCopyToLram(iop_base, s_addr, outbuf, words) #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 @@ AscMemWordCopyToLram(iop_base, s_addr, outbuf, words) #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 @@ AscMemWordCopyToLram(iop_base, s_addr, outbuf, words) #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 @@ typedef struct { 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 @@ typedef struct { 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 @@ typedef struct { 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 @@ typedef struct asc_req_sense { 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 @@ typedef struct asc_scsi_q { 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 @@ typedef struct asc_scsi_req_q { 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 @@ typedef struct asc_dvc_cfg { 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 @@ typedef struct asceep_config { #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 AscAckInterrupt(PortAddr); 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,8896 +2070,13784 @@ STATIC ulong AscGetMaxDmaCount(ushort); /* - * --- Driver Constants and Macros + * --- Adv Library Constants and Macros */ -#define ASC_NUM_BOARD_SUPPORTED 4 -#define ASC_NUM_BUS 4 +#define ADV_LIB_VERSION_MAJOR 3 +#define ADV_LIB_VERSION_MINOR 34 -/* Reference Scsi_Host hostdata */ -#define ASC_BOARDP(host) ((asc_board_t *) &((host)->hostdata)) +/* d_os_dep.h */ +#define ADV_OS_LINUX -/* asc_board_t flags */ -#define ASC_HOST_IN_RESET 0x01 -#define ASC_HOST_IN_ABORT 0x02 +/* + * 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 NO_ISA_DMA 0xff /* No ISA DMA Channel Used */ +/* + * 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) /* - * If the Linux kernel version supports throwing away 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. + * The I/O memory mapping function names changed in 2.1.X. */ -#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 */ -#define ASC_INITFUNC(func) func -#define ASC_INITDATA -#define ASC_INIT -#endif /* version >= v2.1.23 */ +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,0) +#define ioremap vremap +#define iounmap vfree +#endif /* version < v2.1.0 */ -#define ASC_INFO_SIZE 128 /* advansys_info() line size */ +/* + * 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 -/* /proc/scsi/advansys/[0...] related definitions */ -#define ASC_PRTBUF_SIZE 2048 -#define ASC_PRTLINE_SIZE 160 +/* + * Define Adv Library required per request scatter-gather element limit. + */ +#define ADV_MAX_SG_LIST 64 -#define ASC_PRT_NEXT() \ - if (cp) { \ - totlen += len; \ - leftlen -= len; \ - if (leftlen == 0) { \ - return totlen; \ - } \ - cp += len; \ - } +/* + * 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. + */ -#define ASC_MIN(a, b) (((a) < (b)) ? (a) : (b)) +/* 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) -/* Asc Library return codes */ -#define ASC_TRUE 1 -#define ASC_FALSE 0 -#define ASC_NOERROR 1 -#define ASC_BUSY 0 -#define ASC_ERROR (-1) +/* Total contiguous memory needed for SG blocks. */ +#define ADV_SG_TOTAL_MEM_SIZE \ + (sizeof(ADV_SG_BLOCK) * ADV_NUM_SG_BLOCK) -/* Scsi_Cmnd function return codes */ -#define STATUS_BYTE(byte) (byte) -#define MSG_BYTE(byte) ((byte) << 8) -#define HOST_BYTE(byte) ((byte) << 16) -#define DRIVER_BYTE(byte) ((byte) << 24) +#define ASC_PAGE_SIZE PAGE_SIZE /* - * The following definitions and macros are OS independent interfaces to - * the queue functions: - * REQ - SCSI request structure - * REQP - pointer to SCSI request structure - * REQPTID(reqp) - reqp's target id - * REQPNEXT(reqp) - reqp's next pointer - * REQPNEXTP(reqp) - pointer to reqp's next pointer - * REQPTIME(reqp) - reqp's time stamp value - * REQTIMESTAMP() - system time stamp value + * 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. */ -typedef Scsi_Cmnd REQ, *REQP; -#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 ADV_NUM_PAGE_CROSSING \ + ((ADV_SG_TOTAL_MEM_SIZE + (ASC_PAGE_SIZE - 1))/ASC_PAGE_SIZE) -#define REQTIMESTAT(function, ascq, reqp, tid) \ -{ \ - /* - * If the request time stamp is less than the system time stamp, then \ - * maybe the system time stamp wrapped. Set the request time to zero.\ - */ \ - if (REQPTIME(reqp) <= REQTIMESTAMP()) { \ - REQPTIME(reqp) = REQTIMESTAMP() - REQPTIME(reqp); \ - } else { \ - /* Indicate an error occurred with the assertion. */ \ - ASC_ASSERT(REQPTIME(reqp) <= REQTIMESTAMP()); \ - REQPTIME(reqp) = 0; \ - } \ - /* Handle first minimum time case without external initialization. */ \ - if (((ascq)->q_tot_cnt[tid] == 1) || \ - (REQPTIME(reqp) < (ascq)->q_min_tim[tid])) { \ - (ascq)->q_min_tim[tid] = REQPTIME(reqp); \ - ASC_DBG3(1, "%s: new q_min_tim[%d] %u\n", \ - (function), (tid), (ascq)->q_min_tim[tid]); \ - } \ - if (REQPTIME(reqp) > (ascq)->q_max_tim[tid]) { \ - (ascq)->q_max_tim[tid] = REQPTIME(reqp); \ - ASC_DBG3(1, "%s: new q_max_tim[%d] %u\n", \ - (function), tid, (ascq)->q_max_tim[tid]); \ - } \ - (ascq)->q_tot_tim[tid] += REQPTIME(reqp); \ - /* Reset the time stamp field. */ \ - REQPTIME(reqp) = 0; \ -} +/* + * Define Adv Library Assertion Macro. + */ -/* asc_enqueue() flags */ -#define ASC_FRONT 1 -#define ASC_BACK 2 +#define ADV_ASSERT(a) ASC_ASSERT(a) -/* asc_dequeue_list() argument */ -#define ASC_TID_ALL (-1) +/* a_condor.h */ +#define ADV_PCI_VENDOR_ID 0x10CD +#define ADV_PCI_DEVICE_ID_REV_A 0x2300 -/* Return non-zero, if the queue is empty. */ -#define ASC_QUEUE_EMPTY(ascq) ((ascq)->q_tidmask == 0) +#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) -/* PCI configuration declarations */ +#define ASC_EEP_DELAY_MS 100 -#define PCI_BASE_CLASS_PREDEFINED 0x00 -#define PCI_BASE_CLASS_MASS_STORAGE 0x01 -#define PCI_BASE_CLASS_NETWORK 0x02 -#define PCI_BASE_CLASS_DISPLAY 0x03 -#define PCI_BASE_CLASS_MULTIMEDIA 0x04 -#define PCI_BASE_CLASS_MEMORY_CONTROLLER 0x05 -#define PCI_BASE_CLASS_BRIDGE_DEVICE 0x06 +/* + * 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 */ -/* MASS STORAGE */ -#define PCI_SUB_CLASS_SCSI_CONTROLLER 0x00 -#define PCI_SUB_CLASS_IDE_CONTROLLER 0x01 -#define PCI_SUB_CLASS_FLOPPY_DISK_CONTROLLER 0x02 -#define PCI_SUB_CLASS_IPI_BUS_CONTROLLER 0x03 -#define PCI_SUB_CLASS_OTHER_MASS_CONTROLLER 0x80 +/* + * 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; -/* NETWORK CONTROLLER */ -#define PCI_SUB_CLASS_ETHERNET_CONTROLLER 0x00 -#define PCI_SUB_CLASS_TOKEN_RING_CONTROLLER 0x01 -#define PCI_SUB_CLASS_FDDI_CONTROLLER 0x02 -#define PCI_SUB_CLASS_OTHER_NETWORK_CONTROLLER 0x80 +/* + * 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 -/* DISPLAY CONTROLLER */ -#define PCI_SUB_CLASS_VGA_CONTROLLER 0x00 -#define PCI_SUB_CLASS_XGA_CONTROLLER 0x01 -#define PCI_SUB_CLASS_OTHER_DISPLAY_CONTROLLER 0x80 +/* + * ASC 3550 Internal Memory Size - 8KB + */ +#define ADV_CONDOR_MEMSIZE 0x2000 /* 8 KB Internal Memory */ -/* MULTIMEDIA CONTROLLER */ -#define PCI_SUB_CLASS_VIDEO_DEVICE 0x00 -#define PCI_SUB_CLASS_AUDIO_DEVICE 0x01 -#define PCI_SUB_CLASS_OTHER_MULTIMEDIA_DEVICE 0x80 +/* + * ASC 3550 I/O Length - 64 bytes + */ +#define ADV_CONDOR_IOLEN 0x40 /* I/O Port Range in bytes */ -/* MEMORY CONTROLLER */ -#define PCI_SUB_CLASS_RAM_CONTROLLER 0x00 -#define PCI_SUB_CLASS_FLASH_CONTROLLER 0x01 -#define PCI_SUB_CLASS_OTHER_MEMORY_CONTROLLER 0x80 +/* + * 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 -/* BRIDGE CONTROLLER */ -#define PCI_SUB_CLASS_HOST_BRIDGE_CONTROLLER 0x00 -#define PCI_SUB_CLASS_ISA_BRIDGE_CONTROLLER 0x01 -#define PCI_SUB_CLASS_EISA_BRIDGE_CONTROLLER 0x02 -#define PCI_SUB_CLASS_MC_BRIDGE_CONTROLLER 0x03 -#define PCI_SUB_CLASS_PCI_TO_PCI_BRIDGE_CONTROLLER 0x04 -#define PCI_SUB_CLASS_PCMCIA_BRIDGE_CONTROLLER 0x05 -#define PCI_SUB_CLASS_OTHER_BRIDGE_CONTROLLER 0x80 +/* + * 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 */ -#define PCI_MAX_SLOT 0x1F -#define PCI_MAX_BUS 0xFF -#define PCI_IOADDRESS_MASK 0xFFFE -#define ASC_PCI_VENDORID 0x10CD -#define ASC_PCI_DEVICE_ID_1100 0x1100 -#define ASC_PCI_DEVICE_ID_1200 0x1200 -#define ASC_PCI_DEVICE_ID_1300 0x1300 +/* + * 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) -/* PCI IO Port Addresses to generate special cycle */ +/* + * 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 */ -#define PCI_CONFIG_ADDRESS_MECH1 0x0CF8 -#define PCI_CONFIG_DATA_MECH1 0x0CFC +/* + * 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) */ -#define PCI_CONFIG_FORWARD_REGISTER 0x0CFA /* 0=type 0; 1=type 1; */ +/* + 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'. + */ -#define PCI_CONFIG_BUS_NUMBER_MASK 0x00FF0000 -#define PCI_CONFIG_DEVICE_FUNCTION_MASK 0x0000FF00 -#define PCI_CONFIG_REGISTER_NUMBER_MASK 0x000000F8 +/* + * 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 */ -#define PCI_DEVICE_FOUND 0x0000 -#define PCI_DEVICE_NOT_FOUND 0xffff +/* + * 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 */ -#define SUBCLASS_OFFSET 0x0A -#define CLASSCODE_OFFSET 0x0B -#define VENDORID_OFFSET 0x00 -#define DEVICEID_OFFSET 0x02 +/* + * 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) -#ifndef ADVANSYS_STATS -#define ASC_STATS(shp, counter) -#define ASC_STATS_ADD(shp, counter, count) -#else /* ADVANSYS_STATS */ -#define ASC_STATS(shp, counter) \ - (ASC_BOARDP(shp)->asc_stats.counter++) -#define ASC_STATS_ADD(shp, counter, count) \ - (ASC_BOARDP(shp)->asc_stats.counter += (count)) -#endif /* ADVANSYS_STATS */ +/* + * 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 ASC_CEILING(val, unit) (((val) + ((unit) - 1))/(unit)) +#define ADV_MAX_TID 15 /* max. target identifier */ +#define ADV_MAX_LUN 7 /* max. logical unit number */ -/* If the result wraps when calculating tenths, return 0. */ -#define ASC_TENTHS(num, den) \ - (((10 * ((num)/(den))) > (((num) * 10)/(den))) ? \ - 0 : ((((num) * 10)/(den)) - (10 * ((num)/(den))))) /* - * Display a message to the console. + * AscInitGetConfig() and AscInitAsc1000Driver() Definitions + * + * Error code values are set in ASC_DVC_VAR 'err_code'. */ -#define ASC_PRINT(s) \ - { \ - printk("advansys: "); \ - printk(s); \ - } +#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 */ -#define ASC_PRINT1(s, a1) \ - { \ - printk("advansys: "); \ - printk((s), (a1)); \ - } +/* + * 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. */ -#define ASC_PRINT2(s, a1, a2) \ - { \ - printk("advansys: "); \ - printk((s), (a1), (a2)); \ - } +/* + * 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 -#define ASC_PRINT3(s, a1, a2, a3) \ - { \ - printk("advansys: "); \ - printk((s), (a1), (a2), (a3)); \ - } +/* + * 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 */ -#define ASC_PRINT4(s, a1, a2, a3, a4) \ - { \ - printk("advansys: "); \ - printk((s), (a1), (a2), (a3), (a4)); \ - } +/* + * 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. + */ -#ifndef ADVANSYS_DEBUG +#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 -#define ASC_DBG(lvl, s) -#define ASC_DBG1(lvl, s, a1) -#define ASC_DBG2(lvl, s, a1, a2) -#define ASC_DBG3(lvl, s, a1, a2, a3) -#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_HEX(lvl, name, start, length) -#define ASC_DBG_PRT_CDB(lvl, cdb, len) -#define ASC_DBG_PRT_SENSE(lvl, sense, len) -#define ASC_DBG_PRT_INQUIRY(lvl, inq, len) +/* 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. */ -#else /* ADVANSYS_DEBUG */ /* - * Debugging Message Levels: - * 0: Errors Only - * 1: High-Level Tracing - * 2-N: Verbose Tracing + * 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 */ -#define ASC_DBG(lvl, s) \ - { \ - if (asc_dbglvl >= (lvl)) { \ - printk(s); \ - } \ - } - -#define ASC_DBG1(lvl, s, a1) \ - { \ - if (asc_dbglvl >= (lvl)) { \ - printk((s), (a1)); \ - } \ - } - -#define ASC_DBG2(lvl, s, a1, a2) \ - { \ - if (asc_dbglvl >= (lvl)) { \ - printk((s), (a1), (a2)); \ - } \ - } +/* + * 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; -#define ASC_DBG3(lvl, s, a1, a2, a3) \ - { \ - if (asc_dbglvl >= (lvl)) { \ - printk((s), (a1), (a2), (a3)); \ - } \ - } +/* + * 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; -#define ASC_DBG4(lvl, s, a1, a2, a3, a4) \ - { \ - if (asc_dbglvl >= (lvl)) { \ - printk((s), (a1), (a2), (a3), (a4)); \ - } \ - } +/* + * 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 */ -#define ASC_DBG_PRT_SCSI_HOST(lvl, s) \ - { \ - if (asc_dbglvl >= (lvl)) { \ - asc_prt_scsi_host(s); \ - } \ - } +/* + * 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 -#define ASC_DBG_PRT_SCSI_CMND(lvl, s) \ - { \ - if (asc_dbglvl >= (lvl)) { \ - asc_prt_scsi_cmnd(s); \ - } \ - } +/* + * AdvSendIdleCmd() flag definitions. + */ +#define ADV_NOWAIT 0x01 -#define ASC_DBG_PRT_SCSI_Q(lvl, scsiqp) \ - { \ - if (asc_dbglvl >= (lvl)) { \ - asc_prt_scsi_q(scsiqp); \ - } \ - } +/* + * Wait loop time out values. + */ +#define SCSI_WAIT_10_SEC 10 /* 10 seconds */ +#define SCSI_MS_PER_SEC 1000 /* milliseconds per second */ -#define ASC_DBG_PRT_QDONE_INFO(lvl, qdone) \ - { \ - if (asc_dbglvl >= (lvl)) { \ - asc_prt_qdone_info(qdone); \ - } \ - } +/* + * 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); -#define ASC_DBG_PRT_HEX(lvl, name, start, length) \ - { \ - if (asc_dbglvl >= (lvl)) { \ - asc_prt_hex((name), (start), (length)); \ - } \ - } +/* + * 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 *); -#define ASC_DBG_PRT_CDB(lvl, cdb, len) \ - ASC_DBG_PRT_HEX((lvl), "CDB", (uchar *) (cdb), (len)); +/* + * 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 *); -#define ASC_DBG_PRT_SENSE(lvl, sense, len) \ - ASC_DBG_PRT_HEX((lvl), "SENSE", (uchar *) (sense), (len)); +/* + * PCI Bus Definitions + */ +#define AscPCICmdRegBits_BusMastering 0x0007 +#define AscPCICmdRegBits_ParErrRespCtrl 0x0040 -#define ASC_DBG_PRT_INQUIRY(lvl, inq, len) \ - ASC_DBG_PRT_HEX((lvl), "INQUIRY", (uchar *) (inq), (len)); -#endif /* ADVANSYS_DEBUG */ +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0) -#ifndef ADVANSYS_ASSERT -#define ASC_ASSERT(a) -#else /* ADVANSYS_ASSERT */ +/* 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 ASC_ASSERT(a) \ - { \ - if (!(a)) { \ - printk("ASC_ASSERT() Failure: file %s, line %d\n", \ - __FILE__, __LINE__); \ - } \ - } +/* + * 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) -#endif /* ADVANSYS_ASSERT */ +/* + * 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) /* - * --- Driver Structures + * 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) -#ifdef ADVANSYS_STATS +/* + * SCSI Wide Type definition. + */ +#define ADV_SCSI_BIT_ID_TYPE ushort -/* Per board statistics structure */ -struct asc_stats { - /* Driver Entrypoint Statistics */ - ulong command; /* # calls to advansys_command() */ - ulong queuecommand; /* # calls to advansys_queuecommand() */ - 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. */ - /* Data Transfer Statistics */ - ulong cont_cnt; /* # non-scatter-gather I/O requests received */ - ulong cont_xfer; /* # contiguous transfer 512-bytes */ - ulong sg_cnt; /* # scatter-gather I/O requests received */ - ulong sg_elem; /* # scatter-gather elements */ - ulong sg_xfer; /* # scatter-gather transfer 512-bytes */ -}; -#endif /* ADVANSYS_STATS */ +/* + * AdvInitScsiTarget() 'cntl_flag' options. + */ +#define ADV_SCAN_LUN 0x01 +#define ADV_CAPINFO_NOLUN 0x02 /* - * Request queuing structure + * Convert target id to target id bit mask. */ -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 */ -#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 */ -#endif /* ADVANSYS_STATS */ -} asc_queue_t; +#define ADV_TID_TO_TIDMASK(tid) (0x01 << ((tid) & ADV_MAX_TID)) /* - * Structure allocated for each board. - * - * This structure is allocated by scsi_register() at the end - * of the 'Scsi_Host' structure starting at the 'hostdata' - * field. It is guaranteed to be allocated from DMA-able memory. + * ASC_SCSI_REQ_Q 'done_status' and 'host_status' return values. */ -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 */ -#if ASC_QUEUE_FLOW_CONTROL - ushort nerrcnt[ASC_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 */ -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) - /* /proc/scsi/advansys/[0...] */ - char *prtbuf; /* Statistics Print Buffer */ -#endif /* version >= v1.3.0 */ -#ifdef ADVANSYS_STATS - struct asc_stats asc_stats; /* Board statistics */ -#endif /* ADVANSYS_STATS */ -} asc_board_t; -/* - * PCI configuration structures - */ -typedef struct _PCI_DATA_ -{ - uchar type; - uchar bus; - uchar slot; - uchar func; - uchar offset; -} PCI_DATA; +#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 -typedef struct _PCI_DEVICE_ -{ - ushort vendorID; - ushort deviceID; - ushort slotNumber; - ushort slotFound; - uchar busNumber; - uchar maxBusNumber; - uchar devFunc; - ushort startSlot; - ushort endSlot; - uchar bridge; - uchar type; -} PCI_DEVICE; +#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 struct _PCI_CONFIG_SPACE_ -{ - ushort vendorID; - ushort deviceID; - ushort command; - ushort status; - uchar revision; - uchar classCode[3]; - uchar cacheSize; - uchar latencyTimer; - uchar headerType; - uchar bist; - ulong baseAddress[6]; - ushort reserved[4]; - ulong optionRomAddr; - ushort reserved2[4]; - uchar irqLine; - uchar irqPin; - uchar minGnt; - uchar maxLatency; -} PCI_CONFIG_SPACE; +typedef int (* ADV_ISR_CALLBACK) + (ADV_DVC_VAR *, ADV_SCSI_REQ_Q *); +typedef int (* ADV_SBRESET_CALLBACK) + (ADV_DVC_VAR *); /* - * --- Driver Data + * Default EEPROM Configuration structure defined in a_init.c. */ +extern ADVEEP_CONFIG Default_EEPROM_Config; -/* Note: All driver global data should be initialized. */ +/* + * 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 */ -#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 */ - 2 /* nlink_t nlink */ -}; -#endif /* version >= v1.3.0 */ +/* 'IS_SCSIQ_FLAG is now obsolete; Instead use ADV_IS_SCSIQ_FLAG. */ +#define IS_SCSIQ_FLAG ADV_IS_SCSIQ_FLAQ -/* Number of boards detected in system. */ -STATIC int asc_board_count = 0; -STATIC struct Scsi_Host *asc_host[ASC_NUM_BOARD_SUPPORTED] = { 0 }; -/* Overrun buffer shared between all boards. */ -STATIC uchar overrun_buf[ASC_OVERRUN_BSIZE] = { 0 }; +/* Return the address that is aligned at the next doubleword >= to 'addr'. */ +#define ADV_DWALIGN(addr) (((ulong) (addr) + 0x3) & ~0x3) /* - * Global structures required to issue a command. + * 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. */ -STATIC ASC_SCSI_Q asc_scsi_q = { { 0 } }; -STATIC ASC_SG_HEAD asc_sg_head = { 0 }; -/* List of supported bus types. */ -STATIC ushort asc_bus[ASC_NUM_BUS] ASC_INITDATA = { - ASC_IS_ISA, - ASC_IS_VL, - ASC_IS_EISA, - ASC_IS_PCI, -}; +#ifndef ADV_MAX_SG_LIST +Forced Error: Driver must define ADV_MAX_SG_LIST. +#endif /* ADV_MAX_SG_LIST */ -STATIC int pci_scan_method ASC_INITDATA = -1; +#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)) /* - * Used with the LILO 'advansys' option to eliminate or - * limit I/O port probing at boot time, cf. advansys_setup(). + * 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. */ -STATIC int asc_iopflag = ASC_FALSE; -STATIC int asc_ioport[ASC_NUM_BOARD_SUPPORTED] = { 0, 0, 0, 0 }; - -#ifdef ADVANSYS_DEBUG -STATIC char * -asc_bus_name[ASC_NUM_BUS] = { - "ASC_IS_ISA", - "ASC_IS_VL", - "ASC_IS_EISA", - "ASC_IS_PCI", -}; - -STATIC int asc_dbglvl = 0; -#endif /* ADVANSYS_DEBUG */ - -/* Declaration for Asc Library internal data referenced by driver. */ -STATIC PortAddr _asc_def_iop_base[]; +#ifndef ADV_ASSERT +#define ADV_ASSERT(a) +#endif /* ADV_ASSERT */ /* - * --- Driver Function Prototypes - * - * advansys.h contains function prototypes for functions global to Linux. + * --- Driver Constants and Macros */ -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) -STATIC int asc_proc_copy(off_t, off_t, char *, int , char *, int); -#endif /* version >= v1.3.0 */ -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,70) -STATIC void advansys_interrupt(int, struct pt_regs *); -#else /* version >= v1.3.70 */ -STATIC void advansys_interrupt(int, void *, struct pt_regs *); -#endif /* version >= v1.3.70 */ -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) -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 *); -#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, ...); -#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); +#define ASC_NUM_BOARD_SUPPORTED 16 +#define ASC_NUM_IOPORT_PROBE 4 +#define ASC_NUM_BUS 4 -#ifdef ADVANSYS_STATS -STATIC int asc_prt_board_stats(struct Scsi_Host *, char *, int); -#endif /* ADVANSYS_STATS */ +/* Reference Scsi_Host hostdata */ +#define ASC_BOARDP(host) ((asc_board_t *) &((host)->hostdata)) -#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_hex(char *f, uchar *, int); -#endif /* ADVANSYS_DEBUG */ +/* 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 -#ifdef ADVANSYS_ASSERT -STATIC int interrupts_enabled(void); -#endif /* ADVANSYS_ASSERT */ +#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 */ /* - * --- Linux 'Scsi_Host_Template' and advansys_setup() Functions + * 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) 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 */ -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) -/* - * advansys_proc_info() - /proc/scsi/advansys/[0-(ASC_NUM_BOARD_SUPPORTED-1)] - * - * *buffer: I/O buffer - * **start: if inout == FALSE pointer into buffer where user read should start - * offset: current offset into a /proc/scsi/advansys/[0...] file - * length: length of buffer - * hostno: Scsi_Host host_no - * inout: TRUE - user is writing; FALSE - user is reading - * - * Return the number of bytes read from or written to a - * /proc/scsi/advansys/[0...] file. - * - * Note: This function uses the per board buffer 'prtbuf' which is - * allocated when the board is initialized in advansys_detect(). The - * buffer is ASC_PRTBUF_SIZE bytes. The function asc_proc_copy() is - * used to write to the buffer. The way asc_proc_copy() is written - * if 'prtbuf' is too small it will not be overwritten. Instead the - * user just won't get all the available statistics. - */ -int -advansys_proc_info(char *buffer, char **start, off_t offset, int length, - int hostno, int inout) -{ - struct Scsi_Host *shp; - asc_board_t *boardp; - int i; - char *cp; - int cplen; - int cnt; - int totcnt; - int leftlen; - char *curbuf; - off_t advoffset; - Scsi_Device *scd = NULL; +#define ASC_INFO_SIZE 128 /* advansys_info() line size */ - ASC_DBG(1, "advansys_proc_info: begin\n"); +/* /proc/scsi/advansys/[0...] related definitions */ +#define ASC_PRTBUF_SIZE 2048 +#define ASC_PRTLINE_SIZE 160 - /* - * User write not supported. - */ - if (inout == TRUE) { - return(-ENOSYS); +#define ASC_PRT_NEXT() \ + if (cp) { \ + totlen += len; \ + leftlen -= len; \ + if (leftlen == 0) { \ + return totlen; \ + } \ + cp += len; \ } - /* - * User read of /proc/scsi/advansys/[0...] file. - */ - - /* Find the specified board. */ - for (i = 0; i < asc_board_count; i++) { - if (asc_host[i]->host_no == hostno) { - break; - } - } - if (i == asc_board_count) { - return(-ENOENT); - } +#define ASC_MIN(a, b) (((a) < (b)) ? (a) : (b)) - shp = asc_host[i]; - boardp = ASC_BOARDP(shp); +/* Asc Library return codes */ +#define ASC_TRUE 1 +#define ASC_FALSE 0 +#define ASC_NOERROR 1 +#define ASC_BUSY 0 +#define ASC_ERROR (-1) - /* Copy read data starting at the beginning of the buffer. */ - *start = buffer; - curbuf = buffer; - advoffset = 0; - totcnt = 0; - leftlen = length; +/* Scsi_Cmnd function return codes */ +#define STATUS_BYTE(byte) (byte) +#define MSG_BYTE(byte) ((byte) << 8) +#define HOST_BYTE(byte) ((byte) << 16) +#define DRIVER_BYTE(byte) ((byte) << 24) - /* - * Get board configuration information. - * - * advansys_info() returns the board string from its own static buffer. - */ - cp = (char *) advansys_info(shp); - strcat(cp, "\n"); - cplen = strlen(cp); - /* Copy board information. */ - 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; +/* + * The following definitions and macros are OS independent interfaces to + * the queue functions: + * REQ - SCSI request structure + * REQP - pointer to SCSI request structure + * REQPTID(reqp) - reqp's target id + * REQPNEXT(reqp) - reqp's next pointer + * REQPNEXTP(reqp) - pointer to reqp's next pointer + * REQPTIME(reqp) - reqp's time stamp value + * 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 REQPTID(reqp) ((reqp)->target) +#define REQPTIME(reqp) ((reqp)->SCp.this_residual) +#define REQTIMESTAMP() (jiffies) +#define REQTIMESTAT(function, ascq, reqp, tid) \ +{ \ /* - * Display driver information for each device attached to the board. - */ - cp = boardp->prtbuf; - cplen = asc_prt_board_devices(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; + * If the request time stamp is less than the system time stamp, then \ + * maybe the system time stamp wrapped. Set the request time to zero.\ + */ \ + if (REQPTIME(reqp) <= REQTIMESTAMP()) { \ + REQPTIME(reqp) = REQTIMESTAMP() - REQPTIME(reqp); \ + } else { \ + /* Indicate an error occurred with the assertion. */ \ + ASC_ASSERT(REQPTIME(reqp) <= REQTIMESTAMP()); \ + REQPTIME(reqp) = 0; \ + } \ + /* Handle first minimum time case without external initialization. */ \ + if (((ascq)->q_tot_cnt[tid] == 1) || \ + (REQPTIME(reqp) < (ascq)->q_min_tim[tid])) { \ + (ascq)->q_min_tim[tid] = REQPTIME(reqp); \ + ASC_DBG3(1, "%s: new q_min_tim[%d] %u\n", \ + (function), (tid), (ascq)->q_min_tim[tid]); \ + } \ + if (REQPTIME(reqp) > (ascq)->q_max_tim[tid]) { \ + (ascq)->q_max_tim[tid] = REQPTIME(reqp); \ + ASC_DBG3(1, "%s: new q_max_tim[%d] %u\n", \ + (function), tid, (ascq)->q_max_tim[tid]); \ + } \ + (ascq)->q_tot_tim[tid] += REQPTIME(reqp); \ + /* Reset the time stamp field. */ \ + REQPTIME(reqp) = 0; \ +} - /* - * Display target driver information for each device attached - * to the board. - */ - for (scd = scd->host->host_queue; scd; scd = scd->next) { - cp = boardp->prtbuf; - /* - * Note: If proc_print_scsidevice() writes more than - * ASC_PRTBUF_SIZE bytes, it will overrun 'prtbuf'. - */ - proc_print_scsidevice(scd, cp, &cplen, 0); - 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 EEPROM configuration for the board. - */ - cp = boardp->prtbuf; - cplen = asc_prt_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; - leftlen -= cnt; - if (leftlen == 0) { - ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt); - return totcnt; - } - advoffset += cplen; - curbuf += cnt; +/* asc_enqueue() flags */ +#define ASC_FRONT 1 +#define ASC_BACK 2 - /* - * Display driver configuration and information for the board. - */ - cp = boardp->prtbuf; - cplen = asc_prt_driver_conf(shp, cp, ASC_PRTBUF_SIZE); - ASC_ASSERT(cplen < ASC_PRTBUF_SIZE); - cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen); - totcnt += cnt; - leftlen -= cnt; - if (leftlen == 0) { - ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt); - return totcnt; - } - advoffset += cplen; - curbuf += cnt; +/* asc_dequeue_list() argument */ +#define ASC_TID_ALL (-1) -#ifdef ADVANSYS_STATS - /* - * Display driver statistics for the board. - */ - cp = boardp->prtbuf; - cplen = asc_prt_board_stats(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; -#endif /* ADVANSYS_STATS */ +/* Return non-zero, if the queue is empty. */ +#define ASC_QUEUE_EMPTY(ascq) ((ascq)->q_tidmask == 0) - /* - * Display Asc Library dynamic configuration information - * for the board. - */ - cp = boardp->prtbuf; - cplen = asc_prt_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; - leftlen -= cnt; - if (leftlen == 0) { - ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt); - return totcnt; - } - advoffset += cplen; - curbuf += cnt; +/* PCI configuration declarations */ - ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt); +#define PCI_BASE_CLASS_PREDEFINED 0x00 +#define PCI_BASE_CLASS_MASS_STORAGE 0x01 +#define PCI_BASE_CLASS_NETWORK 0x02 +#define PCI_BASE_CLASS_DISPLAY 0x03 +#define PCI_BASE_CLASS_MULTIMEDIA 0x04 +#define PCI_BASE_CLASS_MEMORY_CONTROLLER 0x05 +#define PCI_BASE_CLASS_BRIDGE_DEVICE 0x06 - return totcnt; -} -#endif /* version >= v1.3.0 */ +/* MASS STORAGE */ +#define PCI_SUB_CLASS_SCSI_CONTROLLER 0x00 +#define PCI_SUB_CLASS_IDE_CONTROLLER 0x01 +#define PCI_SUB_CLASS_FLOPPY_DISK_CONTROLLER 0x02 +#define PCI_SUB_CLASS_IPI_BUS_CONTROLLER 0x03 +#define PCI_SUB_CLASS_OTHER_MASS_CONTROLLER 0x80 +/* NETWORK CONTROLLER */ +#define PCI_SUB_CLASS_ETHERNET_CONTROLLER 0x00 +#define PCI_SUB_CLASS_TOKEN_RING_CONTROLLER 0x01 +#define PCI_SUB_CLASS_FDDI_CONTROLLER 0x02 +#define PCI_SUB_CLASS_OTHER_NETWORK_CONTROLLER 0x80 -/* - * advansys_detect() - * - * Detect function for AdvanSys adapters. - * - * Argument is a pointer to the host driver's scsi_hosts entry. - * - * Return number of adapters found. - * - * Note: Because this function is called during system initialization - * it must not call SCSI mid-level functions including scsi_malloc() - * and scsi_free(). - */ -ASC_INITFUNC( -int -advansys_detect(Scsi_Host_Template *tpnt) -) -{ - static int detect_called = ASC_FALSE; - int iop; - int bus; - struct Scsi_Host *shp; - asc_board_t *boardp; - ASC_DVC_VAR *asc_dvc_varp; - int ioport = 0; - int share_irq = FALSE; - PCI_DEVICE pciDevice; - PCI_CONFIG_SPACE pciConfig; - int ret; +/* DISPLAY CONTROLLER */ +#define PCI_SUB_CLASS_VGA_CONTROLLER 0x00 +#define PCI_SUB_CLASS_XGA_CONTROLLER 0x01 +#define PCI_SUB_CLASS_OTHER_DISPLAY_CONTROLLER 0x80 - if (detect_called == ASC_FALSE) { - detect_called = ASC_TRUE; - } else { - printk("AdvanSys SCSI: advansys_detect() mulitple calls ignored\n"); - return 0; - } +/* MULTIMEDIA CONTROLLER */ +#define PCI_SUB_CLASS_VIDEO_DEVICE 0x00 +#define PCI_SUB_CLASS_AUDIO_DEVICE 0x01 +#define PCI_SUB_CLASS_OTHER_MULTIMEDIA_DEVICE 0x80 - ASC_DBG(1, "advansys_detect: begin\n"); +/* MEMORY CONTROLLER */ +#define PCI_SUB_CLASS_RAM_CONTROLLER 0x00 +#define PCI_SUB_CLASS_FLASH_CONTROLLER 0x01 +#define PCI_SUB_CLASS_OTHER_MEMORY_CONTROLLER 0x80 -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) - tpnt->proc_dir = &proc_scsi_advansys; -#endif /* version >= v1.3.0 */ +/* BRIDGE CONTROLLER */ +#define PCI_SUB_CLASS_HOST_BRIDGE_CONTROLLER 0x00 +#define PCI_SUB_CLASS_ISA_BRIDGE_CONTROLLER 0x01 +#define PCI_SUB_CLASS_EISA_BRIDGE_CONTROLLER 0x02 +#define PCI_SUB_CLASS_MC_BRIDGE_CONTROLLER 0x03 +#define PCI_SUB_CLASS_PCI_TO_PCI_BRIDGE_CONTROLLER 0x04 +#define PCI_SUB_CLASS_PCMCIA_BRIDGE_CONTROLLER 0x05 +#define PCI_SUB_CLASS_OTHER_BRIDGE_CONTROLLER 0x80 - asc_board_count = 0; +#define PCI_MAX_SLOT 0x1F +#define PCI_MAX_BUS 0xFF +#define PCI_IOADDRESS_MASK 0xFFFE +#define ASC_PCI_VENDORID 0x10CD +#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 - /* - * If I/O port probing has been modified, then verify and - * clean-up the 'asc_ioport' list. - */ - if (asc_iopflag == ASC_TRUE) { - for (ioport = 0; ioport < ASC_NUM_BOARD_SUPPORTED; ioport++) { - ASC_DBG2(1, "advansys_detect: asc_ioport[%d] %x\n", - ioport, asc_ioport[ioport]); - if (asc_ioport[ioport] != 0) { - for (iop = 0; iop < ASC_IOADR_TABLE_MAX_IX; iop++) { - if (_asc_def_iop_base[iop] == asc_ioport[ioport]) { - break; - } - } - if (iop == ASC_IOADR_TABLE_MAX_IX) { - printk("AdvanSys SCSI: specified I/O Port 0x%X is invalid\n", - asc_ioport[ioport]); - asc_ioport[ioport] = 0; - } - } - } - ioport = 0; - } +/* PCI IO Port Addresses to generate special cycle */ - memset(&pciDevice, 0, sizeof(PCI_DEVICE)); - memset(&pciConfig, 0, sizeof(PCI_CONFIG_SPACE)); - pciDevice.maxBusNumber = PCI_MAX_BUS; - pciDevice.endSlot = PCI_MAX_SLOT; +#define PCI_CONFIG_ADDRESS_MECH1 0x0CF8 +#define PCI_CONFIG_DATA_MECH1 0x0CFC - for (bus = 0; bus < ASC_NUM_BUS; bus++) { +#define PCI_CONFIG_FORWARD_REGISTER 0x0CFA /* 0=type 0; 1=type 1; */ - ASC_DBG2(1, "advansys_detect: bus search type %d (%s)\n", - bus, asc_bus_name[bus]); - iop = 0; +#define PCI_CONFIG_BUS_NUMBER_MASK 0x00FF0000 +#define PCI_CONFIG_DEVICE_FUNCTION_MASK 0x0000FF00 +#define PCI_CONFIG_REGISTER_NUMBER_MASK 0x000000F8 - while (asc_board_count < ASC_NUM_BOARD_SUPPORTED) { +#define PCI_DEVICE_FOUND 0x0000 +#define PCI_DEVICE_NOT_FOUND 0xffff - ASC_DBG1(2, "advansys_detect: asc_board_count %d\n", - asc_board_count); +#define SUBCLASS_OFFSET 0x0A +#define CLASSCODE_OFFSET 0x0B +#define VENDORID_OFFSET 0x00 +#define DEVICEID_OFFSET 0x02 - switch (asc_bus[bus]) { - case ASC_IS_ISA: - case ASC_IS_VL: - if (asc_iopflag == ASC_FALSE) { - iop = AscSearchIOPortAddr(iop, asc_bus[bus]); - } else { - /* - * ISA and VL I/O port scanning has either been - * eliminated or limited to selected ports on - * the LILO command line, /etc/lilo.conf, or - * by setting variables when the module was loaded. - */ - ASC_DBG(1, "advansys_detect: I/O port scanning modified\n"); - ioport_try_again: - iop = 0; - for (; ioport < ASC_NUM_BOARD_SUPPORTED; ioport++) { - if ((iop = asc_ioport[ioport]) != 0) { - break; - } - } - if (iop) { - 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); - /* 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); - /* Don't try this I/O port twice. */ - asc_ioport[ioport] = 0; - goto ioport_try_again; - } else { - /* - * If this isn't an ISA board, then it must be - * a VL board. If currently looking an ISA - * board is being looked for then try for - * another ISA board in 'asc_ioport'. - */ - if (asc_bus[bus] == ASC_IS_ISA && - (AscGetChipVersion(iop, ASC_IS_ISA) & - ASC_CHIP_VER_ISA_BIT) == 0) { - /* - * Don't clear 'asc_ioport[ioport]'. Try - * this board again for VL. Increment - * 'ioport' past this board. - */ - ioport++; - goto ioport_try_again; - } - } - /* - * This board appears good, don't try the I/O port - * again by clearing its value. Increment 'ioport' - * for the next iteration. - */ - asc_ioport[ioport++] = 0; - } - } - break; +#ifndef ADVANSYS_STATS +#define ASC_STATS(shp, counter) +#define ASC_STATS_ADD(shp, counter, count) +#else /* ADVANSYS_STATS */ +#define ASC_STATS(shp, counter) \ + (ASC_BOARDP(shp)->asc_stats.counter++) - case ASC_IS_EISA: - iop = AscSearchIOPortAddr(iop, asc_bus[bus]); - break; +#define ASC_STATS_ADD(shp, counter, count) \ + (ASC_BOARDP(shp)->asc_stats.counter += (count)) +#endif /* ADVANSYS_STATS */ - case ASC_IS_PCI: - if (asc_srch_pci_dev(&pciDevice) != PCI_DEVICE_FOUND) { - iop = 0; - } else { - ASC_DBG2(2, - "advansys_detect: slotFound %d, busNumber %d\n", - 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", - iop, pciConfig.irqLine); - } - break; +#define ASC_CEILING(val, unit) (((val) + ((unit) - 1))/(unit)) - default: - ASC_PRINT1("advansys_detect: unknown bus type: %d\n", - asc_bus[bus]); - break; - } - ASC_DBG1(1, "advansys_detect: iop %x\n", iop); +/* If the result wraps when calculating tenths, return 0. */ +#define ASC_TENTHS(num, den) \ + (((10 * ((num)/(den))) > (((num) * 10)/(den))) ? \ + 0 : ((((num) * 10)/(den)) - (10 * ((num)/(den))))) - /* - * Adapter not found, try next bus type. - */ - if (iop == 0) { - break; - } +/* + * Display a message to the console. + */ +#define ASC_PRINT(s) \ + { \ + printk("advansys: "); \ + printk(s); \ + } - /* - * Adapter found. - * - * Register the adapter, get its configuration, and - * initialize it. - */ - ASC_DBG(2, "advansys_detect: scsi_register()\n"); - shp = scsi_register(tpnt, sizeof(asc_board_t)); +#define ASC_PRINT1(s, a1) \ + { \ + printk("advansys: "); \ + printk((s), (a1)); \ + } - /* Save a pointer to the Scsi_host of each board found. */ - asc_host[asc_board_count++] = shp; +#define ASC_PRINT2(s, a1, a2) \ + { \ + printk("advansys: "); \ + printk((s), (a1), (a2)); \ + } - /* Initialize private per board data */ - 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; +#define ASC_PRINT3(s, a1, a2, a3) \ + { \ + printk("advansys: "); \ + printk((s), (a1), (a2), (a3)); \ + } -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) - if ((boardp->prtbuf = - kmalloc(ASC_PRTBUF_SIZE, GFP_ATOMIC)) == NULL) { - ASC_PRINT3( -"advansys_detect: board %d: kmalloc(%d, %d) returned NULL\n", - boardp->id, ASC_PRTBUF_SIZE, GFP_ATOMIC); - scsi_unregister(shp); - asc_board_count--; - continue; - } -#endif /* version >= v1.3.0 */ +#define ASC_PRINT4(s, a1, a2, a3, a4) \ + { \ + printk("advansys: "); \ + printk((s), (a1), (a2), (a3), (a4)); \ + } - /* - * 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 = - ASC_PCI_MKID(pciDevice.busNumber, - pciDevice.slotFound, - pciDevice.devFunc); - 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; - } - /* - * 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 "&". - */ - 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( -"AscInitGetConfig: board %d: I/O port increment switch enabled\n", - boardp->id); - break; - case ASC_WARN_EEPROM_CHKSUM: - ASC_PRINT1( -"AscInitGetConfig: board %d: EEPROM checksum error\n", - 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( -"AscInitGetConfig: board %d: tag queuing enabled w/o disconnects\n", - 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( -"AscInitGetConfig: board %d error: init_state %x, err_code %x\n", - boardp->id, asc_dvc_varp->init_state, - asc_dvc_varp->err_code); -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) - kfree(boardp->prtbuf); -#endif /* version >= v1.3.0 */ - scsi_unregister(shp); - asc_board_count--; - continue; - } +#ifndef ADVANSYS_DEBUG - /* - * Set the adapter's target id bit in the init_tidmask field. - */ - boardp->init_tidmask |= - ASC_TIX_TO_TARGET_ID(asc_dvc_varp->cfg->chip_scsi_id); +#define ASC_DBG(lvl, s) +#define ASC_DBG1(lvl, s, a1) +#define ASC_DBG2(lvl, s, a1, a2) +#define ASC_DBG3(lvl, s, a1, a2, a3) +#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_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) +#define ASC_DBG_PRT_INQUIRY(lvl, inq, len) - /* - * 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]; +#else /* ADVANSYS_DEBUG */ - /* - * Modify board configuration. - */ - asc_dvc_varp->isr_callback = (Ptr2Func) asc_isr_callback; - asc_dvc_varp->exe_callback = (Ptr2Func) NULL; +/* + * Debugging Message Levels: + * 0: Errors Only + * 1: High-Level Tracing + * 2-N: Verbose Tracing + */ - 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( -"AscInitSetConfig: board %d: I/O port increment switch enabled\n", - boardp->id); - break; - case ASC_WARN_EEPROM_CHKSUM: - ASC_PRINT1( -"AscInitSetConfig: board %d: EEPROM checksum error\n", - 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( -"AscInitSetConfig: board %d: tag queuing w/o disconnects\n", - 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( -"AscInitSetConfig: board %d error: init_state %x, err_code %x\n", - boardp->id, asc_dvc_varp->init_state, - asc_dvc_varp->err_code); -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) - kfree(boardp->prtbuf); -#endif /* version >= v1.3.0 */ - scsi_unregister(shp); - asc_board_count--; - continue; - } +#define ASC_DBG(lvl, s) \ + { \ + if (asc_dbglvl >= (lvl)) { \ + printk(s); \ + } \ + } - /* - * Finish initializing the 'Scsi_Host' structure. - */ +#define ASC_DBG1(lvl, s, a1) \ + { \ + if (asc_dbglvl >= (lvl)) { \ + printk((s), (a1)); \ + } \ + } - /* 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; - } +#define ASC_DBG2(lvl, s, a1, a2) \ + { \ + if (asc_dbglvl >= (lvl)) { \ + printk((s), (a1), (a2)); \ + } \ + } - /* - * One host supports one channel. There are two different - * hosts for each channel of a dual channel board. - */ -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) - shp->max_channel = 0; -#endif /* version >= v1.3.89 */ - shp->max_id = ASC_MAX_TID + 1; - shp->max_lun = ASC_MAX_LUN + 1; +#define ASC_DBG3(lvl, s, a1, a2, a3) \ + { \ + if (asc_dbglvl >= (lvl)) { \ + printk((s), (a1), (a2), (a3)); \ + } \ + } - 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; +#define ASC_DBG4(lvl, s, a1, a2, a3, a4) \ + { \ + if (asc_dbglvl >= (lvl)) { \ + printk((s), (a1), (a2), (a3), (a4)); \ + } \ + } - /* Maximum number of queues this adapter can handle. */ - shp->can_queue = asc_dvc_varp->max_total_qng; +#define ASC_DBG_PRT_SCSI_HOST(lvl, s) \ + { \ + if (asc_dbglvl >= (lvl)) { \ + asc_prt_scsi_host(s); \ + } \ + } -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,89) - /* - * Set a conservative 'cmd_per_lun' value to prevent memory - * allocation failures. - */ -#ifdef MODULE - shp->cmd_per_lun = 1; -#else /* MODULE */ - shp->cmd_per_lun = 4; -#endif /* MODULE */ - 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. - */ - shp->select_queue_depths = advansys_select_queue_depths; +#define ASC_DBG_PRT_SCSI_CMND(lvl, s) \ + { \ + if (asc_dbglvl >= (lvl)) { \ + asc_prt_scsi_cmnd(s); \ + } \ + } -#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; -#else /* MODULE */ - shp->cmd_per_lun = 0; -#endif /* MODULE */ -#endif /* version >= v1.3.89 */ +#define ASC_DBG_PRT_ASC_SCSI_Q(lvl, scsiqp) \ + { \ + if (asc_dbglvl >= (lvl)) { \ + asc_prt_asc_scsi_q(scsiqp); \ + } \ + } - /* - * Set the maximum number of scatter-gather elements adapter - * can handle. - */ +#define ASC_DBG_PRT_ASC_QDONE_INFO(lvl, qdone) \ + { \ + if (asc_dbglvl >= (lvl)) { \ + asc_prt_asc_qdone_info(qdone); \ + } \ + } -#ifdef MODULE - /* - * If the driver is compiled as a module, set a conservative - * '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; -#endif /* MODULE */ +#define ASC_DBG_PRT_ADV_SCSI_REQ_Q(lvl, scsiqp) \ + { \ + if (asc_dbglvl >= (lvl)) { \ + asc_prt_adv_scsi_req_q(scsiqp); \ + } \ + } - /* - * The value of 'sg_tablesize' can not exceed the SCSI - * mid-level driver definition of SG_ALL. SG_ALL also - * must not be exceeded, because it is used to define the - * size of the scatter-gather table in 'struct asc_sg_head'. - */ - if (shp->sg_tablesize > SG_ALL) { - shp->sg_tablesize = SG_ALL; - } +#define ASC_DBG_PRT_HEX(lvl, name, start, length) \ + { \ + if (asc_dbglvl >= (lvl)) { \ + asc_prt_hex((name), (start), (length)); \ + } \ + } - ASC_DBG1(1, "advansys_detect: sg_tablesize: %d\n", - shp->sg_tablesize); +#define ASC_DBG_PRT_CDB(lvl, cdb, len) \ + ASC_DBG_PRT_HEX((lvl), "CDB", (uchar *) (cdb), (len)); - /* BIOS start address. */ - shp->base = (char *) ((ulong) AscGetChipBiosAddress( - asc_dvc_varp->iop_base, - asc_dvc_varp->bus_type)); +#define ASC_DBG_PRT_SENSE(lvl, sense, len) \ + ASC_DBG_PRT_HEX((lvl), "SENSE", (uchar *) (sense), (len)); - /* - * Register Board Resources - I/O Port, DMA, IRQ - */ +#define ASC_DBG_PRT_INQUIRY(lvl, inq, len) \ + ASC_DBG_PRT_HEX((lvl), "INQUIRY", (uchar *) (inq), (len)); +#endif /* ADVANSYS_DEBUG */ - /* Register I/O port range */ - ASC_DBG(2, "advansys_detect: request_region()\n"); - request_region(shp->io_port, shp->n_io_port, "advansys"); +#ifndef ADVANSYS_ASSERT +#define ASC_ASSERT(a) +#else /* ADVANSYS_ASSERT */ - /* 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( -"advansys_detect: board %d: request_dma() %d failed %d\n", - boardp->id, shp->dma_channel, ret); - release_region(shp->io_port, shp->n_io_port); -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) - kfree(boardp->prtbuf); -#endif /* version >= v1.3.0 */ - scsi_unregister(shp); - asc_board_count--; - continue; - } - AscEnableIsaDma(shp->dma_channel); - } +#define ASC_ASSERT(a) \ + { \ + if (!(a)) { \ + printk("ASC_ASSERT() Failure: file %s, line %d\n", \ + __FILE__, __LINE__); \ + } \ + } - /* 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) { -#else /* version >= v1.3.70 */ - if ((ret = request_irq(shp->irq, advansys_interrupt, - SA_INTERRUPT | (share_irq == TRUE ? SA_SHIRQ : 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 (shp->dma_channel != NO_ISA_DMA) { - free_dma(shp->dma_channel); - } -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) - kfree(boardp->prtbuf); -#endif /* version >= v1.3.0 */ - scsi_unregister(shp); - asc_board_count--; - continue; - } +#endif /* ADVANSYS_ASSERT */ - /* - * 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); - release_region(shp->io_port, shp->n_io_port); - if (shp->dma_channel != NO_ISA_DMA) { - free_dma(shp->dma_channel); - } -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) - kfree(boardp->prtbuf); -#endif /* version >= v1.3.0 */ -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,70) - free_irq(shp->irq); -#else /* version >= v1.3.70 */ - free_irq(shp->irq, boardp); -#endif /* version >= v1.3.70 */ - scsi_unregister(shp); - asc_board_count--; - continue; - } - ASC_DBG_PRT_SCSI_HOST(2, shp); - } - } - ASC_DBG1(1, "advansys_detect: done: asc_board_count %d\n", asc_board_count); - return asc_board_count; -} /* - * advansys_release() - * - * Release resources allocated for a single AdvanSys adapter. + * --- Driver Structures */ -int -advansys_release(struct Scsi_Host *shp) -{ - asc_board_t *boardp; - ASC_DBG(1, "advansys_release: begin\n"); - boardp = ASC_BOARDP(shp); -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,70) - free_irq(shp->irq); -#else /* version >= v1.3.70 */ - free_irq(shp->irq, boardp); -#endif /* version >= v1.3.70 */ - if (shp->dma_channel != NO_ISA_DMA) { - ASC_DBG(1, "advansys_release: free_dma()\n"); - free_dma(shp->dma_channel); - } - release_region(shp->io_port, shp->n_io_port); -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) - ASC_ASSERT(boardp->prtbuf != NULL); - kfree(boardp->prtbuf); -#endif /* version >= v1.3.0 */ - scsi_unregister(shp); - ASC_DBG(1, "advansys_release: end\n"); - return 0; -} +#ifdef ADVANSYS_STATS + +/* Per board statistics structure */ +struct asc_stats { + /* Driver Entrypoint Statistics */ + ulong command; /* # calls to advansys_command() */ + ulong queuecommand; /* # calls to advansys_queuecommand() */ + ulong abort; /* # calls to advansys_abort() */ + ulong reset; /* # calls to advansys_reset() */ + ulong biosparam; /* # calls to advansys_biosparam() */ + 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 */ + ulong sg_cnt; /* # scatter-gather I/O requests received */ + ulong sg_elem; /* # scatter-gather elements */ + ulong sg_xfer; /* # scatter-gather transfer 512-bytes */ +}; +#endif /* ADVANSYS_STATS */ /* - * advansys_info() - * - * Return suitable for printing on the console with the argument - * adapter's configuration information. - * - * Note: The information line should not exceed ASC_INFO_SIZE bytes, - * otherwise the static 'info' array will be overrun. + * Request queuing structure */ -const char * -advansys_info(struct Scsi_Host *shp) -{ - static char info[ASC_INFO_SIZE]; - asc_board_t *boardp; - ASC_DVC_VAR *asc_dvc_varp; - char *busname; - - boardp = ASC_BOARDP(shp); - asc_dvc_varp = &boardp->asc_dvc_var; - ASC_DBG(1, "advansys_info: begin\n"); - if (asc_dvc_varp->bus_type & ASC_IS_ISA) { - if ((asc_dvc_varp->bus_type & ASC_IS_ISAPNP) == ASC_IS_ISAPNP) { - busname = "ISA PnP"; - } else { - busname = "ISA"; - } - sprintf(info, - "AdvanSys SCSI %s: %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 { - 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, 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"); - return info; -} +typedef struct asc_queue { + 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[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; /* - * advansys_command() + * Adv Library Request Structures * - * Polled-I/O. Apparently host drivers shouldn't return until - * command is finished. + * 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. * - * Note: This is an old interface that is no longer used by the SCSI - * mid-level driver. The new interface, advansys_queuecommand(), - * currently handles all requests. + * 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. */ -int -advansys_command(Scsi_Cmnd *scp) -{ - ASC_DBG1(1, "advansys_command: scp %x\n", (unsigned) scp); - 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; - } - ASC_DBG1(1, "advansys_command: result %x\n", scp->result); - return scp->result; -} +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; /* - * advansys_queuecommand() + * Structure allocated for each board. * - * This function always returns 0. Command return status is saved - * in the 'scp' result field. + * This structure is allocated by scsi_register() at the end + * of the 'Scsi_Host' structure starting at the 'hostdata' + * field. It is guaranteed to be allocated from DMA-able memory. */ -int -advansys_queuecommand(Scsi_Cmnd *scp, void (*done)(Scsi_Cmnd *)) -{ - struct Scsi_Host *shp; - asc_board_t *boardp; - int flags; - Scsi_Cmnd *done_scp; - - shp = scp->host; - boardp = ASC_BOARDP(shp); - ASC_STATS(shp, queuecommand); - +typedef struct asc_board { + 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[ADV_MAX_TID+1]; /* No error request count */ +#endif /* ASC_QUEUE_FLOW_CONTROL */ + 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 */ +#endif /* version >= v1.3.0 */ +#ifdef ADVANSYS_STATS + struct asc_stats asc_stats; /* Board statistics */ +#endif /* ADVANSYS_STATS */ /* - * Disable interrupts to preserve request ordering and provide - * mutually exclusive access to global structures used to initiate - * a request. + * The following fields are used only for Narrow Boards. */ - save_flags(flags); - cli(); - + /* 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 */ /* - * Block new commands while handling a reset or abort request. + * The following fields are used only for Wide Boards. */ - if (boardp->flags & (ASC_HOST_IN_RESET | ASC_HOST_IN_ABORT)) { - if (boardp->flags & ASC_HOST_IN_RESET) { - ASC_DBG1(1, - "advansys_queuecommand: scp %x blocked for reset request\n", - (unsigned) scp); - scp->result = HOST_BYTE(DID_RESET); - } else { - ASC_DBG1(1, - "advansys_queuecommand: scp %x blocked for abort request\n", - (unsigned) scp); - scp->result = HOST_BYTE(DID_ABORT); - } + 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; - /* - * Add blocked requests to the board's 'done' queue. The queued - * requests will be completed at the end of the abort or reset - * handling. - */ - asc_enqueue(&boardp->done, scp, ASC_BACK); - restore_flags(flags); - return 0; - } +/* + * PCI configuration structures + */ +typedef struct _PCI_DATA_ +{ + uchar type; + uchar bus; + uchar slot; + uchar func; + uchar offset; +} PCI_DATA; - /* - * Attempt to execute any waiting commands for the board. - */ - if (!ASC_QUEUE_EMPTY(&boardp->waiting)) { - ASC_DBG(1, - "advansys_queuecommand: before asc_execute_queue() waiting\n"); - asc_execute_queue(&boardp->waiting); - } +typedef struct _PCI_DEVICE_ +{ + ushort vendorID; + ushort deviceID; + ushort slotNumber; + ushort slotFound; + uchar busNumber; + uchar maxBusNumber; + uchar devFunc; + ushort startSlot; + ushort endSlot; + uchar bridge; + uchar type; +} PCI_DEVICE; - /* - * Save the function pointer to Linux mid-level 'done' function - * and attempt to execute the command. - * - * If ASC_ERROR is returned the request has been added to the - * board's 'active' queue and will be completed by the interrupt - * handler. - * - * If ASC_BUSY is returned add the request to the board's per - * target waiting list. - * - * If an error occurred, the request will have been placed on the - * board's 'done' queue and must be completed before returning. - */ - scp->scsi_done = done; - switch (asc_execute_scsi_cmnd(scp)) { - case ASC_NOERROR: - break; - case ASC_BUSY: - asc_enqueue(&boardp->waiting, scp, ASC_BACK); - break; - case ASC_ERROR: - default: - done_scp = asc_dequeue_list(&boardp->done, NULL, ASC_TID_ALL); - /* Interrupts could be enabled here. */ - asc_scsi_done_list(done_scp); - break; - } +typedef struct _PCI_CONFIG_SPACE_ +{ + ushort vendorID; + ushort deviceID; + ushort command; + ushort status; + uchar revision; + uchar classCode[3]; + uchar cacheSize; + uchar latencyTimer; + uchar headerType; + uchar bist; + ulong baseAddress[6]; + ushort reserved[4]; + ulong optionRomAddr; + ushort reserved2[4]; + uchar irqLine; + uchar irqPin; + uchar minGnt; + uchar maxLatency; +} PCI_CONFIG_SPACE; - restore_flags(flags); - return 0; -} /* - * advansys_abort() - * - * Abort the command specified by 'scp'. + * --- Driver Data */ -int -advansys_abort(Scsi_Cmnd *scp) -{ - struct Scsi_Host *shp; - asc_board_t *boardp; - ASC_DVC_VAR *asc_dvc_varp; - int flags; - int do_scsi_done; - int scp_found; - Scsi_Cmnd *done_scp = NULL; - int ret; - /* Save current flags and disable interrupts. */ - save_flags(flags); - cli(); +/* Note: All driver global data should be initialized. */ - ASC_DBG1(1, "advansys_abort: scp %x\n", (unsigned) scp); +#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 */ + 2 /* nlink_t nlink */ +}; +#endif /* version >= v1.3.0 */ -#ifdef ADVANSYS_STATS - if (scp->host != NULL) { - ASC_STATS(scp->host, abort); - } -#endif /* ADVANSYS_STATS */ +/* Number of boards detected in system. */ +STATIC int asc_board_count = 0; +STATIC struct Scsi_Host *asc_host[ASC_NUM_BOARD_SUPPORTED] = { 0 }; -#ifdef ADVANSYS_ASSERT - do_scsi_done = ASC_ERROR; - scp_found = ASC_ERROR; - ret = ASC_ERROR; -#endif /* ADVANSYS_ASSERT */ +/* Overrun buffer shared between all boards. */ +STATIC uchar overrun_buf[ASC_OVERRUN_BSIZE] = { 0 }; -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) - if (scp->serial_number != scp->serial_number_at_timeout) { - ASC_PRINT1( -"advansys_abort: timeout serial number changed for request %x\n", - (unsigned) scp); - do_scsi_done = ASC_FALSE; - scp_found = ASC_FALSE; - ret = SCSI_ABORT_NOT_RUNNING; - } else -#endif /* version >= v1.3.89 */ - if ((shp = scp->host) == NULL) { - scp->result = HOST_BYTE(DID_ERROR); - do_scsi_done = ASC_TRUE; - scp_found = ASC_FALSE; - ret = SCSI_ABORT_ERROR; - } else if ((boardp = ASC_BOARDP(shp))->flags & - (ASC_HOST_IN_RESET | ASC_HOST_IN_ABORT)) { - ASC_PRINT2( -"advansys_abort: board %d: Nested host reset or abort, flags 0x%x\n", - boardp->id, boardp->flags); - do_scsi_done = ASC_TRUE; - if ((asc_rmqueue(&boardp->active, scp) == ASC_TRUE) || - (asc_rmqueue(&boardp->waiting, scp) == ASC_TRUE)) { - scp_found = ASC_TRUE; - } else { - scp_found = ASC_FALSE; - } - scp->result = HOST_BYTE(DID_ERROR); - ret = SCSI_ABORT_ERROR; - } else { - /* Set abort flag to avoid nested reset or abort requests. */ - boardp->flags |= ASC_HOST_IN_ABORT; +/* + * Global structures required to issue a command. + */ +STATIC ASC_SCSI_Q asc_scsi_q = { { 0 } }; +STATIC ASC_SG_HEAD asc_sg_head = { 0 }; - do_scsi_done = ASC_TRUE; - if (asc_rmqueue(&boardp->waiting, scp) == ASC_TRUE) { - /* - * 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; - scp->result = HOST_BYTE(DID_ABORT); - ret = SCSI_ABORT_SUCCESS; - } else if (asc_isqueued(&boardp->active, scp) == ASC_TRUE) { - /* - * If asc_isqueued() found the command on the active - * queue, it has been sent to the 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); +/* List of supported bus types. */ +STATIC ushort asc_bus[ASC_NUM_BUS] ASC_INITDATA = { + ASC_IS_ISA, + ASC_IS_VL, + ASC_IS_EISA, + ASC_IS_PCI, +}; - 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(); +STATIC int pci_scan_method ASC_INITDATA = -1; - /* - * The request will either still be on the active queue - * or have been added to the board's done queue. - */ - if (asc_rmqueue(&boardp->active, scp) == ASC_TRUE) { - scp->result = HOST_BYTE(DID_ABORT); - scp_found = ASC_TRUE; - } else { - scp_found = asc_rmqueue(&boardp->done, scp); - ASC_ASSERT(scp_found == ASC_TRUE); - } +/* + * Used with the LILO 'advansys' option to eliminate or + * limit I/O port probing at boot time, cf. advansys_setup(). + */ +STATIC int asc_iopflag = ASC_FALSE; +STATIC int asc_ioport[ASC_NUM_IOPORT_PROBE] = { 0, 0, 0, 0 }; - } else { - /* - * The command was not found on the active or waiting queues. - */ - do_scsi_done = ASC_TRUE; - scp_found = ASC_FALSE; - ret = SCSI_ABORT_NOT_RUNNING; - } +#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 */ - /* Clear abort flag. */ - boardp->flags &= ~ASC_HOST_IN_ABORT; +#ifdef ADVANSYS_DEBUG +STATIC char * +asc_bus_name[ASC_NUM_BUS] = { + "ASC_IS_ISA", + "ASC_IS_VL", + "ASC_IS_EISA", + "ASC_IS_PCI", +}; - /* - * Because the ASC_HOST_IN_ABORT flag causes both - * 'advansys_interrupt' and 'asc_isr_callback' to - * queue requests to the board's 'done' queue and - * prevents waiting commands from being executed, - * these queued requests must be handled here. - */ - done_scp = asc_dequeue_list(&boardp->done, NULL, ASC_TID_ALL); +STATIC int asc_dbglvl = 0; +#endif /* ADVANSYS_DEBUG */ - /* - * Start any waiting commands for the board. - */ - if (!ASC_QUEUE_EMPTY(&boardp->waiting)) { - ASC_DBG(1, "advansys_interrupt: before asc_execute_queue()\n"); - asc_execute_queue(&boardp->waiting); - } - } +/* Declaration for Asc Library internal data referenced by driver. */ +STATIC PortAddr _asc_def_iop_base[]; - /* Interrupts could be enabled here. */ - /* - * Complete the request to be aborted, unless it has been - * restarted as detected above, even if it was not found on - * the device active or waiting queues. - */ - ASC_ASSERT(do_scsi_done != ASC_ERROR); - ASC_ASSERT(scp_found != ASC_ERROR); - if (do_scsi_done == ASC_TRUE) { - if (scp->scsi_done == NULL) { - ASC_PRINT1( -"advansys_abort: aborted request scsi_done() is NULL, %x\n", - (unsigned) scp); - } else { - if (scp_found == ASC_FALSE) { - ASC_PRINT1( -"advansys_abort: abort request not active or waiting, completing anyway %x\n", - (unsigned) scp); - } - ASC_STATS(scp->host, done); - scp->scsi_done(scp); - } - } +/* + * --- Driver Function Prototypes + * + * advansys.h contains function prototypes for functions global to Linux. + */ - /* - * It is possible for the request done function to re-enable - * interrupts without confusing the driver. But here interrupts - * aren't enabled until all requests have been completed. - */ - if (done_scp != NULL) { - asc_scsi_done_list(done_scp); - } +#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) +STATIC int asc_proc_copy(off_t, off_t, char *, int , char *, int); +#endif /* version >= v1.3.0 */ +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,70) +STATIC void advansys_interrupt(int, struct pt_regs *); +#else /* version >= v1.3.70 */ +STATIC void advansys_interrupt(int, void *, struct pt_regs *); +#endif /* version >= v1.3.70 */ +#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) +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 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_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 */ - ASC_DBG1(1, "advansys_abort: ret %d\n", ret); +/* Declaration for Asc Library internal functions reference by driver. */ +STATIC int AscFindSignature(PortAddr); +STATIC ushort AscGetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort); - /* Re-enable interrupts, if they were enabled on entry. */ - restore_flags(flags); +#ifdef ADVANSYS_STATS +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_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 */ + +#ifdef ADVANSYS_ASSERT +STATIC int interrupts_enabled(void); +#endif /* ADVANSYS_ASSERT */ - ASC_ASSERT(ret != ASC_ERROR); - return ret; -} /* - * advansys_reset() + * --- Linux 'Scsi_Host_Template' and advansys_setup() Functions + */ + +#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) +/* + * advansys_proc_info() - /proc/scsi/advansys/[0-(ASC_NUM_BOARD_SUPPORTED-1)] * - * Reset the device associated with the command 'scp'. + * *buffer: I/O buffer + * **start: if inout == FALSE pointer into buffer where user read should start + * offset: current offset into a /proc/scsi/advansys/[0...] file + * length: length of buffer + * hostno: Scsi_Host host_no + * inout: TRUE - user is writing; FALSE - user is reading + * + * Return the number of bytes read from or written to a + * /proc/scsi/advansys/[0...] file. + * + * Note: This function uses the per board buffer 'prtbuf' which is + * allocated when the board is initialized in advansys_detect(). The + * buffer is ASC_PRTBUF_SIZE bytes. The function asc_proc_copy() is + * used to write to the buffer. The way asc_proc_copy() is written + * if 'prtbuf' is too small it will not be overwritten. Instead the + * user just won't get all the available statistics. */ int -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,89) -advansys_reset(Scsi_Cmnd *scp) -#else /* version >= v1.3.89 */ -advansys_reset(Scsi_Cmnd *scp, unsigned int reset_flags) -#endif /* version >= v1.3.89 */ +advansys_proc_info(char *buffer, char **start, off_t offset, int length, + int hostno, int inout) { - struct Scsi_Host *shp; - asc_board_t *boardp; - ASC_DVC_VAR *asc_dvc_varp; - int flags; - Scsi_Cmnd *done_scp = NULL, *last_scp = NULL; - Scsi_Cmnd *tscp, *new_last_scp; - int do_scsi_done; - int scp_found; - int status; - int target; - int ret; + struct Scsi_Host *shp; + asc_board_t *boardp; + int i; + char *cp; + int cplen; + int cnt; + int totcnt; + int leftlen; + char *curbuf; + off_t advoffset; + Scsi_Device *scd; - /* Save current flags and disable interrupts. */ - save_flags(flags); - cli(); + ASC_DBG(1, "advansys_proc_info: begin\n"); - ASC_DBG1(1, "advansys_reset: %x\n", (unsigned) scp); + /* + * User write not supported. + */ + if (inout == TRUE) { + return(-ENOSYS); + } -#ifdef ADVANSYS_STATS - if (scp->host != NULL) { - ASC_STATS(scp->host, reset); - } -#endif /* ADVANSYS_STATS */ + /* + * User read of /proc/scsi/advansys/[0...] file. + */ -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) - if ((reset_flags & SCSI_RESET_ASYNCHRONOUS) && - (scp->serial_number != scp->serial_number_at_timeout)) { - ASC_PRINT1( -"advansys_reset: timeout serial number changed for request %x\n", - (unsigned) scp); - do_scsi_done = ASC_FALSE; - scp_found = ASC_FALSE; - ret = SCSI_RESET_NOT_RUNNING; - } else -#endif /* version >= v1.3.89 */ - if ((shp = scp->host) == NULL) { - scp->result = HOST_BYTE(DID_ERROR); - do_scsi_done = ASC_TRUE; - scp_found = ASC_FALSE; - ret = SCSI_RESET_ERROR; - } else if ((boardp = ASC_BOARDP(shp))->flags & - (ASC_HOST_IN_RESET | ASC_HOST_IN_ABORT)) { - ASC_PRINT2( -"advansys_reset: board %d: Nested host reset or abort, flags 0x%x\n", - boardp->id, boardp->flags); - do_scsi_done = ASC_TRUE; - if ((asc_rmqueue(&boardp->active, scp) == ASC_TRUE) || - (asc_rmqueue(&boardp->waiting, scp) == ASC_TRUE)) { - scp_found = ASC_TRUE; - } else { - scp_found = ASC_FALSE; - } - scp->result = HOST_BYTE(DID_ERROR); - ret = SCSI_RESET_ERROR; - } else if (jiffies >= boardp->last_reset && - jiffies < (boardp->last_reset + (10 * HZ))) { - /* - * Don't allow a reset to be attempted within 10 seconds - * of the last reset. - * - * If 'jiffies' wrapping occurs, the reset request will go - * through, because a wrapped 'jiffies' would not pass the - * test above. - */ - ASC_DBG(1, - "advansys_reset: reset within 10 sec of last reset ignored\n"); - do_scsi_done = ASC_TRUE; - if ((asc_rmqueue(&boardp->active, scp) == ASC_TRUE) || - (asc_rmqueue(&boardp->waiting, scp) == ASC_TRUE)) { - scp_found = ASC_TRUE; - } else { - scp_found = ASC_FALSE; + /* Find the specified board. */ + for (i = 0; i < asc_board_count; i++) { + if (asc_host[i]->host_no == hostno) { + break; } - scp->result = HOST_BYTE(DID_ERROR); - ret = SCSI_RESET_ERROR; - } else { - int device_reset = ASC_FALSE; + } + if (i == asc_board_count) { + return(-ENOENT); + } - do_scsi_done = ASC_TRUE; + shp = asc_host[i]; + boardp = ASC_BOARDP(shp); - /* Set reset flag to avoid nested reset or abort requests. */ - boardp->flags |= ASC_HOST_IN_RESET; + /* Copy read data starting at the beginning of the buffer. */ + *start = buffer; + curbuf = buffer; + advoffset = 0; + totcnt = 0; + leftlen = length; - /* - * If the request is on the target waiting or active queue - * or the board done queue, then remove it and note that it - * was found. - */ - if (asc_rmqueue(&boardp->active, scp) == ASC_TRUE) { - ASC_DBG(1, "advansys_reset: active scp_found = TRUE\n"); - scp_found = ASC_TRUE; - } else if (asc_rmqueue(&boardp->waiting, scp) == ASC_TRUE) { - ASC_DBG(1, "advansys_reset: waiting scp_found = TRUE\n"); - scp_found = ASC_TRUE; - } else if (asc_rmqueue(&boardp->done, scp) == ASC_TRUE) { - scp_found = ASC_TRUE; - } else { - scp_found = ASC_FALSE; + /* + * Get board configuration information. + * + * advansys_info() returns the board string from its own static buffer. + */ + cp = (char *) advansys_info(shp); + strcat(cp, "\n"); + cplen = strlen(cp); + /* Copy board information. */ + 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 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; + } - /* - * 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 */ + /* + * Display driver information for each device attached to the board. + */ + cp = boardp->prtbuf; + cplen = asc_prt_board_devices(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 target driver information for each device attached + * to the board. + */ +#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; /* - * Reset the target's SCSI bus. + * Note: If proc_print_scsidevice() writes more than + * ASC_PRTBUF_SIZE bytes, it will overrun 'prtbuf'. */ - 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; + proc_print_scsidevice(scd, cp, &cplen, 0); + 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 EEPROM configuration for the board. + */ + cp = boardp->prtbuf; + 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; + leftlen -= cnt; + if (leftlen == 0) { + ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt); + return totcnt; + } + advoffset += cplen; + curbuf += cnt; -#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. - */ + /* + * Display driver configuration and information for the board. + */ + cp = boardp->prtbuf; + cplen = asc_prt_driver_conf(shp, cp, ASC_PRTBUF_SIZE); + ASC_ASSERT(cplen < ASC_PRTBUF_SIZE); + cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen); + totcnt += cnt; + leftlen -= cnt; + if (leftlen == 0) { + ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt); + return totcnt; + } + advoffset += cplen; + curbuf += cnt; - 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(); +#ifdef ADVANSYS_STATS + /* + * Display driver statistics for the board. + */ + cp = boardp->prtbuf; + cplen = asc_prt_board_stats(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; +#endif /* ADVANSYS_STATS */ - /* - * If the device has been reset, try to initialize it. - */ - if (status == ASC_TRUE) { - status = asc_init_dev(asc_dvc_varp, scp); - } + /* + * Display Asc Library dynamic configuration information + * for the board. + */ + cp = boardp->prtbuf; + 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; + leftlen -= cnt; + if (leftlen == 0) { + ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt); + return totcnt; + } + advoffset += cplen; + curbuf += cnt; - switch (status) { - case ASC_TRUE: - ASC_DBG(1, "advansys_reset: AscResetDevice() success\n"); - device_reset = ASC_TRUE; - ret = SCSI_RESET_SUCCESS; - break; - case ASC_ERROR: - default: - ASC_DBG(1, -"advansys_reset: AscResetDevice() failed; Calling AscResetSB()\n"); - sti(); /* Enable interrupts for AscResetSB(). */ - status = AscResetSB(asc_dvc_varp); - cli(); - switch (status) { - case ASC_TRUE: - ASC_DBG(1, "advansys_reset: AscResetSB() TRUE\n"); - ret = SCSI_RESET_SUCCESS; - break; - case ASC_ERROR: - default: - ASC_DBG(1, "advansys_reset: AscResetSB() ERROR\n"); - ret = SCSI_RESET_ERROR; - break; - } - break; - } - } -#endif /* version >= v1.3.89 */ - - /* - * Because the ASC_HOST_IN_RESET flag causes both - * 'advansys_interrupt' and 'asc_isr_callback' to - * queue requests to the board's 'done' queue and - * prevents waiting commands from being executed, - * these queued requests must be handled here. - */ - done_scp = asc_dequeue_list(&boardp->done, &last_scp, - ASC_TID_ALL); - - /* - * If a device reset was performed dequeue all waiting - * and active requests for the device and set the request - * status to DID_RESET. - * - * If a SCSI bus reset was performed dequeue all waiting - * and active requests for all devices and set the request - * status to DID_RESET. - */ - if (device_reset == ASC_TRUE) { - target = scp->target; - } else { - target = ASC_TID_ALL; - } - - /* - * Add active requests to 'done_scp' and set the request status - * to DID_RESET. - */ - if (done_scp == NULL) { - done_scp = asc_dequeue_list(&boardp->active, &last_scp, target); - for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) { - tscp->result = HOST_BYTE(DID_RESET); - } - } else { - ASC_ASSERT(last_scp != NULL); - REQPNEXT(last_scp) = asc_dequeue_list(&boardp->active, - &new_last_scp, target); - if (new_last_scp != NULL) { - ASC_ASSERT(REQPNEXT(last_scp) != NULL); - for (tscp = REQPNEXT(last_scp); tscp; tscp = REQPNEXT(tscp)) { - tscp->result = HOST_BYTE(DID_RESET); - } - last_scp = new_last_scp; - } - } - - /* - * Add waiting requests to 'done_scp' and set the request status - * to DID_RESET. - */ - if (done_scp == NULL) { - done_scp = asc_dequeue_list(&boardp->waiting, &last_scp, target); - for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) { - tscp->result = HOST_BYTE(DID_RESET); - } - } else { - ASC_ASSERT(last_scp != NULL); - REQPNEXT(last_scp) = asc_dequeue_list(&boardp->waiting, - &new_last_scp, target); - if (new_last_scp != NULL) { - ASC_ASSERT(REQPNEXT(last_scp) != NULL); - for (tscp = REQPNEXT(last_scp); tscp; tscp = REQPNEXT(tscp)) { - tscp->result = HOST_BYTE(DID_RESET); - } - last_scp = new_last_scp; - } - } - - /* Save the time of the most recently completed reset. */ - boardp->last_reset = jiffies; - - /* Clear reset flag. */ - boardp->flags &= ~ASC_HOST_IN_RESET; - - /* - * Start any waiting commands for the board. - */ - if (!ASC_QUEUE_EMPTY(&boardp->waiting)) { - ASC_DBG(1, "advansys_interrupt: before asc_execute_queue()\n"); - asc_execute_queue(&boardp->waiting); - } - ret = SCSI_RESET_SUCCESS; - } - - /* Interrupts could be enabled here. */ - - ASC_ASSERT(do_scsi_done != ASC_ERROR); - ASC_ASSERT(scp_found != ASC_ERROR); - if (do_scsi_done == ASC_TRUE) { - if (scp->scsi_done == NULL) { - ASC_PRINT1( -"advansys_reset: reset request scsi_done() is NULL, %x\n", - (unsigned) scp); - } else { - if (scp_found == ASC_FALSE) { - ASC_PRINT1( -"advansys_reset: reset request not active or waiting, completing anyway %x\n", - (unsigned) scp); - } - ASC_STATS(scp->host, done); - scp->scsi_done(scp); - } - } - - /* - * It is possible for the request done function to re-enable - * interrupts without confusing the driver. But here interrupts - * aren't enabled until requests have been completed. - */ - if (done_scp != NULL) { - asc_scsi_done_list(done_scp); - } - - ASC_DBG1(1, "advansys_reset: ret %d", ret); - - /* Re-enable interrupts, if they were enabled on entry. */ - restore_flags(flags); + ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt); - ASC_ASSERT(ret != ASC_ERROR); - return ret; + return totcnt; } - -/* - * advansys_biosparam() - * - * Translate disk drive geometry if the "BIOS greater than 1 GB" - * support is enabled for a drive. - * - * ip (information pointer) is an int array with the following definition: - * ip[0]: heads - * ip[1]: sectors - * ip[2]: cylinders - */ -int -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0) -advansys_biosparam(Disk *dp, int dep, int ip[]) -#else /* version >= v1.3.0 */ -advansys_biosparam(Disk *dp, kdev_t dep, int ip[]) #endif /* version >= v1.3.0 */ -{ - 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; - } else { - ip[0] = 64; - ip[1] = 32; - } - ip[2] = dp->capacity / (ip[0] * ip[1]); - ASC_DBG(1, "advansys_biosparam: end\n"); - return 0; -} /* - * advansys_setup() - * - * This function is called from init/main.c at boot time. - * It it passed LILO parameters that can be set from the - * LILO command line or in /etc/lilo.conf. + * advansys_detect() * - * It is used by the AdvanSys driver to either disable I/O - * port scanning or to limit scanning to 1 - 4 I/O ports. - * Regardless of the option setting EISA and PCI boards - * will still be searched for and detected. This option - * only affects searching for ISA and VL boards. + * Detect function for AdvanSys adapters. * - * If ADVANSYS_DEBUG is defined the driver debug level may - * be set using the 5th (ASC_NUM_BOARD_SUPPORTED + 1) I/O Port. + * Argument is a pointer to the host driver's scsi_hosts entry. * - * Examples: - * 1. Eliminate I/O port scanning: - * boot: linux advansys= - * or - * boot: linux advansys=0x0 - * 2. Limit I/O port scanning to one I/O port: - * boot: linux advansys=0x110 - * 3. Limit I/O port scanning to four I/O ports: - * boot: linux advansys=0x110,0x210,0x230,0x330 - * 4. If ADVANSYS_DEBUG, limit I/O port scanning to four I/O ports and - * set the driver debug level to 2. - * boot: linux advansys=0x110,0x210,0x230,0x330,0xdeb2 + * Return number of adapters found. * - * ints[0] - number of arguments - * ints[1] - first argument - * ints[2] - second argument - * ... + * Note: Because this function is called during system initialization + * it must not call SCSI mid-level functions including scsi_malloc() + * and scsi_free(). */ ASC_INITFUNC( -void -advansys_setup(char *str, int *ints) +int +advansys_detect(Scsi_Host_Template *tpnt) ) { - int i; + static int detect_called = ASC_FALSE; + int iop; + int bus; + struct Scsi_Host *shp; + asc_board_t *boardp; + 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 (asc_iopflag == ASC_TRUE) { - printk("AdvanSys SCSI: 'advansys' LILO option may appear only once\n"); - return; + if (detect_called == ASC_FALSE) { + detect_called = ASC_TRUE; + } else { + printk("AdvanSys SCSI: advansys_detect() multiple calls ignored\n"); + return 0; } - asc_iopflag = ASC_TRUE; + ASC_DBG(1, "advansys_detect: begin\n"); - if (ints[0] > ASC_NUM_BOARD_SUPPORTED) { -#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; - } else { -#endif /* ADVANSYS_DEBUG */ - printk("AdvanSys SCSI: only %d I/O ports accepted\n", - ASC_NUM_BOARD_SUPPORTED); -#ifdef ADVANSYS_DEBUG - } -#endif /* ADVANSYS_DEBUG */ - } +#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) + tpnt->proc_dir = &proc_scsi_advansys; +#endif /* version >= v1.3.0 */ -#ifdef ADVANSYS_DEBUG - ASC_DBG1(1, "advansys_setup: ints[0] %d\n", ints[0]); - for (i = 1; i < ints[0]; i++) { - ASC_DBG2(1, " ints[%d] %x", i, ints[i]); - } - ASC_DBG(1, "\n"); -#endif /* ADVANSYS_DEBUG */ + asc_board_count = 0; - for (i = 1; i <= ints[0] && i <= ASC_NUM_BOARD_SUPPORTED; i++) { - asc_ioport[i-1] = ints[i]; - ASC_DBG2(1, "advansys_setup: asc_ioport[%d] %x\n", - i - 1, asc_ioport[i-1]); + /* + * If I/O port probing has been modified, then verify and + * clean-up the 'asc_ioport' list. + */ + if (asc_iopflag == ASC_TRUE) { + 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) { + for (iop = 0; iop < ASC_IOADR_TABLE_MAX_IX; iop++) { + if (_asc_def_iop_base[iop] == asc_ioport[ioport]) { + break; + } + } + if (iop == ASC_IOADR_TABLE_MAX_IX) { + printk( +"AdvanSys SCSI: specified I/O Port 0x%X is invalid\n", + asc_ioport[ioport]); + asc_ioport[ioport] = 0; + } + } + } + ioport = 0; } -} + memset(&pciDevice, 0, sizeof(PCI_DEVICE)); + memset(&pciConfig, 0, sizeof(PCI_CONFIG_SPACE)); + pciDevice.maxBusNumber = PCI_MAX_BUS; + pciDevice.endSlot = PCI_MAX_SLOT; -/* - * --- Loadable Driver Support - */ - -#ifdef MODULE -Scsi_Host_Template driver_template = ADVANSYS; -# include "scsi_module.c" -#endif /* MODULE */ + for (bus = 0; bus < ASC_NUM_BUS; bus++) { + ASC_DBG2(1, "advansys_detect: bus search type %d (%s)\n", + bus, asc_bus_name[bus]); + iop = 0; -/* - * --- Miscellaneous Driver Functions - */ + while (asc_board_count < ASC_NUM_BOARD_SUPPORTED) { -/* - * First-level interrupt handler. - * - * For versions > v1.3.70, 'dev_id' is a pointer to the interrupting - * adapter's asc_board_t. Because all boards are currently checked - * for interrupts on each interrupt, 'dev_id' is not referenced. 'dev_id' - * could be used to identify an interrupt passed to the AdvanSys driver, - * which is for a device sharing an interrupt with an AdvanSys adapter. - */ -STATIC void -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,70) -advansys_interrupt(int irq, struct pt_regs *regs) -#else /* version >= v1.3.70 */ -advansys_interrupt(int irq, void *dev_id, struct pt_regs *regs) -#endif /* version >= v1.3.70 */ -{ - int flags; - int i; - asc_board_t *boardp; - Scsi_Cmnd *done_scp = NULL, *last_scp = NULL; - Scsi_Cmnd *new_last_scp; + ASC_DBG1(2, "advansys_detect: asc_board_count %d\n", + asc_board_count); - /* Disable interrupts, if they aren't already disabled. */ - save_flags(flags); - cli(); + switch (asc_bus[bus]) { + case ASC_IS_ISA: + case ASC_IS_VL: + if (asc_iopflag == ASC_FALSE) { + iop = AscSearchIOPortAddr(iop, asc_bus[bus]); + } else { + /* + * ISA and VL I/O port scanning has either been + * eliminated or limited to selected ports on + * the LILO command line, /etc/lilo.conf, or + * by setting variables when the module was loaded. + */ + ASC_DBG(1, "advansys_detect: I/O port scanning modified\n"); + ioport_try_again: + iop = 0; + for (; ioport < ASC_NUM_IOPORT_PROBE; ioport++) { + if ((iop = asc_ioport[ioport]) != 0) { + break; + } + } + if (iop) { + 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); + /* 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); + /* Don't try this I/O port twice. */ + asc_ioport[ioport] = 0; + goto ioport_try_again; + } else { + /* + * If this isn't an ISA board, then it must be + * a VL board. If currently looking an ISA + * board is being looked for then try for + * another ISA board in 'asc_ioport'. + */ + if (asc_bus[bus] == ASC_IS_ISA && + (AscGetChipVersion(iop, ASC_IS_ISA) & + ASC_CHIP_VER_ISA_BIT) == 0) { + /* + * Don't clear 'asc_ioport[ioport]'. Try + * this board again for VL. Increment + * 'ioport' past this board. + */ + ioport++; + goto ioport_try_again; + } + } + /* + * This board appears good, don't try the I/O port + * again by clearing its value. Increment 'ioport' + * for the next iteration. + */ + asc_ioport[ioport++] = 0; + } + } + break; - 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); - } + case ASC_IS_EISA: + iop = AscSearchIOPortAddr(iop, asc_bus[bus]); + break; - /* - * Start waiting requests and create a list of completed requests. - * - * If a reset or abort request is being performed for the board, - * the reset or abort handler will complete pending requests after - * it has completed. - */ - if ((boardp->flags & (ASC_HOST_IN_RESET | ASC_HOST_IN_ABORT)) == 0) { - /* Start any waiting commands for the board. */ - if (!ASC_QUEUE_EMPTY(&boardp->waiting)) { - ASC_DBG(1, "advansys_interrupt: before asc_execute_queue()\n"); - asc_execute_queue(&boardp->waiting); + case ASC_IS_PCI: + if (asc_srch_pci_dev(&pciDevice) != PCI_DEVICE_FOUND) { + iop = 0; + } else { + ASC_DBG2(2, + "advansys_detect: slotFound %d, busNumber %d\n", + pciDevice.slotFound, pciDevice.busNumber); + asc_get_pci_cfg(&pciDevice, &pciConfig); + iop = pciConfig.baseAddress[0] & PCI_IOADDRESS_MASK; + 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; + + default: + ASC_PRINT1("advansys_detect: unknown bus type: %d\n", + asc_bus[bus]); + break; } + ASC_DBG1(1, "advansys_detect: iop %x\n", iop); - /* - * Add to the list of requests that must be completed. + /* + * Adapter not found, try next bus type. */ - if (done_scp == NULL) { - done_scp = asc_dequeue_list(&boardp->done, &last_scp, - ASC_TID_ALL); - } else { - ASC_ASSERT(last_scp != NULL); - REQPNEXT(last_scp) = asc_dequeue_list(&boardp->done, - &new_last_scp, ASC_TID_ALL); - if (new_last_scp != NULL) { - ASC_ASSERT(REQPNEXT(last_scp) != NULL); - last_scp = new_last_scp; - } + if (iop == 0) { + break; } - } - } - /* Interrupts could be enabled here. */ + /* + * Adapter found. + * + * Register the adapter, get its configuration, and + * initialize it. + */ + ASC_DBG(2, "advansys_detect: scsi_register()\n"); + shp = scsi_register(tpnt, sizeof(asc_board_t)); - /* - * It is possible for the request done function to re-enable - * interrupts without confusing the driver. But here interrupts - * aren't enabled until all requests have been completed. - */ - asc_scsi_done_list(done_scp); + /* Save a pointer to the Scsi_host of each board found. */ + asc_host[asc_board_count++] = shp; - /* Re-enable interrupts, if they were enabled on entry. */ - restore_flags(flags); + /* Initialize private per board data */ + boardp = ASC_BOARDP(shp); + memset(boardp, 0, sizeof(asc_board_t)); + boardp->id = asc_board_count - 1; - ASC_DBG(1, "advansys_interrupt: end\n"); - return; -} + /* + * 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,89) -/* - * Set the number of commands to queue per device for the - * specified host adapter. - */ -STATIC void -advansys_select_queue_depths(struct Scsi_Host *shp, Scsi_Device *devicelist) -{ - Scsi_Device *device; - asc_board_t *boardp; +#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 */ - boardp = ASC_BOARDP(shp); - for (device = devicelist; device != NULL; device = device->next) { - if (device->host != shp) { - continue; - } - /* - * Save a pointer to the device and set its initial/maximum - * queue depth. - */ - boardp->device[device->id] = device; - device->queue_depth = boardp->asc_dvc_var.max_dvc_qng[device->id]; - ASC_DBG3(1, "advansys_select_queue_depths: shp %x, id %d, depth %d\n", - (unsigned) shp, device->id, device->queue_depth); - } -} -#endif /* version >= v1.3.89 */ + /* + * 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; + } -/* - * Function used only with polled I/O requests that are initiated by - * advansys_command(). - */ -STATIC void -advansys_command_done(Scsi_Cmnd *scp) -{ - ASC_DBG1(1, "advansys_command_done: scp %x\n", (unsigned) scp); - scp->SCp.Status = 1; -} +#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( +"advansys_detect: board %d: kmalloc(%d, %d) returned NULL\n", + boardp->id, ASC_PRTBUF_SIZE, GFP_ATOMIC); + scsi_unregister(shp); + asc_board_count--; + continue; + } +#endif /* version >= v1.3.0 */ -/* - * Complete all requests on the singly linked list pointed - * to by 'scp'. - * - * Interrupts can be enabled on entry. - */ -STATIC void -asc_scsi_done_list(Scsi_Cmnd *scp) -{ - Scsi_Cmnd *tscp; - - while (scp != NULL) { - tscp = REQPNEXT(scp); - REQPNEXT(scp) = NULL; - ASC_STATS(scp->host, done); - ASC_ASSERT(scp->scsi_done != NULL); - scp->scsi_done(scp); - scp = tscp; - } - return; -} + 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); + 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; + 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); + } -/* - * Execute a single 'Scsi_Cmnd'. - * - * The function 'done' is called when the request has been completed. - * - * Scsi_Cmnd: - * - * host - board controlling device - * device - device to send command - * target - target of device - * lun - lun of device - * cmd_len - length of SCSI 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 - * - * 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 - * - * 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 - * - * If this function returns ASC_NOERROR or ASC_ERROR the request - * has been enqueued on the board's 'done' queue and must be - * completed by the caller. - * - * If ASC_BUSY is returned the request must be enqueued by the - * caller and re-tried later. - */ -STATIC int -asc_execute_scsi_cmnd(Scsi_Cmnd *scp) -{ - asc_board_t *boardp; - ASC_DVC_VAR *asc_dvc_varp; - Scsi_Device *device; - int ret; + /* + * Read the board configuration. + */ + 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( +"AscInitGetConfig: board %d: I/O port increment switch enabled\n", + boardp->id); + break; + case ASC_WARN_EEPROM_CHKSUM: + ASC_PRINT1( +"AscInitGetConfig: board %d: EEPROM checksum error\n", + 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( +"AscInitGetConfig: board %d: tag queuing enabled w/o disconnects\n", + boardp->id); + break; + default: + ASC_PRINT2( +"AscInitGetConfig: board %d: unknown warning: %x\n", + 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); + } + } 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 */ + scsi_unregister(shp); + asc_board_count--; + continue; + } - ASC_ASSERT(interrupts_enabled() == ASC_FALSE); - ASC_DBG2(1, "asc_execute_scsi_cmnd: scp %x, done %x\n", - (unsigned) scp, (unsigned) scp->scsi_done); + /* + * Save the EEPROM configuration so that it can be displayed + * from /proc/scsi/advansys/[0...]. + */ + if (ASC_NARROW_BOARD(boardp)) { - boardp = ASC_BOARDP(scp->host); - asc_dvc_varp = &boardp->asc_dvc_var; - device = boardp->device[scp->target]; + ASCEEP_CONFIG *ep; - /* - * 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); - asc_enqueue(&boardp->done, scp, ASC_BACK); - return ASC_ERROR; - } - boardp->init_tidmask |= ASC_TIX_TO_TARGET_ID(scp->target); - } + /* + * 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); - /* - * Mutually exclusive access is required to 'asc_scsi_q' and - * 'asc_sg_head' until after the request is started. - */ - memset(&asc_scsi_q, 0, sizeof(ASC_SCSI_Q)); + /* + * 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( +"AscInitSetConfig: board %d: I/O port increment switch enabled\n", + boardp->id); + break; + case ASC_WARN_EEPROM_CHKSUM: + ASC_PRINT1( +"AscInitSetConfig: board %d: EEPROM checksum error\n", + 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( +"AscInitSetConfig: board %d: tag queuing w/o disconnects\n", + 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( +"AscInitSetConfig: board %d error: init_state %x, err_code %x\n", + boardp->id, asc_dvc_varp->init_state, + asc_dvc_varp->err_code); +#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) + kfree(boardp->prtbuf); +#endif /* version >= v1.3.0 */ + scsi_unregister(shp); + asc_board_count--; + continue; + } - /* - * Point the ASC_SCSI_Q to the 'Scsi_Cmnd'. - */ - asc_scsi_q.q2.srb_ptr = (ulong) scp; + /* + * 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 { - /* - * Build the ASC_SCSI_Q request. - */ - asc_scsi_q.cdbptr = &scp->cmnd[0]; - asc_scsi_q.q2.cdb_len = scp->cmd_len; - asc_scsi_q.q1.target_id = ASC_TID_TO_TARGET_ID(scp->target); - asc_scsi_q.q1.target_lun = scp->lun; - asc_scsi_q.q2.target_ix = ASC_TIDLUN_TO_IX(scp->target, scp->lun); -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0) - asc_scsi_q.q1.sense_addr = (ulong) &scp->sense_buffer[0]; -#else /* version >= v2.0.0 */ - asc_scsi_q.q1.sense_addr = virt_to_bus(&scp->sense_buffer[0]); -#endif /* version >= v2.0.0 */ - asc_scsi_q.q1.sense_len = sizeof(scp->sense_buffer); + ADVEEP_CONFIG *ep; - /* - * If there are any outstanding requests for the current target, - * then every 255th request send an ORDERED request. This heuristic - * tries to retain the benefit of request sorting while preventing - * request starvation. 255 is the max number of tags or pending commands - * a device may have outstanding. - * - * The request count is incremented below for every successfully - * started request. - * - */ - if ((asc_dvc_varp->cur_dvc_qng[scp->target] > 0) && - (boardp->reqcnt[scp->target] % 255) == 0) { - asc_scsi_q.q2.tag_code = M2_QTAG_MSG_ORDERED; - } else { - asc_scsi_q.q2.tag_code = M2_QTAG_MSG_SIMPLE; - } + /* + * 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; - /* - * Build ASC_SCSI_Q for a contiguous buffer or a scatter-gather - * buffer command. - */ - if (scp->use_sg == 0) { - /* - * CDB request of single contiguous buffer. - */ - ASC_STATS(scp->host, cont_cnt); -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0) - asc_scsi_q.q1.data_addr = (ulong) scp->request_buffer; -#else /* version >= v2.0.0 */ - asc_scsi_q.q1.data_addr = virt_to_bus(scp->request_buffer); -#endif /* version >= v2.0.0 */ - asc_scsi_q.q1.data_cnt = scp->request_bufflen; - ASC_STATS_ADD(scp->host, cont_xfer, - ASC_CEILING(scp->request_bufflen, 512)); - asc_scsi_q.q1.sg_queue_cnt = 0; - asc_scsi_q.sg_head = NULL; - } else { - /* - * CDB scatter-gather request list. - */ - int sgcnt; - struct scatterlist *slp; + /* + * 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); - if (scp->use_sg > scp->host->sg_tablesize) { - ASC_PRINT3( -"asc_execute_scsi_cmnd: board %d: use_sg %d > sg_tablesize %d\n", - boardp->id, scp->use_sg, scp->host->sg_tablesize); - scp->result = HOST_BYTE(DID_ERROR); - asc_enqueue(&boardp->done, scp, ASC_BACK); - return ASC_ERROR; - } + /* + * Finish initializing the 'Scsi_Host' structure. + */ + shp->irq = adv_dvc_varp->irq_no; + } - ASC_STATS(scp->host, sg_cnt); +#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) + /* + * 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. + */ + shp->max_channel = 0; +#endif /* version >= v1.3.89 */ + if (ASC_NARROW_BOARD(boardp)) { + shp->max_id = ASC_MAX_TID + 1; + shp->max_lun = ASC_MAX_LUN + 1; - /* - * Allocate a ASC_SG_HEAD structure and set the ASC_SCSI_Q - * to point to it. - */ - memset(&asc_sg_head, 0, sizeof(ASC_SG_HEAD)); + 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; - asc_scsi_q.q1.cntl |= QC_SG_HEAD; - asc_scsi_q.sg_head = &asc_sg_head; - asc_scsi_q.q1.data_cnt = 0; - asc_scsi_q.q1.data_addr = 0; - asc_sg_head.entry_cnt = asc_scsi_q.q1.sg_queue_cnt = scp->use_sg; - ASC_STATS_ADD(scp->host, sg_elem, asc_sg_head.entry_cnt); + /* 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; - /* - * Convert scatter-gather list into ASC_SG_HEAD list. - */ - slp = (struct scatterlist *) scp->request_buffer; - for (sgcnt = 0; sgcnt < scp->use_sg; sgcnt++, slp++) { -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0) - asc_sg_head.sg_list[sgcnt].addr = (ulong) slp->address; -#else /* version >= v2.0.0 */ - asc_sg_head.sg_list[sgcnt].addr = virt_to_bus(slp->address); -#endif /* version >= v2.0.0 */ - asc_sg_head.sg_list[sgcnt].bytes = slp->length; - ASC_STATS_ADD(scp->host, sg_xfer, ASC_CEILING(slp->length, 512)); - } - } + /* + * 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; - ASC_DBG_PRT_SCSI_Q(2, &asc_scsi_q); - ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len); + shp->this_id = adv_dvc_varp->chip_scsi_id; - /* - * 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, asc_noerror); - /* - * Increment monotonically increasing per device successful - * request counter. Wrapping doesn't matter. - */ - boardp->reqcnt[scp->target]++; + /* Set maximum number of queues the adapter can handle. */ + shp->can_queue = adv_dvc_varp->max_host_qng; + } -#if ASC_QUEUE_FLOW_CONTROL - /* - * 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. - */ - 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++; +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,89) + /* + * 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; +#else /* MODULE */ + shp->cmd_per_lun = 4; +#endif /* MODULE */ + ASC_DBG1(1, "advansys_detect: cmd_per_lun: %d\n", shp->cmd_per_lun); +#else /* version >= v1.3.89 */ + /* + * 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. + */ +#ifdef MODULE + 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 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; } - } -#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. - */ - boardp->nerrcnt[scp->target] = 0; - if (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, 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_DBG(1, "asc_execute_scsi_cmnd: end\n"); - ASC_ASSERT(interrupts_enabled() == ASC_FALSE); - return ret; -} +#ifdef MODULE + /* + * 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. + */ + if (shp->sg_tablesize > 64) { + shp->sg_tablesize = 64; + } +#endif /* MODULE */ -/* - * asc_isr_callback() - Second Level Interrupt Handler called by AscISR(). - */ -STATIC void -asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep) -{ - asc_board_t *boardp; - Scsi_Cmnd *scp; - struct Scsi_Host *shp; - int i; + /* + * The value of 'sg_tablesize' can not exceed the SCSI + * mid-level driver definition of SG_ALL. SG_ALL also + * must not be exceeded, because it is used to define the + * size of the scatter-gather table in 'struct asc_sg_head'. + */ + if (shp->sg_tablesize > SG_ALL) { + shp->sg_tablesize = SG_ALL; + } - ASC_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_DBG1(1, "advansys_detect: sg_tablesize: %d\n", + shp->sg_tablesize); - /* - * Get the Scsi_Cmnd structure and Scsi_Host structure for the - * command that has been completed. - */ - 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); + /* BIOS start address. */ + 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 (scp == NULL) { - ASC_PRINT("asc_isr_callback: scp is NULL\n"); - return; - } + /* + * 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; + } + } - /* - * 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; - } - } - if (i == asc_board_count) { - ASC_PRINT2("asc_isr_callback: scp %x has bad host pointer, host %x\n", - (unsigned) scp, (unsigned) shp); - return; - } + /* + * Register Board Resources - I/O Port, DMA, IRQ + */ - ASC_STATS(shp, callback); - ASC_DBG1(1, "asc_isr_callback: shp %x\n", (unsigned) shp); + /* Register I/O port range. */ + ASC_DBG(2, "advansys_detect: request_region()\n"); + request_region(shp->io_port, shp->n_io_port, "advansys"); - /* - * If the request isn't found on the active queue, it may - * have been removed to handle a reset or abort request. - * Display a message and return. - */ - boardp = ASC_BOARDP(shp); - if (asc_rmqueue(&boardp->active, scp) == ASC_FALSE) { - ASC_PRINT2("asc_isr_callback: board %d: scp %x not on active queue\n", - boardp->id, (unsigned) scp); - return; - } + /* 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); +#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) + kfree(boardp->prtbuf); +#endif /* version >= v1.3.0 */ + scsi_unregister(shp); + asc_board_count--; + continue; + } + AscEnableIsaDma(shp->dma_channel); + } + } - /* - * 'qdonep' contains the command's ending status. - */ - switch (qdonep->d3.done_stat) { - case QD_NO_ERROR: - ASC_DBG(2, "asc_isr_callback: QD_NO_ERROR\n"); - switch (qdonep->d3.host_stat) { - case QHSTA_NO_ERROR: - scp->result = 0; - break; - default: - /* QHSTA error occurred */ - scp->result = HOST_BYTE(DID_ERROR); - break; - } - break; + /* 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) +#else /* version >= v1.3.70 */ + if ((ret = request_irq(shp->irq, advansys_interrupt, + SA_INTERRUPT | (share_irq == TRUE ? SA_SHIRQ : 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); + } +#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) + kfree(boardp->prtbuf); +#endif /* version >= v1.3.0 */ + scsi_unregister(shp); + asc_board_count--; + continue; + } - case QD_WITH_ERROR: - ASC_DBG(2, "asc_isr_callback: QD_WITH_ERROR\n"); - switch (qdonep->d3.host_stat) { - case QHSTA_NO_ERROR: - if (qdonep->d3.scsi_stat == SS_CHK_CONDITION) { - ASC_DBG(2, "asc_isr_callback: SS_CHK_CONDITION\n"); - ASC_DBG_PRT_SENSE(2, scp->sense_buffer, - sizeof(scp->sense_buffer)); + /* + * Initialize board RISC chip and enable interrupts. + */ + 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 */ /* - * 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. + * Allocate up to 'max_host_qng' request structures for + * the Wide board. */ - scp->result = DRIVER_BYTE(DRIVER_SENSE) | - STATUS_BYTE(qdonep->d3.scsi_stat); - } else { - scp->result = STATUS_BYTE(qdonep->d3.scsi_stat); - } - break; + for (req_cnt = adv_dvc_varp->max_host_qng; + req_cnt > 0; req_cnt--) { - default: - /* QHSTA error occurred */ - ASC_DBG1(2, "asc_isr_callback: host_stat %x\n", - qdonep->d3.host_stat); - scp->result = HOST_BYTE(DID_ERROR) | MSG_BYTE(qdonep->d3.scsi_msg) | - STATUS_BYTE(qdonep->d3.scsi_stat); - break; - } - break; + reqp = (adv_req_t *) + kmalloc(sizeof(adv_req_t) * req_cnt, GFP_ATOMIC); - case QD_ABORTED_BY_HOST: - ASC_DBG(1, "asc_isr_callback: QD_ABORTED_BY_HOST\n"); - scp->result = HOST_BYTE(DID_ABORT) | MSG_BYTE(qdonep->d3.scsi_msg) | - STATUS_BYTE(qdonep->d3.scsi_stat); - break; + ASC_DBG3(1, + "advansys_detect: reqp %x, req_cnt %d, bytes %d\n", + (unsigned) reqp, req_cnt, sizeof(adv_req_t) * req_cnt); - default: - ASC_PRINT1("asc_isr_callback: done_stat %x\n", qdonep->d3.done_stat); - scp->result = HOST_BYTE(DID_ERROR) | MSG_BYTE(qdonep->d3.scsi_msg) | - STATUS_BYTE(qdonep->d3.scsi_stat); - break; - } + if (reqp != NULL) { + break; + } + } - /* - * 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); + /* + * 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--) { - return; -} + sgp = (adv_sgblk_t *) + kmalloc(sizeof(adv_sgblk_t) * sg_cnt, GFP_ATOMIC); -/* - * asc_init_dev() - * - * Perform one-time initialization of a device. - */ -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_DBG3(1, + "advansys_detect: sgp %x, sg_cnt %d, bytes %d\n", + (unsigned) sgp, sg_cnt, sizeof(adv_sgblk_t) * sg_cnt); - ASC_DBG1(1, "asc_init_dev: target %d\n", (unsigned) scp->target); + if (sgp != NULL) { + break; + } + } +#endif /* version >= v1.3.0 */ - /* The host's target id is set in init_tidmask during initialization. */ - ASC_ASSERT(asc_dvc_varp->cfg->chip_scsi_id != scp->target); + /* + * 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; - boardp = ASC_BOARDP(scp->host); + /* + * 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]; - /* 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)); + /* + * Save original pointer for kfree() in case the + * driver is built as a module and can be unloaded. + */ + boardp->orig_sgblkp = sgp; - /* - * 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(). - */ - save_use_tagged_qng = asc_dvc_varp->use_tagged_qng; - save_can_tagged_qng = asc_dvc_varp->cfg->can_tagged_qng; + /* + * 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, "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; - } + ASC_DBG(2, "advansys_detect: AdvInitAsc3550Driver()\n"); + warn_code = AdvInitAsc3550Driver(adv_dvc_varp); + err_code = adv_dvc_varp->err_code; - 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); + 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); + } + } + } - 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 (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); + } +#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) + kfree(boardp->prtbuf); +#endif /* version >= v1.3.0 */ +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,70) + free_irq(shp->irq); +#else /* version >= v1.3.70 */ + free_irq(shp->irq, boardp); +#endif /* version >= v1.3.70 */ + scsi_unregister(shp); + asc_board_count--; + continue; + } + ASC_DBG_PRT_SCSI_HOST(2, shp); } -#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; } - - /* 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_DBG1(1, "asc_init_dev: found %d\n", found); - - return found; + ASC_DBG1(1, "advansys_detect: done: asc_board_count %d\n", asc_board_count); + return asc_board_count; } /* - * Search for an AdvanSys PCI device in the PCI configuration space. + * advansys_release() + * + * Release resources allocated for a single AdvanSys adapter. */ -ASC_INITFUNC( -STATIC int -asc_srch_pci_dev(PCI_DEVICE *pciDevice) -) +int +advansys_release(struct Scsi_Host *shp) { - int ret; - - ASC_DBG(2, "asc_srch_pci_dev: begin\n"); + asc_board_t *boardp; - if (pci_scan_method == -1) { - pci_scan_method = asc_scan_method(); + ASC_DBG(1, "advansys_release: begin\n"); + boardp = ASC_BOARDP(shp); +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,70) + free_irq(shp->irq); +#else /* version >= v1.3.70 */ + free_irq(shp->irq, boardp); +#endif /* version >= v1.3.70 */ + if (shp->dma_channel != NO_ISA_DMA) { + ASC_DBG(1, "advansys_release: free_dma()\n"); + free_dma(shp->dma_channel); } - pciDevice->type = pci_scan_method; - ASC_DBG1(2, "asc_srch_pci_dev: type %d\n", pciDevice->type); - - ret = asc_pci_find_dev(pciDevice); - ASC_DBG1(2, "asc_srch_pci_dev: asc_pci_find_dev() return %d\n", ret); - if (ret == PCI_DEVICE_FOUND) { - pciDevice->slotNumber = pciDevice->slotFound + 1; - pciDevice->startSlot = pciDevice->slotFound + 1; - } else { - if (pciDevice->bridge > pciDevice->busNumber) { - ASC_DBG2(2, "asc_srch_pci_dev: bridge %x, busNumber %x\n", - pciDevice->bridge, pciDevice->busNumber); - pciDevice->busNumber++; - pciDevice->slotNumber = 0; - pciDevice->startSlot = 0; - pciDevice->endSlot = 0x0f; - ret = asc_srch_pci_dev(pciDevice); - ASC_DBG1(2, "asc_srch_pci_dev: recursive call return %d\n", ret); + 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; } } - ASC_DBG1(2, "asc_srch_pci_dev: return %d\n", ret); - return ret; +#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) + ASC_ASSERT(boardp->prtbuf != NULL); + kfree(boardp->prtbuf); +#endif /* version >= v1.3.0 */ + scsi_unregister(shp); + ASC_DBG(1, "advansys_release: end\n"); + return 0; } /* - * Determine the access method to be used for 'pciDevice'. + * advansys_info() + * + * Return suitable for printing on the console with the argument + * adapter's configuration information. + * + * Note: The information line should not exceed ASC_INFO_SIZE bytes, + * otherwise the static 'info' array will be overrun. */ -ASC_INITFUNC( -STATIC uchar -asc_scan_method(void) -) +const char * +advansys_info(struct Scsi_Host *shp) { - ushort data; - PCI_DATA pciData; - uchar type; - uchar slot; + static char info[ASC_INFO_SIZE]; + asc_board_t *boardp; + ASC_DVC_VAR *asc_dvc_varp; + ADV_DVC_VAR *adv_dvc_varp; + char *busname; - ASC_DBG(2, "asc_scan_method: begin\n"); - memset(&pciData, 0, sizeof(pciData)); - for (type = 1; type < 3; type++) { - pciData.type = type; - for (slot = 0; slot < PCI_MAX_SLOT; slot++) { - pciData.slot = slot; - data = asc_get_cfg_word(&pciData); - if ((data != 0xFFFF) && (data != 0x0000)) { - ASC_DBG2(4, "asc_scan_method: data %x, type %d\n", data, type); - return (type); + boardp = ASC_BOARDP(shp); + 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 { + 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); + } + } 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 { + sprintf(info, +"AdvanSys SCSI %s: PCI Ultra-Wide: IO %X/%X, IRQ %u", + ASC_VERSION, + (unsigned) boardp->ioport, + (ADV_CONDOR_IOLEN - 1), + shp->irq); } } - ASC_DBG1(4, "asc_scan_method: type %d\n", type); - return (type); + ASC_ASSERT(strlen(info) < ASC_INFO_SIZE); + ASC_DBG(1, "advansys_info: end\n"); + return info; } /* - * Check for an AdvanSys PCI device in 'pciDevice'. + * advansys_command() - polled I/O entrypoint. * - * Return PCI_DEVICE_FOUND if found, otherwise return PCI_DEVICE_NOT_FOUND. - */ -ASC_INITFUNC( -STATIC int -asc_pci_find_dev(PCI_DEVICE *pciDevice) -) -{ - PCI_DATA pciData; - ushort vendorid, deviceid; - uchar classcode, subclass; - uchar lslot; - - ASC_DBG(3, "asc_pci_find_dev: begin\n"); - pciData.type = pciDevice->type; - pciData.bus = pciDevice->busNumber; - pciData.func = pciDevice->devFunc; - lslot = pciDevice->startSlot; - for (; lslot < pciDevice->endSlot; lslot++) { - pciData.slot = lslot; - pciData.offset = VENDORID_OFFSET; - vendorid = asc_get_cfg_word(&pciData); - ASC_DBG1(3, "asc_pci_find_dev: vendorid %x\n", vendorid); - if (vendorid != 0xffff) { - pciData.offset = DEVICEID_OFFSET; - deviceid = asc_get_cfg_word(&pciData); - ASC_DBG1(3, "asc_pci_find_dev: deviceid %x\n", deviceid); - if ((vendorid == ASC_PCI_VENDORID) && - ((deviceid == ASC_PCI_DEVICE_ID_1100) || - (deviceid == ASC_PCI_DEVICE_ID_1200) || - (deviceid == ASC_PCI_DEVICE_ID_1300))) { - pciDevice->slotFound = lslot; - ASC_DBG(3, "asc_pci_find_dev: PCI_DEVICE_FOUND\n"); - return PCI_DEVICE_FOUND; - } else { - pciData.offset = SUBCLASS_OFFSET; - subclass = asc_get_cfg_byte(&pciData); - pciData.offset = CLASSCODE_OFFSET; - classcode = asc_get_cfg_byte(&pciData); - if ((classcode & PCI_BASE_CLASS_BRIDGE_DEVICE) && - (subclass & PCI_SUB_CLASS_PCI_TO_PCI_BRIDGE_CONTROLLER)) { - pciDevice->bridge++; - } - ASC_DBG2(3, "asc_pci_find_dev: subclass %x, classcode %x\n", - subclass, classcode); - } - } - } - return PCI_DEVICE_NOT_FOUND; -} - -/* - * Read PCI configuration data into 'pciConfig'. + * 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(), + * currently handles all requests. */ -ASC_INITFUNC( -STATIC void -asc_get_pci_cfg(PCI_DEVICE *pciDevice, PCI_CONFIG_SPACE *pciConfig) -) +int +advansys_command(Scsi_Cmnd *scp) { - PCI_DATA pciData; - uchar counter; - uchar *localConfig; - - ASC_DBG1(4, "asc_get_pci_cfg: slot found - %d\n ", - pciDevice->slotFound); - - pciData.type = pciDevice->type; - pciData.bus = pciDevice->busNumber; - pciData.slot = pciDevice->slotFound; - pciData.func = pciDevice->devFunc; - localConfig = (uchar *) pciConfig; - - for (counter = 0; counter < sizeof(PCI_CONFIG_SPACE); counter++) { - pciData.offset = counter; - *localConfig = asc_get_cfg_byte(&pciData); - ASC_DBG1(4, "asc_get_pci_cfg: byte %x\n", *localConfig); - localConfig++; + ASC_DBG1(1, "advansys_command: scp %x\n", (unsigned) scp); + ASC_STATS(scp->host, command); + scp->SCp.Status = 0; /* Set to a known state */ + advansys_queuecommand(scp, advansys_command_done); + while (scp->SCp.Status == 0) { + continue; } - ASC_DBG1(4, "asc_get_pci_cfg: counter %d\n", counter); + ASC_DBG1(1, "advansys_command: result %x\n", scp->result); + return scp->result; } /* - * Read a word (16 bits) from the PCI configuration space. + * advansys_queuecommand() - interrupt-driven I/O entrypoint. * - * The configuration mechanism is checked for the correct access method. + * This function always returns 0. Command return status is saved + * in the 'scp' result field. */ -ASC_INITFUNC( -STATIC ushort -asc_get_cfg_word(PCI_DATA *pciData) -) +int +advansys_queuecommand(Scsi_Cmnd *scp, void (*done)(Scsi_Cmnd *)) { - ushort tmp; - ulong address; - ulong lbus = pciData->bus; - ulong lslot = pciData->slot; - ulong lfunc = pciData->func; - uchar t2CFA, t2CF8; - ulong t1CF8, t1CFC; + struct Scsi_Host *shp; + asc_board_t *boardp; + int flags; + Scsi_Cmnd *done_scp; - ASC_DBG4(4, "asc_get_cfg_word: type %d, bus %lu, slot %lu, func %lu\n", - pciData->type, lbus, lslot, lfunc); + shp = scp->host; + boardp = ASC_BOARDP(shp); + ASC_STATS(shp, queuecommand); /* - * Check type of configuration mechanism. + * Disable interrupts to preserve request ordering and provide + * mutually exclusive access to global structures used to initiate + * a request. */ - if (pciData->type == 2) { - /* - * Save registers to be restored later. - */ - t2CFA = inp(0xCFA); /* save PCI bus register */ - t2CF8 = inp(0xCF8); /* save config space enable register */ - - /* - * Write the bus and enable registers. - */ - /* set for type 1 cycle, if needed */ - outp(0xCFA, pciData->bus); - /* set the function number */ - outp(0xCF8, 0x10 | (pciData->func << 1)) ; - - /* - * Read the configuration space type 2 locations. - */ - tmp = (ushort) inpw(0xC000 | ((pciData->slot << 8) + pciData->offset)); - - outp(0xCFA, t2CFA); /* save PCI bus register */ - outp(0xCF8, t2CF8); /* save config space enable register */ - } else { - /* - * Type 1 or 3 configuration mechanism. - * - * Save the CONFIG_ADDRESS and CONFIG_DATA register values. - */ - t1CF8 = inpl(0xCF8); - t1CFC = inpl(0xCFC); + save_flags(flags); + cli(); - /* - * enable <31>, bus = <23:16>, slot = <15:11>, - * func = <10:8>, reg = <7:2> - */ - address = (ulong) ((lbus << 16) | (lslot << 11) | - (lfunc << 8) | (pciData->offset & 0xFC) | 0x80000000L); + /* + * Block new commands while handling a reset or abort request. + */ + if (boardp->flags & (ASC_HOST_IN_RESET | ASC_HOST_IN_ABORT)) { + if (boardp->flags & ASC_HOST_IN_RESET) { + ASC_DBG1(1, + "advansys_queuecommand: scp %x blocked for reset request\n", + (unsigned) scp); + scp->result = HOST_BYTE(DID_RESET); + } else { + ASC_DBG1(1, + "advansys_queuecommand: scp %x blocked for abort request\n", + (unsigned) scp); + scp->result = HOST_BYTE(DID_ABORT); + } /* - * Write out the address to CONFIG_ADDRESS. + * Add blocked requests to the board's 'done' queue. The queued + * requests will be completed at the end of the abort or reset + * handling. */ - outpl(0xCF8, address); + asc_enqueue(&boardp->done, scp, ASC_BACK); + restore_flags(flags); + return 0; + } - /* - * Read in word from CONFIG_DATA. - */ - tmp = (ushort) ((inpl(0xCFC) >> - ((pciData->offset & 2) * 8)) & 0xFFFF); + /* + * Attempt to execute any waiting commands for the board. + */ + if (!ASC_QUEUE_EMPTY(&boardp->waiting)) { + ASC_DBG(1, + "advansys_queuecommand: before asc_execute_queue() waiting\n"); + asc_execute_queue(&boardp->waiting); + } - /* - * Restore registers. - */ - outpl(0xCF8, t1CF8); - outpl(0xCFC, t1CFC); + /* + * Save the function pointer to Linux mid-level 'done' function + * and attempt to execute the command. + * + * If ASC_ERROR is returned the request has been added to the + * board's 'active' queue and will be completed by the interrupt + * handler. + * + * If ASC_BUSY is returned add the request to the board's per + * target waiting list. + * + * If an error occurred, the request will have been placed on the + * board's 'done' queue and must be completed before returning. + */ + scp->scsi_done = done; + switch (asc_execute_scsi_cmnd(scp)) { + case ASC_NOERROR: + break; + case ASC_BUSY: + asc_enqueue(&boardp->waiting, scp, ASC_BACK); + break; + case ASC_ERROR: + default: + done_scp = asc_dequeue_list(&boardp->done, NULL, ASC_TID_ALL); + /* Interrupts could be enabled here. */ + asc_scsi_done_list(done_scp); + break; } - ASC_DBG1(4, "asc_get_cfg_word: config data: %x\n", tmp); - return tmp; + + restore_flags(flags); + return 0; } /* - * Reads a byte from the PCI configuration space. + * advansys_abort() * - * The configuration mechanism is checked for the correct access method. + * Abort the command specified by 'scp'. */ -ASC_INITFUNC( -STATIC uchar -asc_get_cfg_byte(PCI_DATA *pciData) -) +int +advansys_abort(Scsi_Cmnd *scp) { - uchar tmp; - ulong address; - ulong lbus = pciData->bus, lslot = pciData->slot, lfunc = pciData->func; - uchar t2CFA, t2CF8; - ulong t1CF8, t1CFC; - - ASC_DBG1(4, "asc_get_cfg_byte: type: %d\n", pciData->type); + 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; + Scsi_Cmnd *done_scp = NULL; + int ret; - /* - * Check type of configuration mechanism. - */ - if (pciData->type == 2) { - /* - * Save registers to be restored later. - */ - t2CFA = inp(0xCFA); /* save PCI bus register */ - t2CF8 = inp(0xCF8); /* save config space enable register */ + /* Save current flags and disable interrupts. */ + save_flags(flags); + cli(); - /* - * Write the bus and enable registers. - */ - /* set for type 1 cycle, if needed */ - outp(0xCFA, pciData->bus); - /* set the function number */ - outp(0xCF8, 0x10 | (pciData->func << 1)); + ASC_DBG1(1, "advansys_abort: scp %x\n", (unsigned) scp); - /* - * Read configuration space type 2 locations. - */ - tmp = inp(0xC000 | ((pciData->slot << 8) + pciData->offset)); +#ifdef ADVANSYS_STATS + if (scp->host != NULL) { + ASC_STATS(scp->host, abort); + } +#endif /* ADVANSYS_STATS */ - /* - * Restore registers. - */ - outp(0xCF8, t2CF8); /* restore the enable register */ - outp(0xCFA, t2CFA); /* restore PCI bus register */ +#ifdef ADVANSYS_ASSERT + do_scsi_done = ASC_ERROR; + scp_found = ASC_ERROR; + ret = ASC_ERROR; +#endif /* ADVANSYS_ASSERT */ + +#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) + if (scp->serial_number != scp->serial_number_at_timeout) { + ASC_PRINT1( +"advansys_abort: timeout serial number changed for request %x\n", + (unsigned) scp); + do_scsi_done = ASC_FALSE; + scp_found = ASC_FALSE; + ret = SCSI_ABORT_NOT_RUNNING; + } else +#endif /* version >= v1.3.89 */ + if ((shp = scp->host) == NULL) { + scp->result = HOST_BYTE(DID_ERROR); + do_scsi_done = ASC_TRUE; + scp_found = ASC_FALSE; + ret = SCSI_ABORT_ERROR; + } else if ((boardp = ASC_BOARDP(shp))->flags & + (ASC_HOST_IN_RESET | ASC_HOST_IN_ABORT)) { + ASC_PRINT2( +"advansys_abort: board %d: Nested host reset or abort, flags 0x%x\n", + boardp->id, boardp->flags); + do_scsi_done = ASC_TRUE; + if ((asc_rmqueue(&boardp->active, scp) == ASC_TRUE) || + (asc_rmqueue(&boardp->waiting, scp) == ASC_TRUE)) { + scp_found = ASC_TRUE; + } else { + scp_found = ASC_FALSE; + } + scp->result = HOST_BYTE(DID_ERROR); + ret = SCSI_ABORT_ERROR; } else { - /* - * Type 1 or 3 configuration mechanism. - * - * Save CONFIG_ADDRESS and CONFIG_DATA register values. - */ - t1CF8 = inpl(0xCF8); - t1CFC = inpl(0xCFC); + /* Set abort flag to avoid nested reset or abort requests. */ + boardp->flags |= ASC_HOST_IN_ABORT; - /* - * enable <31>, bus = <23:16>, slot = <15:11>, func = <10:8>, - * reg = <7:2> - */ - address = (ulong) ((lbus << 16) | (lslot << 11) | - (lfunc << 8) | (pciData->offset & 0xFC) | 0x80000000L); + do_scsi_done = ASC_TRUE; + if (asc_rmqueue(&boardp->waiting, scp) == ASC_TRUE) { + /* + * 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; + scp->result = HOST_BYTE(DID_ABORT); + ret = SCSI_ABORT_SUCCESS; + } else if (asc_isqueued(&boardp->active, scp) == ASC_TRUE) { + /* + * If asc_isqueued() found the command on the active + * queue, it has been sent to the device. The command + * will be returned through the interrupt handler after + * it has been aborted. + */ - /* - * Write out address to CONFIG_ADDRESS. - */ - outpl(0xCF8, address); + if (ASC_NARROW_BOARD(boardp)) { + /* + * Narrow Board + */ + asc_dvc_varp = &boardp->dvc_var.asc_dvc_var; + scp->result = HOST_BYTE(DID_ABORT); - /* - * Read in word from CONFIG_DATA. - */ - tmp = (uchar) ((inpl(0xCFC) >> ((pciData->offset & 3) * 8)) & 0xFF); + 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); - /* - * Restore registers. - */ - outpl(0xCF8, t1CF8); - outpl(0xCFC, t1CFC); - } - ASC_DBG1(4, "asc_get_cfg_byte: config data: %x\n", tmp); - return tmp; -} + 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); + } -/* - * Write a byte to the PCI configuration space. - */ -ASC_INITFUNC( -STATIC void -asc_put_cfg_byte(PCI_DATA *pciData, uchar byte_data) -) -{ - ulong tmpl; - ulong address; - ulong lbus = pciData->bus, lslot = pciData->slot, lfunc = pciData->func; - uchar t2CFA, t2CF8; - ulong t1CF8, t1CFC; + /* + * The request will either still be on the active queue + * or have been added to the board's done queue. + */ + if (asc_rmqueue(&boardp->active, scp) == ASC_TRUE) { + scp->result = HOST_BYTE(DID_ABORT); + scp_found = ASC_TRUE; + } else { + scp_found = asc_rmqueue(&boardp->done, scp); + ASC_ASSERT(scp_found == ASC_TRUE); + } - ASC_DBG2(4, "asc_put_cfg_byte: type: %d, byte_data %x\n", - pciData->type, byte_data); + } else { + /* + * The command was not found on the active or waiting queues. + */ + do_scsi_done = ASC_TRUE; + scp_found = ASC_FALSE; + ret = SCSI_ABORT_NOT_RUNNING; + } - /* - * Check type of configuration mechanism. - */ - if (pciData->type == 2) { + /* Clear abort flag. */ + boardp->flags &= ~ASC_HOST_IN_ABORT; /* - * Save registers to be restored later. + * Because the ASC_HOST_IN_ABORT flag causes both + * 'advansys_interrupt' and 'asc_isr_callback' to + * queue requests to the board's 'done' queue and + * prevents waiting commands from being executed, + * these queued requests must be handled here. */ - t2CFA = inp(0xCFA); /* save PCI bus register */ - t2CF8 = inp(0xCF8); /* save config space enable register */ + done_scp = asc_dequeue_list(&boardp->done, NULL, ASC_TID_ALL); /* - * Write bus and enable registers. + * Start any waiting commands for the board. */ - outp(0xCFA, pciData->bus); + if (!ASC_QUEUE_EMPTY(&boardp->waiting)) { + ASC_DBG(1, "advansys_interrupt: before asc_execute_queue()\n"); + asc_execute_queue(&boardp->waiting); + } + } - /* - * Set the function number. - */ - outp(0xCF8, 0x10 | (pciData->func << 1)); + /* Interrupts could be enabled here. */ - /* - * Write the configuration space type 2 locations. - */ - outp(0xC000 | ((pciData->slot << 8) + pciData->offset), byte_data); + /* + * Complete the request to be aborted, unless it has been + * restarted as detected above, even if it was not found on + * the device active or waiting queues. + */ + ASC_ASSERT(do_scsi_done != ASC_ERROR); + ASC_ASSERT(scp_found != ASC_ERROR); + if (do_scsi_done == ASC_TRUE) { + if (scp->scsi_done == NULL) { + ASC_PRINT1( +"advansys_abort: aborted request scsi_done() is NULL, %x\n", + (unsigned) scp); + } else { + if (scp_found == ASC_FALSE) { + ASC_PRINT1( +"advansys_abort: abort request not active or waiting, completing anyway %x\n", + (unsigned) scp); + } + ASC_STATS(scp->host, done); + scp->scsi_done(scp); + } + } - /* - * Restore registers. - */ - outp(0xCF8, t2CF8); /* restore the enable register */ - outp(0xCFA, t2CFA); /* restore PCI bus register */ - } else { + /* + * It is possible for the request done function to re-enable + * interrupts without confusing the driver. But here interrupts + * aren't enabled until all requests have been completed. + */ + if (done_scp != NULL) { + asc_scsi_done_list(done_scp); + } - /* - * Type 1 or 3 configuration mechanism. - * - * Save the CONFIG_ADDRESS and CONFIG_DATA register values. - */ - t1CF8 = inpl(0xCF8); - t1CFC = inpl(0xCFC); + ASC_DBG1(1, "advansys_abort: ret %d\n", ret); - /* - * enable <31>, bus = <23:16>, slot = <15:11>, func = <10:8>, - * reg = <7:2> - */ - address = (ulong) ((lbus << 16) | (lslot << 11) | (lfunc << 8) | - (pciData->offset & 0xFC) | 0x80000000L); - /* - * Write out address to CONFIG_ADDRESS. - */ - outpl(0xCF8, address); - - /* - * Write double word to CONFIG_DATA preserving the bytes - * in the double not written. - */ - tmpl = inpl(0xCFC) & ~(0xFF << ((pciData->offset & 3) * 8)); - outpl(0xCFC, tmpl | (byte_data << ((pciData->offset & 3) * 8))); + /* Re-enable interrupts, if they were enabled on entry. */ + restore_flags(flags); - /* - * Restore registers. - */ - outpl(0xCF8, t1CF8); - outpl(0xCFC, t1CFC); - } - ASC_DBG(4, "asc_put_cfg_byte: end\n"); + ASC_ASSERT(ret != ASC_ERROR); + return ret; } /* - * Add a 'REQP' to the end of specified queue. Set 'tidmask' - * to indicate a command is queued for the device. - * - * 'flag' may be either ASC_FRONT or ASC_BACK. + * advansys_reset() * - * 'REQPNEXT(reqp)' returns reqp's next pointer. + * Reset the device associated with the command 'scp'. */ -STATIC void -asc_enqueue(asc_queue_t *ascq, REQP reqp, int flag) +int +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,89) +advansys_reset(Scsi_Cmnd *scp) +#else /* version >= v1.3.89 */ +advansys_reset(Scsi_Cmnd *scp, unsigned int reset_flags) +#endif /* version >= v1.3.89 */ { - int tid; + 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; + int do_scsi_done; + int scp_found; + int status; + int target; + int ret; + int device_reset = ASC_FALSE; - ASC_DBG3(2, "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); - if (flag == ASC_FRONT) { - REQPNEXT(reqp) = ascq->q_first[tid]; - ascq->q_first[tid] = reqp; - /* If the queue was empty, set the last pointer. */ - if (ascq->q_last[tid] == NULL) { - ascq->q_last[tid] = reqp; - } - } else { /* ASC_BACK */ - if (ascq->q_last[tid] != NULL) { - REQPNEXT(ascq->q_last[tid]) = reqp; - } - ascq->q_last[tid] = reqp; - REQPNEXT(reqp) = NULL; - /* If the queue was empty, set the first pointer. */ - if (ascq->q_first[tid] == NULL) { - ascq->q_first[tid] = reqp; - } - } - /* The queue has at least one entry, set its bit. */ - ascq->q_tidmask |= ASC_TIX_TO_TARGET_ID(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", - tid, ascq->q_max_cnt[tid]); - } - REQPTIME(reqp) = REQTIMESTAMP(); -#endif /* ADVANSYS_STATS */ - ASC_DBG1(1, "asc_enqueue: reqp %x\n", (unsigned) reqp); - return; -} + /* Save current flags and disable interrupts. */ + save_flags(flags); + cli(); -/* - * Return first queued 'REQP' on the specified queue for - * the specified target device. Clear the 'tidmask' bit for - * the device if no more commands are left queued for it. - * - * 'REQPNEXT(reqp)' returns reqp's next pointer. - */ -STATIC REQP -asc_dequeue(asc_queue_t *ascq, int tid) -{ - REQP reqp; + ASC_DBG1(1, "advansys_reset: %x\n", (unsigned) scp); - ASC_DBG2(1, "asc_dequeue: ascq %x, tid %d\n", (unsigned) ascq, tid); - ASC_ASSERT(interrupts_enabled() == ASC_FALSE); - ASC_ASSERT(tid >= 0 && tid <= ASC_MAX_TID); - if ((reqp = ascq->q_first[tid]) != NULL) { - ASC_ASSERT(ascq->q_tidmask & ASC_TIX_TO_TARGET_ID(tid)); - ascq->q_first[tid] = REQPNEXT(reqp); - /* If the queue is empty, clear its bit and the last pointer. */ - if (ascq->q_first[tid] == NULL) { - ascq->q_tidmask &= ~ASC_TIX_TO_TARGET_ID(tid); - ASC_ASSERT(ascq->q_last[tid] == reqp); - ascq->q_last[tid] = NULL; - } #ifdef ADVANSYS_STATS - /* Maintain request queue statistics. */ - ascq->q_cur_cnt[tid]--; - ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0); - REQTIMESTAT("asc_dequeue", ascq, reqp, tid); + if (scp->host != NULL) { + ASC_STATS(scp->host, reset); + } #endif /* ADVANSYS_STATS */ - } - ASC_DBG1(1, "asc_dequeue: reqp %x\n", (unsigned) reqp); - return reqp; -} - -/* - * Return a pointer to a singly linked list of all the requests queued - * for 'tid' on the 'asc_queue_t' pointed to by 'ascq'. - * - * If 'lastpp' is not NULL, '*lastpp' will be set to point to the - * the last request returned in the singly linked list. - * - * 'tid' should either be a valid target id or if it is ASC_TID_ALL, - * then all queued requests are concatenated into one list and - * returned. - * - * Note: If 'lastpp' is used to append a new list to the end of - * an old list, only change the old list last pointer if '*lastpp' - * (or the function return value) is not NULL, i.e. use a temporary - * variable for 'lastpp' and check its value after the function return - * before assigning it to the list last pointer. - * - * Unfortunately collecting queuing time statistics adds overhead to - * the function that isn't inherent to the function's algorithm. - */ -STATIC REQP -asc_dequeue_list(asc_queue_t *ascq, REQP *lastpp, int tid) -{ - REQP firstp, lastp; - int i; - - ASC_DBG2(1, "asc_dequeue_list: ascq %x, tid %d\n", (unsigned) ascq, tid); - ASC_ASSERT(interrupts_enabled() == ASC_FALSE); - ASC_ASSERT((tid == ASC_TID_ALL) || (tid >= 0 && tid <= ASC_MAX_TID)); - /* - * If 'tid' is not ASC_TID_ALL, return requests only for - * the specified 'tid'. If 'tid' is ASC_TID_ALL, return all - * requests for all tids. - */ - if (tid != ASC_TID_ALL) { - /* Return all requests for the specified 'tid'. */ - if ((ascq->q_tidmask & ASC_TIX_TO_TARGET_ID(tid)) == 0) { - /* List is empty; Set first and last return pointers to NULL. */ - firstp = lastp = NULL; +#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) + if ((reset_flags & SCSI_RESET_ASYNCHRONOUS) && + (scp->serial_number != scp->serial_number_at_timeout)) { + ASC_PRINT1( +"advansys_reset: timeout serial number changed for request %x\n", + (unsigned) scp); + do_scsi_done = ASC_FALSE; + scp_found = ASC_FALSE; + ret = SCSI_RESET_NOT_RUNNING; + } else +#endif /* version >= v1.3.89 */ + if ((shp = scp->host) == NULL) { + scp->result = HOST_BYTE(DID_ERROR); + do_scsi_done = ASC_TRUE; + scp_found = ASC_FALSE; + ret = SCSI_RESET_ERROR; + } else if ((boardp = ASC_BOARDP(shp))->flags & + (ASC_HOST_IN_RESET | ASC_HOST_IN_ABORT)) { + ASC_PRINT2( +"advansys_reset: board %d: Nested host reset or abort, flags 0x%x\n", + boardp->id, boardp->flags); + do_scsi_done = ASC_TRUE; + if ((asc_rmqueue(&boardp->active, scp) == ASC_TRUE) || + (asc_rmqueue(&boardp->waiting, scp) == ASC_TRUE)) { + scp_found = ASC_TRUE; } else { - firstp = ascq->q_first[tid]; - lastp = ascq->q_last[tid]; - ascq->q_first[tid] = ascq->q_last[tid] = NULL; - ascq->q_tidmask &= ~ASC_TIX_TO_TARGET_ID(tid); -#ifdef ADVANSYS_STATS - { - REQP reqp; - ascq->q_cur_cnt[tid] = 0; - for (reqp = firstp; reqp; reqp = REQPNEXT(reqp)) { - REQTIMESTAT("asc_dequeue_list", ascq, reqp, tid); - } - } -#endif /* ADVANSYS_STATS */ - } - } else { - /* Return all requests for all tids. */ - firstp = lastp = NULL; - for (i = 0; i <= ASC_MAX_TID; i++) { - if (ascq->q_tidmask & ASC_TIX_TO_TARGET_ID(i)) { - if (firstp == NULL) { - firstp = ascq->q_first[i]; - lastp = ascq->q_last[i]; - } else { - ASC_ASSERT(lastp != NULL); - REQPNEXT(lastp) = ascq->q_first[i]; - lastp = ascq->q_last[i]; - } - ascq->q_first[i] = ascq->q_last[i] = NULL; - ascq->q_tidmask &= ~ASC_TIX_TO_TARGET_ID(i); -#ifdef ADVANSYS_STATS - ascq->q_cur_cnt[i] = 0; -#endif /* ADVANSYS_STATS */ - } + scp_found = ASC_FALSE; } -#ifdef ADVANSYS_STATS - { - REQP reqp; - for (reqp = firstp; reqp; reqp = REQPNEXT(reqp)) { - REQTIMESTAT("asc_dequeue_list", ascq, reqp, reqp->target); - } + scp->result = HOST_BYTE(DID_ERROR); + ret = SCSI_RESET_ERROR; + } else if (jiffies >= boardp->last_reset && + jiffies < (boardp->last_reset + (10 * HZ))) { + /* + * Don't allow a reset to be attempted within 10 seconds + * of the last reset. + * + * If 'jiffies' wrapping occurs, the reset request will go + * through, because a wrapped 'jiffies' would not pass the + * test above. + */ + ASC_DBG(1, + "advansys_reset: reset within 10 sec of last reset ignored\n"); + do_scsi_done = ASC_TRUE; + if ((asc_rmqueue(&boardp->active, scp) == ASC_TRUE) || + (asc_rmqueue(&boardp->waiting, scp) == ASC_TRUE)) { + scp_found = ASC_TRUE; + } else { + scp_found = ASC_FALSE; } -#endif /* ADVANSYS_STATS */ - } - if (lastpp) { - *lastpp = lastp; - } - ASC_DBG1(1, "asc_dequeue_list: firstp %x\n", (unsigned) firstp); - return firstp; -} + scp->result = HOST_BYTE(DID_ERROR); + ret = SCSI_RESET_ERROR; + } else { + do_scsi_done = ASC_TRUE; -/* - * Remove the specified 'REQP' from the specified queue for - * the specified target device. Clear the 'tidmask' bit for the - * device if no more commands are left queued for it. - * - * 'REQPNEXT(reqp)' returns reqp's the next pointer. - * - * Return ASC_TRUE if the command was found and removed, - * otherwise return ASC_FALSE. - */ -STATIC int -asc_rmqueue(asc_queue_t *ascq, REQP reqp) -{ - REQP currp, prevp; - int tid; - int ret = ASC_FALSE; - - ASC_DBG2(1, "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); + /* Set reset flag to avoid nested reset or abort requests. */ + boardp->flags |= ASC_HOST_IN_RESET; - /* - * Handle the common case of 'reqp' being the first - * entry on the queue. - */ - if (reqp == ascq->q_first[tid]) { - ret = ASC_TRUE; - ascq->q_first[tid] = REQPNEXT(reqp); - /* If the queue is now empty, clear its bit and the last pointer. */ - if (ascq->q_first[tid] == NULL) { - ascq->q_tidmask &= ~ASC_TIX_TO_TARGET_ID(tid); - ASC_ASSERT(ascq->q_last[tid] == reqp); - ascq->q_last[tid] = NULL; - } - } else if (ascq->q_first[tid] != NULL) { - ASC_ASSERT(ascq->q_last[tid] != NULL); /* - * Because the case of 'reqp' being the first entry has been - * handled above and it is known the queue is not empty, if - * 'reqp' is found on the queue it is guaranteed the queue will - * not become empty and that 'q_first[tid]' will not be changed. - * - * Set 'prevp' to the first entry, 'currp' to the second entry, - * and search for 'reqp'. + * If the request is on the target waiting or active queue + * or the board done queue, then remove it and note that it + * was found. */ - for (prevp = ascq->q_first[tid], currp = REQPNEXT(prevp); - currp; prevp = currp, currp = REQPNEXT(currp)) { - if (currp == reqp) { - ret = ASC_TRUE; - REQPNEXT(prevp) = REQPNEXT(currp); - REQPNEXT(reqp) = NULL; - if (ascq->q_last[tid] == reqp) { - ascq->q_last[tid] = prevp; - } - break; - } + if (asc_rmqueue(&boardp->active, scp) == ASC_TRUE) { + ASC_DBG(1, "advansys_reset: active scp_found = TRUE\n"); + scp_found = ASC_TRUE; + } else if (asc_rmqueue(&boardp->waiting, scp) == ASC_TRUE) { + ASC_DBG(1, "advansys_reset: waiting scp_found = TRUE\n"); + scp_found = ASC_TRUE; + } else if (asc_rmqueue(&boardp->done, scp) == ASC_TRUE) { + scp_found = ASC_TRUE; + } else { + scp_found = ASC_FALSE; } - } -#ifdef ADVANSYS_STATS - /* Maintain request queue statistics. */ - if (ret == ASC_TRUE) { - ascq->q_cur_cnt[tid]--; - REQTIMESTAT("asc_rmqueue", ascq, reqp, tid); - } - ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0); -#endif /* ADVANSYS_STATS */ - ASC_DBG2(1, "asc_rmqueue: reqp %x, ret %d\n", (unsigned) reqp, ret); - return ret; -} -/* - * If the specified 'REQP' is queued on the specified queue for - * the specified target device, return ASC_TRUE. - */ -STATIC int -asc_isqueued(asc_queue_t *ascq, REQP reqp) -{ - REQP treqp; - int tid; - int ret = ASC_FALSE; - ASC_DBG2(1, "asc_isqueued: ascq %x, reqp %x\n", - (unsigned) ascq, (unsigned) reqp); - ASC_ASSERT(interrupts_enabled() == ASC_FALSE); - ASC_ASSERT(reqp != NULL); + if (ASC_NARROW_BOARD(boardp)) { + /* + * Narrow Board + * + * If the suggest reset bus flags are set, then reset the bus. + * Otherwise only reset the device. + */ + asc_dvc_varp = &boardp->dvc_var.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 */ - tid = REQPTID(reqp); - ASC_ASSERT(tid >= 0 && tid <= ASC_MAX_TID); + /* + * 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() success\n"); + ret = SCSI_RESET_SUCCESS; + break; + case ASC_ERROR: + default: + ASC_DBG(1, "advansys_reset: AscResetSB() failed\n"); + ret = SCSI_RESET_ERROR; + break; + } - for (treqp = ascq->q_first[tid]; treqp; treqp = REQPNEXT(treqp)) { - ASC_ASSERT(ascq->q_tidmask & ASC_TIX_TO_TARGET_ID(tid)); - if (treqp == reqp) { - ret = ASC_TRUE; - break; - } - } - ASC_DBG1(1, "asc_isqueued: ret %x\n", ret); - return ret; -} +#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. + */ -/* - * Execute as many queued requests as possible for the specified queue. - * - * Calls asc_execute_scsi_cmnd() to execute a REQP/Scsi_Cmnd. - */ -STATIC void -asc_execute_queue(asc_queue_t *ascq) -{ - ASC_SCSI_BIT_ID_TYPE scan_tidmask; - REQP reqp; - int i; + 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(); - ASC_DBG1(1, "asc_execute_queue: ascq %x\n", (unsigned) ascq); - ASC_ASSERT(interrupts_enabled() == ASC_FALSE); - /* - * Execute queued commands for devices attached to - * the current board in round-robin fashion. - */ - scan_tidmask = ascq->q_tidmask; - do { - for (i = 0; i <= ASC_MAX_TID; i++) { - if (scan_tidmask & ASC_TIX_TO_TARGET_ID(i)) { - if ((reqp = asc_dequeue(ascq, i)) == NULL) { - scan_tidmask &= ~ASC_TIX_TO_TARGET_ID(i); - } else if (asc_execute_scsi_cmnd((Scsi_Cmnd *) reqp) - == ASC_BUSY) { - scan_tidmask &= ~ASC_TIX_TO_TARGET_ID(i); - /* Put the request back at front of the list. */ - asc_enqueue(ascq, reqp, ASC_FRONT); + /* + * 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; } } - } - } while (scan_tidmask); - return; -} +#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 */ -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) -/* - * asc_prt_board_devices() - * - * Print driver information for devices attached to the board. - * - * 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_board_devices(struct Scsi_Host *shp, char *cp, int cplen) -{ - asc_board_t *boardp; - int leftlen; - int totlen; - int len; - int i; + /* + * 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. + */ - boardp = ASC_BOARDP(shp); - leftlen = cplen; - totlen = len = 0; + 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 */ + } - len = asc_prt_line(cp, leftlen, -"\nDevice Information for AdvanSys SCSI Host %d:\n", shp->host_no); - ASC_PRT_NEXT(); + /* + * Because the ASC_HOST_IN_RESET flag causes both + * 'advansys_interrupt' and 'asc_isr_callback' to + * queue requests to the board's 'done' queue and + * prevents waiting commands from being executed, + * these queued requests must be handled here. + */ + done_scp = asc_dequeue_list(&boardp->done, &last_scp, + ASC_TID_ALL); - 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); - ASC_PRT_NEXT(); + /* + * If a device reset was performed dequeue all waiting + * and active requests for the device and set the request + * status to DID_RESET. + * + * If a SCSI bus reset was performed dequeue all waiting + * and active requests for all devices and set the request + * status to DID_RESET. + */ + if (device_reset == ASC_TRUE) { + target = scp->target; + } else { + target = ASC_TID_ALL; } - } - len = asc_prt_line(cp, leftlen, " (%d=Host Adapter)\n", - boardp->asc_dvc_cfg.chip_scsi_id); - ASC_PRT_NEXT(); - return totlen; -} + /* + * Add active requests to 'done_scp' and set the request status + * to DID_RESET. + */ + if (done_scp == NULL) { + done_scp = asc_dequeue_list(&boardp->active, &last_scp, target); + for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) { + tscp->result = HOST_BYTE(DID_RESET); + } + } else { + ASC_ASSERT(last_scp != NULL); + REQPNEXT(last_scp) = asc_dequeue_list(&boardp->active, + &new_last_scp, target); + if (new_last_scp != NULL) { + ASC_ASSERT(REQPNEXT(last_scp) != NULL); + for (tscp = REQPNEXT(last_scp); tscp; tscp = REQPNEXT(tscp)) { + tscp->result = HOST_BYTE(DID_RESET); + } + last_scp = new_last_scp; + } + } -/* - * asc_prt_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_board_eeprom(struct Scsi_Host *shp, char *cp, int cplen) -{ - asc_board_t *boardp; - ASC_DVC_VAR *asc_dvc_varp; - int leftlen; - int totlen; - int len; - ASCEEP_CONFIG *ep; - int i; - int isa_dma_speed[] = { 10, 8, 7, 6, 5, 4, 3, 2 }; + /* + * Add waiting requests to 'done_scp' and set the request status + * to DID_RESET. + */ + if (done_scp == NULL) { + done_scp = asc_dequeue_list(&boardp->waiting, &last_scp, target); + for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) { + tscp->result = HOST_BYTE(DID_RESET); + } + } else { + ASC_ASSERT(last_scp != NULL); + REQPNEXT(last_scp) = asc_dequeue_list(&boardp->waiting, + &new_last_scp, target); + if (new_last_scp != NULL) { + ASC_ASSERT(REQPNEXT(last_scp) != NULL); + for (tscp = REQPNEXT(last_scp); tscp; tscp = REQPNEXT(tscp)) { + tscp->result = HOST_BYTE(DID_RESET); + } + last_scp = new_last_scp; + } + } - boardp = ASC_BOARDP(shp); - asc_dvc_varp = &boardp->asc_dvc_var; - ep = &boardp->eep_config; + /* Save the time of the most recently completed reset. */ + boardp->last_reset = jiffies; - leftlen = cplen; - totlen = len = 0; + /* Clear reset flag. */ + boardp->flags &= ~ASC_HOST_IN_RESET; - len = asc_prt_line(cp, leftlen, -"\nEEPROM Settings for AdvanSys SCSI Host %d:\n", shp->host_no); - ASC_PRT_NEXT(); + /* + * Start any waiting commands for the board. + */ + if (!ASC_QUEUE_EMPTY(&boardp->waiting)) { + ASC_DBG(1, "advansys_interrupt: before asc_execute_queue()\n"); + asc_execute_queue(&boardp->waiting); + } + ret = SCSI_RESET_SUCCESS; + } - 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(); + /* Interrupts could be enabled here. */ - len = asc_prt_line(cp, leftlen, -" Disconnects: "); - 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'); - ASC_PRT_NEXT(); + ASC_ASSERT(do_scsi_done != ASC_ERROR); + ASC_ASSERT(scp_found != ASC_ERROR); + if (do_scsi_done == ASC_TRUE) { + if (scp->scsi_done == NULL) { + ASC_PRINT1( +"advansys_reset: reset request scsi_done() is NULL, %x\n", + (unsigned) scp); + } else { + if (scp_found == ASC_FALSE) { + ASC_PRINT1( +"advansys_reset: reset request not active or waiting, completing anyway %x\n", + (unsigned) scp); + } + ASC_STATS(scp->host, done); + scp->scsi_done(scp); + } } - 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 <= 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'); - ASC_PRT_NEXT(); + /* + * It is possible for the request done function to re-enable + * interrupts without confusing the driver. But here interrupts + * aren't enabled until requests have been completed. + */ + if (done_scp != NULL) { + asc_scsi_done_list(done_scp); } - 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 <= ASC_MAX_TID; i++) { - len = asc_prt_line(cp, leftlen, " %d:%c", - i, (ep->start_motor & ASC_TIX_TO_TARGET_ID(i)) ? 'Y' : 'N'); - ASC_PRT_NEXT(); - } - len = asc_prt_line(cp, leftlen, "\n"); - ASC_PRT_NEXT(); + ASC_DBG1(1, "advansys_reset: ret %d", ret); - len = asc_prt_line(cp, leftlen, -" 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'); - ASC_PRT_NEXT(); - } - len = asc_prt_line(cp, leftlen, "\n"); - ASC_PRT_NEXT(); + /* Re-enable interrupts, if they were enabled on entry. */ + restore_flags(flags); - if (asc_dvc_varp->bus_type & ASC_IS_ISA) { - len = asc_prt_line(cp, leftlen, -" Host ISA DMA speed: %d MB/S\n", - isa_dma_speed[ep->isa_dma_speed]); - ASC_PRT_NEXT(); - } + ASC_ASSERT(ret != ASC_ERROR); + return ret; +} - return totlen; +/* + * advansys_biosparam() + * + * Translate disk drive geometry if the "BIOS greater than 1 GB" + * support is enabled for a drive. + * + * ip (information pointer) is an int array with the following definition: + * ip[0]: heads + * ip[1]: sectors + * ip[2]: cylinders + */ +int +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0) +advansys_biosparam(Disk *dp, int dep, int ip[]) +#else /* version >= v1.3.0 */ +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); + 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 { + 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"); + return 0; } /* - * asc_prt_driver_conf() + * advansys_setup() * - * Note: no single line should be greater than ASC_PRTLINE_SIZE, - * cf. asc_prt_line(). + * This function is called from init/main.c at boot time. + * It it passed LILO parameters that can be set from the + * LILO command line or in /etc/lilo.conf. * - * Return the number of characters copied into 'cp'. No more than - * 'cplen' characters will be copied to 'cp'. + * It is used by the AdvanSys driver to either disable I/O + * port scanning or to limit scanning to 1 - 4 I/O ports. + * Regardless of the option setting EISA and PCI boards + * will still be searched for and detected. This option + * 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_IOPORT_PROBE + 1) I/O Port. + * + * Examples: + * 1. Eliminate I/O port scanning: + * boot: linux advansys= + * or + * boot: linux advansys=0x0 + * 2. Limit I/O port scanning to one I/O port: + * boot: linux advansys=0x110 + * 3. Limit I/O port scanning to four I/O ports: + * boot: linux advansys=0x110,0x210,0x230,0x330 + * 4. If ADVANSYS_DEBUG, limit I/O port scanning to four I/O ports and + * set the driver debug level to 2. + * boot: linux advansys=0x110,0x210,0x230,0x330,0xdeb2 + * + * ints[0] - number of arguments + * ints[1] - first argument + * ints[2] - second argument + * ... */ -STATIC int -asc_prt_driver_conf(struct Scsi_Host *shp, char *cp, int cplen) +ASC_INITFUNC( +void +advansys_setup(char *str, int *ints) +) { - asc_board_t *boardp; - int leftlen; - int totlen; - int len; -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) - int i; -#endif /* version >= v1.3.89 */ + int i; - boardp = ASC_BOARDP(shp); + if (asc_iopflag == ASC_TRUE) { + printk("AdvanSys SCSI: 'advansys' LILO option may appear only once\n"); + return; + } - leftlen = cplen; - totlen = len = 0; + asc_iopflag = ASC_TRUE; - len = asc_prt_line(cp, leftlen, -"\nLinux Driver Configuration and Information for AdvanSys SCSI Host %d:\n", - shp->host_no); - ASC_PRT_NEXT(); + if (ints[0] > ASC_NUM_IOPORT_PROBE) { +#ifdef ADVANSYS_DEBUG + 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_IOPORT_PROBE); +#ifdef ADVANSYS_DEBUG + } +#endif /* ADVANSYS_DEBUG */ + } - len = asc_prt_line(cp, leftlen, -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,89) -" host_busy %u, last_reset %u, max_id %u, max_lun %u\n", - shp->host_busy, shp->last_reset, shp->max_id, shp->max_lun); -#else /* version >= v1.3.89 */ -" host_busy %u, last_reset %u, max_id %u, max_lun %u, max_channel %u\n", - shp->host_busy, shp->last_reset, shp->max_id, shp->max_lun, - shp->max_channel); -#endif /* version >= v1.3.89 */ - ASC_PRT_NEXT(); - - len = asc_prt_line(cp, leftlen, -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,57) -" can_queue %d, this_id %d, sg_tablesize %u, cmd_per_lun %u\n", - shp->can_queue, shp->this_id, shp->sg_tablesize, shp->cmd_per_lun); -#else /* version >= v1.3.57 */ -" unique_id %d, can_queue %d, this_id %d, sg_tablesize %u, cmd_per_lun %u\n", - shp->unique_id, shp->can_queue, shp->this_id, shp->sg_tablesize, - shp->cmd_per_lun); -#endif /* version >= v1.3.57 */ - ASC_PRT_NEXT(); +#ifdef ADVANSYS_DEBUG + ASC_DBG1(1, "advansys_setup: ints[0] %d\n", ints[0]); + for (i = 1; i < ints[0]; i++) { + ASC_DBG2(1, " ints[%d] %x", i, ints[i]); + } + ASC_DBG(1, "\n"); +#endif /* ADVANSYS_DEBUG */ - len = asc_prt_line(cp, leftlen, -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,57) -" unchecked_isa_dma %d, loaded_as_module %d\n", - shp->unchecked_isa_dma, shp->loaded_as_module); -#else /* version >= v1.3.57 */ -" unchecked_isa_dma %d, use_clustering %d, loaded_as_module %d\n", - shp->unchecked_isa_dma, shp->use_clustering, shp->loaded_as_module); -#endif /* version >= v1.3.57 */ - ASC_PRT_NEXT(); + 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]); + } +} - len = asc_prt_line(cp, leftlen, -" flags %x, last_reset %x, jiffies %x\n", - ASC_BOARDP(shp)->flags, ASC_BOARDP(shp)->last_reset, jiffies); - ASC_PRT_NEXT(); -#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; - } - len = asc_prt_line(cp, leftlen, " %d:%d", - i, boardp->device[i]->queue_depth); - ASC_PRT_NEXT(); - } - len = asc_prt_line(cp, leftlen, "\n"); - ASC_PRT_NEXT(); -#endif /* version >= v1.3.89 */ +/* + * --- Loadable Driver Support + */ -#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; - } - len = asc_prt_line(cp, leftlen, " %d:%d", - i, boardp->device[i]->queue_curr_depth); - ASC_PRT_NEXT(); - } - len = asc_prt_line(cp, leftlen, "\n"); - ASC_PRT_NEXT(); +#ifdef MODULE +Scsi_Host_Template driver_template = ADVANSYS; +# include "scsi_module.c" +#endif /* MODULE */ - 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, " %d:%d", - i, boardp->device[i]->queue_count); - ASC_PRT_NEXT(); - } - len = asc_prt_line(cp, leftlen, "\n"); - ASC_PRT_NEXT(); -#endif /* ASC_QUEUE_FLOW_CONTROL */ - return totlen; -} +/* + * --- Miscellaneous Driver Functions + */ /* - * asc_prt_board_info() - * - * Print dynamic board configuration information. - * - * Note: no single line should be greater than ASC_PRTLINE_SIZE, - * cf. asc_prt_line(). + * First-level interrupt handler. * - * Return the number of characters copied into 'cp'. No more than - * 'cplen' characters will be copied to 'cp'. + * For versions > v1.3.70, 'dev_id' is a pointer to the interrupting + * adapter's asc_board_t. Because all boards are currently checked + * for interrupts on each interrupt, 'dev_id' is not referenced. 'dev_id' + * could be used to identify an interrupt passed to the AdvanSys driver, + * which is for a device sharing an interrupt with an AdvanSys adapter. */ -STATIC int -asc_prt_board_info(struct Scsi_Host *shp, char *cp, int cplen) +STATIC void +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,70) +advansys_interrupt(int irq, struct pt_regs *regs) +#else /* version >= v1.3.70 */ +advansys_interrupt(int irq, void *dev_id, struct pt_regs *regs) +#endif /* version >= v1.3.70 */ { - asc_board_t *boardp; - int leftlen; - int totlen; - int len; - ASC_DVC_VAR *v; - ASC_DVC_CFG *c; - int i; - - boardp = ASC_BOARDP(shp); - v = &boardp->asc_dvc_var; - c = &boardp->asc_dvc_cfg; + int flags; + int i; + asc_board_t *boardp; + Scsi_Cmnd *done_scp = NULL, *last_scp = NULL; + Scsi_Cmnd *new_last_scp; - leftlen = cplen; - totlen = len = 0; + /* Disable interrupts, if they aren't already disabled. */ + save_flags(flags); + cli(); - len = asc_prt_line(cp, leftlen, -"\nAsc Library Configuration and Statistics for AdvanSys SCSI Host %d:\n", - shp->host_no); - ASC_PRT_NEXT(); + ASC_DBG(1, "advansys_interrupt: begin\n"); - len = asc_prt_line(cp, leftlen, -" chip_version %u, lib_version %u, lib_serial_no %u, mcode_date %u\n", - c->chip_version, c->lib_version, c->lib_serial_no, c->mcode_date); - ASC_PRT_NEXT(); + /* + * Check for interrupts on all boards. + * AscISR() will call asc_isr_callback(). + */ + for (i = 0; i < asc_board_count; i++) { + boardp = ASC_BOARDP(asc_host[i]); + 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); + } + } - len = asc_prt_line(cp, leftlen, -" mcode_version %u, err_code %u\n", - c->mcode_version, v->err_code); - ASC_PRT_NEXT(); + /* + * Start waiting requests and create a list of completed requests. + * + * If a reset or abort request is being performed for the board, + * the reset or abort handler will complete pending requests after + * it has completed. + */ + if ((boardp->flags & (ASC_HOST_IN_RESET | ASC_HOST_IN_ABORT)) == 0) { + ASC_DBG2(1, "advansys_interrupt: done_scp %lx, last_scp %lx\n", + (ulong) done_scp, (ulong) last_scp); - /* Current number of commands waiting for the host. */ - len = asc_prt_line(cp, leftlen, -" Total Command Pending: %d\n", v->cur_total_qng); - ASC_PRT_NEXT(); + /* Start any waiting commands for the board. */ + if (!ASC_QUEUE_EMPTY(&boardp->waiting)) { + ASC_DBG(1, "advansys_interrupt: before asc_execute_queue()\n"); + asc_execute_queue(&boardp->waiting); + } - len = asc_prt_line(cp, leftlen, -" 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)) { - continue; + /* + * 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); + } else { + ASC_ASSERT(last_scp != NULL); + REQPNEXT(last_scp) = asc_dequeue_list(&boardp->done, + &new_last_scp, ASC_TID_ALL); + if (new_last_scp != NULL) { + ASC_ASSERT(REQPNEXT(last_scp) != NULL); + last_scp = new_last_scp; + } + } } - len = asc_prt_line(cp, leftlen, " %d:%c", - i, (v->use_tagged_qng & ASC_TIX_TO_TARGET_ID(i)) ? 'Y' : 'N'); - ASC_PRT_NEXT(); } - len = asc_prt_line(cp, leftlen, "\n"); - ASC_PRT_NEXT(); - /* Current number of commands waiting for a device. */ - len = asc_prt_line(cp, leftlen, -" 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)) { - continue; - } - len = asc_prt_line(cp, leftlen, " %d:%u", i, v->cur_dvc_qng[i]); - ASC_PRT_NEXT(); - } - len = asc_prt_line(cp, leftlen, "\n"); - ASC_PRT_NEXT(); + /* Interrupts could be enabled here. */ - /* Current limit on number of commands that can be sent to a device. */ - len = asc_prt_line(cp, leftlen, -" 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)) { - continue; - } - len = asc_prt_line(cp, leftlen, " %d:%u", i, v->max_dvc_qng[i]); - ASC_PRT_NEXT(); - } - len = asc_prt_line(cp, leftlen, "\n"); - ASC_PRT_NEXT(); + /* + * It is possible for the request done function to re-enable + * interrupts without confusing the driver. But here interrupts + * aren't enabled until all requests have been completed. + */ + asc_scsi_done_list(done_scp); - /* Indicate whether the device has returned queue full status. */ - len = asc_prt_line(cp, leftlen, -" 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)) { + /* Re-enable interrupts, if they were enabled on entry. */ + restore_flags(flags); + + ASC_DBG(1, "advansys_interrupt: end\n"); + return; +} + +#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) +/* + * Set the number of commands to queue per device for the + * specified host adapter. + */ +STATIC void +advansys_select_queue_depths(struct Scsi_Host *shp, Scsi_Device *devicelist) +{ + Scsi_Device *device; + 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; } - if (boardp->queue_full & ASC_TIX_TO_TARGET_ID(i)) { - len = asc_prt_line(cp, leftlen, " %d:Y-%d", - i, boardp->queue_full_cnt[i]); + /* + * Save a pointer to the device and set its initial/maximum + * queue depth. + */ + boardp->device[device->id] = device; + if (ASC_NARROW_BOARD(boardp)) { + device->queue_depth = + boardp->dvc_var.asc_dvc_var.max_dvc_qng[device->id]; } else { - len = asc_prt_line(cp, leftlen, " %d:N", i); + device->queue_depth = + boardp->dvc_var.adv_dvc_var.max_dvc_qng; } - ASC_PRT_NEXT(); + ASC_DBG3(1, "advansys_select_queue_depths: shp %x, id %d, depth %d\n", + (unsigned) shp, device->id, device->queue_depth); } - 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 <= 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, " %d:%c", - i, (v->sdtr_done & ASC_TIX_TO_TARGET_ID(i)) ? 'Y' : 'N'); - ASC_PRT_NEXT(); - } - len = asc_prt_line(cp, leftlen, "\n"); - ASC_PRT_NEXT(); - - 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)) { - continue; - } - if ((v->sdtr_done & ASC_TIX_TO_TARGET_ID(i)) == 0) { - continue; - } - syn_period_ix = (boardp->sdtr_data[i] >> 4) & (v->max_sdtr_index - 1); - len = asc_prt_line(cp, leftlen, " %d:", i); - ASC_PRT_NEXT(); - - len = asc_prt_line(cp, leftlen, - " Transfer Period Factor: %d (%d.%d Mhz),", - v->sdtr_period_tbl[syn_period_ix], - 250 / v->sdtr_period_tbl[syn_period_ix], - ASC_TENTHS(250, v->sdtr_period_tbl[syn_period_ix])); - ASC_PRT_NEXT(); - - len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d\n", - boardp->sdtr_data[i] & ASC_SYN_MAX_OFFSET); - ASC_PRT_NEXT(); - } - - return totlen; } +#endif /* version >= v1.3.89 */ /* - * 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. + * Function used only with polled I/O requests that are initiated by + * advansys_command(). */ -STATIC int -asc_proc_copy(off_t advoffset, off_t offset, char *curbuf, int leftlen, - char *cp, int cplen) +STATIC void +advansys_command_done(Scsi_Cmnd *scp) { - 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_DBG1(1, "advansys_command_done: scp %x\n", (unsigned) scp); + scp->SCp.Status = 1; } /* - * 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. + * Complete all requests on the singly linked list pointed + * to by 'scp'. * - * 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' - * global variable which is incremented once every 5 ms - * from a timer interrupt, because this function may be - * called when interrupts are disabled. + * Interrupts can be enabled on entry. */ STATIC void -DvcSleepMilliSecond(ulong n) +asc_scsi_done_list(Scsi_Cmnd *scp) { - ulong i; + Scsi_Cmnd *tscp; - ASC_DBG1(4, "DvcSleepMilliSecond: %lu\n", n); - for (i = 0; i < n; i++) { - udelay(1000); + 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); + ASC_ASSERT(scp->scsi_done != NULL); + scp->scsi_done(scp); + scp = tscp; } -} - -STATIC int -DvcEnterCritical(void) -{ - int flags; - - save_flags(flags); - cli(); - return flags; -} - -STATIC void -DvcLeaveCritical(int flags) -{ - restore_flags(flags); -} - -STATIC ulong -DvcGetSGList(ASC_DVC_VAR *asc_dvc_sg, uchar *buf_addr, ulong buf_len, - ASC_SG_HEAD *asc_sg_head_ptr) -{ - ulong buf_size; - - buf_size = buf_len; - asc_sg_head_ptr->entry_cnt = 1; -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0) - asc_sg_head_ptr->sg_list[0].addr = (ulong) buf_addr; -#else /* version >= v2.0.0 */ - asc_sg_head_ptr->sg_list[0].addr = virt_to_bus(buf_addr); -#endif /* version >= v2.0.0 */ - asc_sg_head_ptr->sg_list[0].bytes = buf_size; - return buf_size; + ASC_DBG(2, "asc_scsi_done_list: done\n"); + return; } /* - * void - * DvcPutScsiQ(PortAddr iop_base, ushort s_addr, ushort *outbuf, int words) + * Execute a single 'Scsi_Cmnd'. * - * Calling/Exit State: - * none + * The function 'done' is called when the request has been completed. * - * Description: - * Output an ASC_SCSI_Q structure to the chip - */ -STATIC void -DvcPutScsiQ(PortAddr iop_base, ushort s_addr, ushort *outbuf, int words) -{ - int i; - - ASC_DBG_PRT_HEX(2, "DvcPutScsiQ", (uchar *) outbuf, 2 * words); - AscSetChipLramAddr(iop_base, s_addr); - for (i = 0; i < words; i++, outbuf++) { - if (i == 2 || i == 10) { - continue; - } - AscSetChipLramDataNoSwap(iop_base, *outbuf); - } -} - -/* - * void - * DvcGetQinfo(PortAddr iop_base, ushort s_addr, ushort *inbuf, int words) + * Scsi_Cmnd: * - * Calling/Exit State: - * none + * host - board controlling device + * device - device to send command + * target - target of device + * lun - lun of device + * cmd_len - length of SCSI CDB + * cmnd - buffer for SCSI 8, 10, or 12 byte CDB + * use_sg - if non-zero indicates scatter-gather request with use_sg elements * - * Description: - * Input an ASC_QDONE_INFO structure from the chip - */ -STATIC void -DvcGetQinfo(PortAddr iop_base, ushort s_addr, ushort *inbuf, int words) -{ - int i; - - AscSetChipLramAddr(iop_base, s_addr); - for (i = 0; i < words; i++, inbuf++) { - if (i == 5) { - continue; - } - *inbuf = AscGetChipLramDataNoSwap(iop_base); - } - ASC_DBG_PRT_HEX(2, "DvcGetQinfo", (uchar *) inbuf, 2 * words); -} - -/* - * void DvcOutPortWords(ushort iop_base, ushort &outbuf, int words) + * if (use_sg == 0) { + * request_buffer - buffer address for request + * request_bufflen - length of request buffer + * } else { + * request_buffer - pointer to scatterlist structure + * } * - * Calling/Exit State: - * none + * sense_buffer - sense command buffer * - * Description: - * output a buffer to an i/o port address - */ -STATIC void -DvcOutPortWords(ushort iop_base, ushort *outbuf, int words) -{ - int i; - - for (i = 0; i < words; i++, outbuf++) - outpw(iop_base, *outbuf); -} - -/* - * void DvcInPortWords(ushort iop_base, ushort &outbuf, int words) + * 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 * - * Calling/Exit State: - * none + * 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 * - * Description: - * input a buffer from an i/o port address + * If this function returns ASC_NOERROR or ASC_ERROR the request + * has been enqueued on the board's 'done' queue and must be + * completed by the caller. + * + * If ASC_BUSY is returned the request must be enqueued by the + * caller and re-tried later. */ -STATIC void -DvcInPortWords(ushort iop_base, ushort *inbuf, int words) +STATIC int +asc_execute_scsi_cmnd(Scsi_Cmnd *scp) { - int i; - - for (i = 0; i < words; i++, inbuf++) - *inbuf = inpw(iop_base); -} + 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; + ASC_ASSERT(interrupts_enabled() == ASC_FALSE); + ASC_DBG2(1, "asc_execute_scsi_cmnd: scp %x, done %x\n", + (unsigned) scp, (unsigned) scp->scsi_done); -/* - * void DvcOutPortDWords(PortAddr port, ulong *pdw, int dwords) - * - * Calling/Exit State: - * none - * - * Description: - * output a buffer of 32-bit integers to an i/o port address in - * 16 bit integer units - */ -STATIC void -DvcOutPortDWords(PortAddr port, ulong *pdw, int dwords) -{ - int i; - int words; - ushort *pw; + boardp = ASC_BOARDP(scp->host); + device = boardp->device[scp->target]; - pw = (ushort *) pdw; - words = dwords << 1; - for(i = 0; i < words; i++, pw++) { - outpw(port, *pw); - } - return; -} + if (ASC_NARROW_BOARD(boardp)) { + /* + * Build and execute Narrow Board request. + */ -/* - * Read a PCI configuration byte. - */ -ASC_INITFUNC( -STATIC uchar -DvcReadPCIConfigByte( - ASC_DVC_VAR asc_ptr_type *asc_dvc, - ushort offset) -) -{ - PCI_DATA pciData; + asc_dvc_varp = &boardp->dvc_var.asc_dvc_var; - 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); -} + /* + * 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); + } -/* - * Write a PCI configuration byte. - */ -ASC_INITFUNC( -STATIC void -DvcWritePCIConfigByte( - ASC_DVC_VAR asc_ptr_type *asc_dvc, - ushort offset, - uchar byte_data) -) -{ - PCI_DATA pciData; + /* + * 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; + } - 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); -} + /* + * 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]++; -/* - * Return the BIOS address of the adapter at the specified - * I/O port and with the specified bus type. - */ -ASC_INITFUNC( -STATIC ushort -AscGetChipBiosAddress( - PortAddr iop_base, - ushort bus_type -) -) -{ - ushort cfg_lsw ; - ushort bios_addr ; +#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; - /* - * The PCI BIOS is re-located by the motherboard BIOS. Because - * of this the driver can not determine where a PCI BIOS is - * loaded and executes. - */ - if (bus_type & ASC_IS_PCI) - { - return(0); + /* + * 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; + } + + /* + * 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; + } } - if((bus_type & ASC_IS_EISA) != 0) - { - cfg_lsw = AscGetEisaChipCfg(iop_base) ; - cfg_lsw &= 0x000F ; - bios_addr = (ushort)(ASC_BIOS_MIN_ADDR + - (cfg_lsw * ASC_BIOS_BANK_SIZE)) ; - return(bios_addr) ; - }/* if */ - - cfg_lsw = AscGetChipCfgLsw(iop_base) ; - - /* - * ISA PnP uses the top bit as the 32K BIOS flag - */ - if (bus_type == ASC_IS_ISAPNP) - { - cfg_lsw &= 0x7FFF; - }/* if */ - - bios_addr = (ushort)(((cfg_lsw >> 12) * ASC_BIOS_BANK_SIZE) + - ASC_BIOS_MIN_ADDR) ; - return(bios_addr) ; + ASC_DBG(1, "asc_execute_scsi_cmnd: end\n"); + ASC_ASSERT(interrupts_enabled() == ASC_FALSE); + return ret; } - -/* - * --- Tracing and Debugging Functions - */ - -#ifdef ADVANSYS_STATS /* - * asc_prt_board_stats() + * Build a request structure for the Asc Library (Narrow Board). * - * Note: no single line should be greater than ASC_PRTLINE_SIZE, - * cf. asc_prt_line(). + * The global structures 'asc_scsi_q' and 'asc_sg_head' are + * used to build the request. * - * Return the number of characters copied into 'cp'. No more than - * 'cplen' characters will be copied to 'cp'. + * If an error occurs, then return ASC_ERROR. */ STATIC int -asc_prt_board_stats(struct Scsi_Host *shp, char *cp, int cplen) +asc_build_req(asc_board_t *boardp, Scsi_Cmnd *scp) { - int leftlen; - int totlen; - int len; - struct asc_stats *s; - int i; - asc_queue_t *active; - asc_queue_t *waiting; - - leftlen = cplen; - totlen = len = 0; - - s = &ASC_BOARDP(shp)->asc_stats; - len = asc_prt_line(cp, leftlen, -"\nLinux Driver Statistics for AdvanSys SCSI Host %d:\n", shp->host_no); - ASC_PRT_NEXT(); - - len = asc_prt_line(cp, leftlen, -" command %lu, queuecommand %lu, abort %lu, reset %lu, biosparam %lu\n", - s->command, s->queuecommand, s->abort, s->reset, s->biosparam); - 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); - 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); - ASC_PRT_NEXT(); - /* - * Display data transfer statistics. + * Mutually exclusive access is required to 'asc_scsi_q' and + * 'asc_sg_head' until after the request is started. */ - if (s->cont_cnt > 0) { - len = asc_prt_line(cp, leftlen, " cont_cnt %lu, ", s->cont_cnt); - ASC_PRT_NEXT(); + memset(&asc_scsi_q, 0, sizeof(ASC_SCSI_Q)); - len = asc_prt_line(cp, leftlen, "cont_xfer %lu.%01lu kb ", - s->cont_xfer/2, - ASC_TENTHS(s->cont_xfer, 2)); - ASC_PRT_NEXT(); + /* + * Point the ASC_SCSI_Q to the 'Scsi_Cmnd'. + */ + asc_scsi_q.q2.srb_ptr = (ulong) scp; - /* Contiguous transfer average size */ - len = asc_prt_line(cp, leftlen, "avg_xfer %lu.%01lu kb\n", - (s->cont_xfer/2)/s->cont_cnt, - ASC_TENTHS((s->cont_xfer/2), s->cont_cnt)); - ASC_PRT_NEXT(); + /* + * 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); + asc_scsi_q.q1.target_lun = scp->lun; + asc_scsi_q.q2.target_ix = ASC_TIDLUN_TO_IX(scp->target, scp->lun); +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0) + asc_scsi_q.q1.sense_addr = (ulong) &scp->sense_buffer[0]; +#else /* version >= v2.0.0 */ + asc_scsi_q.q1.sense_addr = virt_to_bus(&scp->sense_buffer[0]); +#endif /* version >= v2.0.0 */ + asc_scsi_q.q1.sense_len = sizeof(scp->sense_buffer); - if (s->sg_cnt > 0) { - - len = asc_prt_line(cp, leftlen, " sg_cnt %lu, sg_elem %lu, ", - s->sg_cnt, s->sg_elem); - ASC_PRT_NEXT(); - - len = asc_prt_line(cp, leftlen, "sg_xfer %lu.%01lu kb\n", - s->sg_xfer/2, - ASC_TENTHS(s->sg_xfer, 2)); - ASC_PRT_NEXT(); - - /* Scatter gather transfer statistics */ - len = asc_prt_line(cp, leftlen, " avg_num_elem %lu.%01lu, ", - s->sg_elem/s->sg_cnt, - ASC_TENTHS(s->sg_elem, s->sg_cnt)); - ASC_PRT_NEXT(); - - len = asc_prt_line(cp, leftlen, "avg_elem_size %lu.%01lu kb, ", - (s->sg_xfer/2)/s->sg_elem, - ASC_TENTHS((s->sg_xfer/2), s->sg_elem)); - ASC_PRT_NEXT(); - - len = asc_prt_line(cp, leftlen, "avg_xfer_size %lu.%01lu kb\n", - (s->sg_xfer/2)/s->sg_cnt, - ASC_TENTHS((s->sg_xfer/2), s->sg_cnt)); - ASC_PRT_NEXT(); + /* + * If there are any outstanding requests for the current target, + * then every 255th request send an ORDERED request. This heuristic + * tries to retain the benefit of request sorting while preventing + * request starvation. 255 is the max number of tags or pending commands + * a device may have outstanding. + * + * The request count is incremented below for every successfully + * started request. + * + */ + 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 { + asc_scsi_q.q2.tag_code = M2_QTAG_MSG_SIMPLE; } /* - * Display request queuing statistics. + * Build ASC_SCSI_Q for a contiguous buffer or a scatter-gather + * buffer command. */ - len = asc_prt_line(cp, leftlen, -" Active and Waiting Request Queues (time unit: %d HZ):\n", HZ); - ASC_PRT_NEXT(); + if (scp->use_sg == 0) { + /* + * CDB request of single contiguous buffer. + */ + ASC_STATS(scp->host, cont_cnt); +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0) + asc_scsi_q.q1.data_addr = (ulong) scp->request_buffer; +#else /* version >= v2.0.0 */ + asc_scsi_q.q1.data_addr = virt_to_bus(scp->request_buffer); +#endif /* version >= v2.0.0 */ + asc_scsi_q.q1.data_cnt = scp->request_bufflen; + ASC_STATS_ADD(scp->host, cont_xfer, + ASC_CEILING(scp->request_bufflen, 512)); + asc_scsi_q.q1.sg_queue_cnt = 0; + asc_scsi_q.sg_head = NULL; + } else { + /* + * CDB scatter-gather request list. + */ + int sgcnt; + struct scatterlist *slp; - active = &ASC_BOARDP(shp)->active; - waiting = &ASC_BOARDP(shp)->waiting; - for (i = 0; i < ASC_MAX_TID + 1; i++) { - 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(); + if (scp->use_sg > scp->host->sg_tablesize) { + ASC_PRINT3( +"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); + return ASC_ERROR; + } - len = asc_prt_line(cp, leftlen, -" active: cnt [cur %d, max %d, tot %u], time [min %d, max %d, avg %lu.%01lu]\n", - active->q_cur_cnt[i], active->q_max_cnt[i], - active->q_tot_cnt[i], - active->q_min_tim[i], active->q_max_tim[i], - (active->q_tot_cnt[i] == 0) ? 0 : - (active->q_tot_tim[i]/active->q_tot_cnt[i]), - (active->q_tot_cnt[i] == 0) ? 0 : - ASC_TENTHS(active->q_tot_tim[i], active->q_tot_cnt[i])); - ASC_PRT_NEXT(); + ASC_STATS(scp->host, sg_cnt); - len = asc_prt_line(cp, leftlen, -" waiting: cnt [cur %d, max %d, tot %u], time [min %u, max %u, avg %lu.%01lu]\n", - waiting->q_cur_cnt[i], waiting->q_max_cnt[i], - waiting->q_tot_cnt[i], - waiting->q_min_tim[i], waiting->q_max_tim[i], - (waiting->q_tot_cnt[i] == 0) ? 0 : - (waiting->q_tot_tim[i]/waiting->q_tot_cnt[i]), - (waiting->q_tot_cnt[i] == 0) ? 0 : - ASC_TENTHS(waiting->q_tot_tim[i], waiting->q_tot_cnt[i])); - ASC_PRT_NEXT(); + /* + * 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)); + + asc_scsi_q.q1.cntl |= QC_SG_HEAD; + asc_scsi_q.sg_head = &asc_sg_head; + asc_scsi_q.q1.data_cnt = 0; + asc_scsi_q.q1.data_addr = 0; + asc_sg_head.entry_cnt = asc_scsi_q.q1.sg_queue_cnt = scp->use_sg; + ASC_STATS_ADD(scp->host, sg_elem, asc_sg_head.entry_cnt); + + /* + * Convert scatter-gather list into ASC_SG_HEAD list. + */ + slp = (struct scatterlist *) scp->request_buffer; + for (sgcnt = 0; sgcnt < scp->use_sg; sgcnt++, slp++) { +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0) + asc_sg_head.sg_list[sgcnt].addr = (ulong) slp->address; +#else /* version >= v2.0.0 */ + asc_sg_head.sg_list[sgcnt].addr = virt_to_bus(slp->address); +#endif /* version >= v2.0.0 */ + asc_sg_head.sg_list[sgcnt].bytes = slp->length; + ASC_STATS_ADD(scp->host, sg_xfer, ASC_CEILING(slp->length, 512)); } } - return totlen; + ASC_DBG_PRT_ASC_SCSI_Q(2, &asc_scsi_q); + ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len); + + return ASC_NOERROR; } -#endif /* ADVANSYS_STATS */ -#ifdef ADVANSYS_DEBUG /* - * asc_prt_scsi_host() + * 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 void -asc_prt_scsi_host(struct Scsi_Host *s) +STATIC int +adv_build_req(asc_board_t *boardp, Scsi_Cmnd *scp, + ADV_SCSI_REQ_Q **adv_scsiqpp) { - 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); + adv_req_t *reqp; + ADV_SCSI_REQ_Q *scsiqp; + int i; -#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 */ /* } */ + /* + * Allocate an adv_req_t structure from the board to execute + * the command. + */ + 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; + } - printk( -" wish_block %d, base %x, io_port %d, n_io_port %d, irq %d, dma_channel %d,\n", - s->wish_block, (unsigned) s->base, s->io_port, s->n_io_port, - s->irq, s->dma_channel); + /* + * 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)); - printk( -" this_id %d, can_queue %d,\n", s->this_id, s->can_queue); + /* + * Set the ADV_SCSI_REQ_Q 'srb_ptr' to point to the adv_req_t structure. + */ + scsiqp->srb_ptr = (ulong) reqp; - printk( -" cmd_per_lun %d, sg_tablesize %d, unchecked_isa_dma %d, loaded_as_module %d\n", - s->cmd_per_lun, s->sg_tablesize, s->unchecked_isa_dma, - s->loaded_as_module); + /* + * Set the adv_req_t 'cmndp' to point to the Scsi_Cmnd structure. + */ + reqp->cmndp = scp; - asc_prt_dvc_var(&ASC_BOARDP(s)->asc_dvc_var); - asc_prt_dvc_cfg(&ASC_BOARDP(s)->asc_dvc_cfg); -} + /* + * Build the ADV_SCSI_REQ_Q request. + */ -/* - * asc_prt_scsi_cmnd() - */ -STATIC void -asc_prt_scsi_cmnd(Scsi_Cmnd *s) -{ - printk("Scsi_Cmnd at addr %x\n", (unsigned) s); + /* + * 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]; + } -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0) - printk( -" host %x, device %x, target %u, lun %u\n", - (unsigned) s->host, (unsigned) s->device, s->target, s->lun); -#else /* version >= v1.3.0 */ - printk( -" host %x, device %x, target %u, lun %u, channel %u,\n", - (unsigned) s->host, (unsigned) s->device, s->target, s->lun, - s->channel); -#endif /* version >= v1.3.0 */ + scsiqp->target_id = scp->target; + scsiqp->target_lun = scp->lun; - asc_prt_hex(" CDB", s->cmnd, s->cmd_len); + 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); - printk( -" use_sg %u, sglist_len %u, abort_reason %x\n", - s->use_sg, s->sglist_len, s->abort_reason); + /* + * 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 LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,89) - printk( -" retries %d, allowed %d\n", - s->retries, s->allowed); -#else /* version >= v1.3.89 */ - printk( -" serial_number %x, serial_number_at_timeout %x, retries %d, allowed %d\n", - (unsigned) s->serial_number, (unsigned) s->serial_number_at_timeout, - s->retries, s->allowed); -#endif /* version >= v1.3.89 */ + if (scp->use_sg == 0) { + /* + * CDB request of single contiguous buffer. + */ + 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); - printk( -" timeout_per_command %d, timeout_total %d, timeout %d\n", - s->timeout_per_command, s->timeout_total, s->timeout); + /* + * 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; - printk( -" internal_timeout %u, flags %u, this_count %d\n", - s->internal_timeout, s->flags, s->this_count); + return ASC_ERROR; + } - printk( -" scsi_done %x, done %x, host_scribble %x, result %x\n", - (unsigned) s->scsi_done, (unsigned) s->done, - (unsigned) s->host_scribble, s->result); + /* + * 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; + } - printk( -" tag %u, pid %u\n", - (unsigned) s->tag, (unsigned) s->pid); -} + /* + * Build scatter-gather list. + */ + scsiqp->sg_list_ptr = (ADV_SG_BLOCK *) + ADV_DWALIGN(&reqp->sgblkp->sg_block[0]); -/* - * asc_prt_dvc_var() - */ -STATIC void -asc_prt_dvc_var(ASC_DVC_VAR *h) -{ - printk("ASC_DVC_VAR at addr %x\n", (unsigned) h); + 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) { - printk( -" iop_base %x, err_code %x, dvc_cntl %x, bug_fix_cntl %d,\n", - h->iop_base, h->err_code, h->dvc_cntl, h->bug_fix_cntl); + /* + * 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; - printk( -" bus_type %d, isr_callback %x, exe_callback %x, init_sdtr %x,\n", - h->bus_type, (unsigned) h->isr_callback, (unsigned) h->exe_callback, - (unsigned) h->init_sdtr); + /* + * 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; - printk( -" sdtr_done %x, use_tagged_qng %x, unit_not_ready %x, chip_no %x,\n", - (unsigned) h->sdtr_done, (unsigned) h->use_tagged_qng, - (unsigned) h->unit_not_ready, (unsigned) h->chip_no); - - printk( -" queue_full_or_busy %x, start_motor %x, scsi_reset_wait %x, irq_no %x,\n", - (unsigned) h->queue_full_or_busy, (unsigned) h->start_motor, - (unsigned) h->scsi_reset_wait, (unsigned) h->irq_no); + return ADV_ERROR; + } - printk( -" is_in_int %x, max_total_qng %x, cur_total_qng %x, in_critical_cnt %x,\n", - (unsigned) h->is_in_int, (unsigned) h->max_total_qng, - (unsigned) h->cur_total_qng, (unsigned) h->in_critical_cnt); + ASC_STATS(scp->host, sg_cnt); + ASC_STATS_ADD(scp->host, sg_elem, scp->use_sg); + } - printk( -" last_q_shortage %x, init_state %x, no_scam %x, pci_fix_asyn_xfer %x,\n", - (unsigned) h->last_q_shortage, (unsigned) h->init_state, - (unsigned) h->no_scam, (unsigned) h->pci_fix_asyn_xfer); + ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp); + ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len); - printk( -" cfg %x, saved_ptr2func %x\n", - (unsigned) h->cfg, (unsigned) h->saved_ptr2func); + *adv_scsiqpp = scsiqp; + + return ASC_NOERROR; } /* - * asc_prt_dvc_cfg() + * 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 void -asc_prt_dvc_cfg(ASC_DVC_CFG *h) -{ - printk("ASC_DVC_CFG at addr %x\n", (unsigned) h); - - printk( -" can_tagged_qng %x, cmd_qng_enabled %x, disc_enable %x, res %x,\n", - h->can_tagged_qng, h->cmd_qng_enabled, h->disc_enable, h->res); +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; - printk( -" chip_scsi_id %d, isa_dma_speed %d, isa_dma_channel %d, chip_version %d,\n", - h->chip_scsi_id, h->isa_dma_speed, h->isa_dma_channel, - h->chip_version); + 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)); - printk( -" pci_device_id %d, lib_serial_no %d, lib_version %d, mcode_date %d,\n", - h->pci_device_id, h->lib_serial_no, h->lib_version, h->mcode_date); + 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); - printk( -" mcode_version %d, overrun_buf %x\n", - h->mcode_version, (unsigned) h->overrun_buf); + 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_prt_scsi_q() + * asc_isr_callback() - Second Level Interrupt Handler called by AscISR(). + * + * Interrupt callback function for the Narrow SCSI Asc Library. */ -STATIC void -asc_prt_scsi_q(ASC_SCSI_Q *q) +STATIC void +asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep) { - ASC_SG_HEAD *sgp; - int i; - - printk("ASC_SCSI_Q at addr %x\n", (unsigned) q); + asc_board_t *boardp; + Scsi_Cmnd *scp; + struct Scsi_Host *shp; + int underrun = ASC_FALSE; + int i; - printk( -" target_ix %u, target_lun %u, srb_ptr %x, tag_code %u,\n", - q->q2.target_ix, q->q1.target_lun, - (unsigned) q->q2.srb_ptr, q->q2.tag_code); + 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_ASC_QDONE_INFO(2, qdonep); - printk( -" data_addr %x, data_cnt %lu, sense_addr %x, sense_len %u,\n", - (unsigned) q->q1.data_addr, q->q1.data_cnt, - (unsigned) q->q1.sense_addr, q->q1.sense_len); + /* + * Get the Scsi_Cmnd structure and Scsi_Host structure for the + * command that has been completed. + */ + scp = (Scsi_Cmnd *) qdonep->d2.srb_ptr; + ASC_DBG1(1, "asc_isr_callback: scp %x\n", (unsigned) scp); - printk( -" cdbptr %x, cdb_len %u, sg_head %x, sg_queue_cnt %u\n", - (unsigned) q->cdbptr, q->q2.cdb_len, - (unsigned) q->sg_head, q->q1.sg_queue_cnt); + if (scp == NULL) { + ASC_PRINT("asc_isr_callback: scp is NULL\n"); + return; + } + ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len); - if (q->sg_head) { - sgp = q->sg_head; - printk("ASC_SG_HEAD at addr %x\n", (unsigned) sgp); - printk(" entry_cnt %u, queue_cnt %u\n", sgp->entry_cnt, sgp->queue_cnt); - for (i = 0; i < sgp->entry_cnt; i++) { - printk(" [%u]: addr %x, bytes %lu\n", - i, (unsigned) sgp->sg_list[i].addr, sgp->sg_list[i].bytes); + /* + * 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; } - } -} + if (i == asc_board_count) { + ASC_PRINT2("asc_isr_callback: scp %x has bad host pointer, host %x\n", + (unsigned) scp, (unsigned) shp); + return; + } -/* - * asc_prt_qdone_info() - */ -STATIC void -asc_prt_qdone_info(ASC_QDONE_INFO *q) -{ - printk("ASC_QDONE_INFO at addr %x\n", (unsigned) q); - printk( -" srb_ptr %x, target_ix %u, cdb_len %u, tag_code %u, done_stat %x\n", - (unsigned) q->d2.srb_ptr, q->d2.target_ix, q->d2.cdb_len, - q->d2.tag_code, q->d3.done_stat); - printk( -" host_stat %x, scsi_stat %x, scsi_msg %x\n", - q->d3.host_stat, q->d3.scsi_stat, q->d3.scsi_msg); -} + ASC_STATS(shp, callback); + ASC_DBG1(1, "asc_isr_callback: shp %x\n", (unsigned) shp); -/* - * 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; + /* + * If the request isn't found on the active queue, it may + * have been removed to handle a reset or abort request. + * Display a message and return. + */ + boardp = ASC_BOARDP(shp); + if (asc_rmqueue(&boardp->active, scp) == ASC_FALSE) { + ASC_PRINT2("asc_isr_callback: board %d: scp %x not on active queue\n", + boardp->id, (unsigned) scp); + return; + } - printk("%s: (%d bytes)\n", f, l); + /* + * 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; + } - 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 ; + /* + * 'qdonep' contains the command's ending status. + */ + switch (qdonep->d3.done_stat) { + case QD_NO_ERROR: + ASC_DBG(2, "asc_isr_callback: QD_NO_ERROR\n"); + switch (qdonep->d3.host_stat) { + case QHSTA_NO_ERROR: + scp->result = 0; + break; + default: + /* QHSTA error occurred */ + 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; - 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]); - } + case QD_WITH_ERROR: + ASC_DBG(2, "asc_isr_callback: QD_WITH_ERROR\n"); + switch (qdonep->d3.host_stat) { + case QHSTA_NO_ERROR: + if (qdonep->d3.scsi_stat == SS_CHK_CONDITION) { + ASC_DBG(2, "asc_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(qdonep->d3.scsi_stat); + } else { + scp->result = STATUS_BYTE(qdonep->d3.scsi_stat); + } + break; - switch (m) { - case 0: default: - break; - case 1: - printk(" %2.2X", - (unsigned) s[i+(j*4)]); - break; - case 2: - printk(" %2.2X%2.2X", - (unsigned) s[i+(j*4)], - (unsigned) s[i+(j*4)+1]); - break; - case 3: - printk(" %2.2X%2.2X%2.2X", - (unsigned) s[i+(j*4)+1], - (unsigned) s[i+(j*4)+2], - (unsigned) s[i+(j*4)+3]); + /* QHSTA error occurred */ + ASC_DBG1(2, "asc_isr_callback: host_stat %x\n", + qdonep->d3.host_stat); + scp->result = HOST_BYTE(DID_ERROR) | MSG_BYTE(qdonep->d3.scsi_msg) | + STATUS_BYTE(qdonep->d3.scsi_stat); break; } + break; - printk("\n"); - } -} -#endif /* ADVANSYS_DEBUG */ - -#ifdef ADVANSYS_ASSERT -/* - * interrupts_enabled() - * - * Return 1 if interrupts are enabled, otherwise return 0. - */ -STATIC int -interrupts_enabled(void) -{ - int flags; + case QD_ABORTED_BY_HOST: + ASC_DBG(1, "asc_isr_callback: QD_ABORTED_BY_HOST\n"); + scp->result = HOST_BYTE(DID_ABORT) | MSG_BYTE(qdonep->d3.scsi_msg) | + STATUS_BYTE(qdonep->d3.scsi_stat); + break; - save_flags(flags); - if (flags & 0x0200) { - return ASC_TRUE; - } else { - return ASC_FALSE; + default: + ASC_PRINT1("asc_isr_callback: done_stat %x\n", qdonep->d3.done_stat); + scp->result = HOST_BYTE(DID_ERROR) | MSG_BYTE(qdonep->d3.scsi_msg) | + STATUS_BYTE(qdonep->d3.scsi_stat); + break; } -} -#endif /* ADVANSYS_ASSERT */ + /* + * 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); + + return; +} /* - * --- Asc Library Functions + * adv_isr_callback() - Second Level Interrupt Handler called by AdvISR(). + * + * Callback function for the Wide SCSI Adv Library. */ - -ASC_INITFUNC( -STATIC ushort -AscGetEisaChipCfg( - PortAddr iop_base -) -) +STATIC void +adv_isr_callback(ADV_DVC_VAR *adv_dvc_varp, ADV_SCSI_REQ_Q *scsiqp) { - 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)); -} + asc_board_t *boardp; + adv_req_t *reqp; + Scsi_Cmnd *scp; + struct Scsi_Host *shp; + int underrun = ASC_FALSE; + int i; -ASC_INITFUNC( -STATIC uchar -AscSetChipScsiID( - PortAddr iop_base, - uchar new_host_id -) -) -{ - ushort cfg_lsw; - if (AscGetChipScsiID(iop_base) == new_host_id) { - return (new_host_id); - } - cfg_lsw = AscGetChipCfgLsw(iop_base); - cfg_lsw &= 0xF8FF; - cfg_lsw |= (ushort) ((new_host_id & ASC_MAX_TID) << 8); - AscSetChipCfgLsw(iop_base, cfg_lsw); - return (AscGetChipScsiID(iop_base)); -} + 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); -ASC_INITFUNC( -STATIC uchar -AscGetChipScsiCtrl( - PortAddr iop_base -) -) -{ - uchar sc; - AscSetBank(iop_base, 1); - sc = inp(iop_base + IOP_REG_SC); - AscSetBank(iop_base, 0); - return (sc); -} + /* + * 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; + } -ASC_INITFUNC( -STATIC uchar -AscGetChipVersion( - PortAddr iop_base, - ushort bus_type -) -) -{ - if ((bus_type & ASC_IS_EISA) != 0) { - PortAddr eisa_iop; - uchar revision; - eisa_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) | - (PortAddr) ASC_EISA_REV_IOP_MASK; - revision = inp(eisa_iop); - return ((uchar) ((ASC_CHIP_MIN_VER_EISA - 1) + revision)); + /* + * 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. + */ + 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; } - return (AscGetChipVerNo(iop_base)); -} + ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len); -ASC_INITFUNC( -STATIC ushort -AscGetChipBusType( - PortAddr iop_base -) -) -{ - ushort chip_ver; - chip_ver = AscGetChipVerNo(iop_base); - if ( - (chip_ver >= ASC_CHIP_MIN_VER_VL) - && (chip_ver <= ASC_CHIP_MAX_VER_VL) -) { - if ( - ((iop_base & 0x0C30) == 0x0C30) - || ((iop_base & 0x0C50) == 0x0C50) -) { - return (ASC_IS_EISA); + /* + * 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; } - return (ASC_IS_VL); } - if ((chip_ver >= ASC_CHIP_MIN_VER_ISA) && - (chip_ver <= ASC_CHIP_MAX_VER_ISA)) { - if (chip_ver >= ASC_CHIP_MIN_VER_ISA_PNP) { - return (ASC_IS_ISAPNP); - } - return (ASC_IS_ISA); - } else if ((chip_ver >= ASC_CHIP_MIN_VER_PCI) && - (chip_ver <= ASC_CHIP_MAX_VER_PCI)) { - return (ASC_IS_PCI); + /* + * 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; } - return (0); -} -ASC_INITFUNC( -STATIC ulong -AscLoadMicroCode( - PortAddr iop_base, - ushort s_addr, - ushort *mcode_buf, - ushort mcode_size -) -) -{ - 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); - chksum = AscMemSumLramWord(iop_base, s_addr, mcode_word_size); - mcode_chksum = (ushort) AscMemSumLramWord(iop_base, - (ushort) ASC_CODE_SEC_BEG, - (ushort) ((mcode_size - s_addr - (ushort) ASC_CODE_SEC_BEG) / 2)); - AscWriteLramWord(iop_base, ASCV_MCODE_CHKSUM_W, mcode_chksum); - AscWriteLramWord(iop_base, ASCV_MCODE_SIZE_W, mcode_size); - return (chksum); -} + ASC_STATS(shp, callback); + ASC_DBG1(1, "adv_isr_callback: shp %x\n", (unsigned) shp); -ASC_INITFUNC( -STATIC int -AscFindSignature( - PortAddr iop_base -) -) -{ - ushort sig_word; - if (AscGetChipSignatureByte(iop_base) == (uchar) ASC_1000_ID1B) { - sig_word = AscGetChipSignatureWord(iop_base); - if ((sig_word == (ushort) ASC_1000_ID0W) || - (sig_word == (ushort) ASC_1000_ID0W_FIX)) { - return (1); - } + /* + * 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; } - return (0); -} - -STATIC uchar _isa_pnp_inited ASC_INITDATA = 0; -STATIC PortAddr _asc_def_iop_base[ASC_IOADR_TABLE_MAX_IX] ASC_INITDATA = -{ - 0x100, ASC_IOADR_1, 0x120, ASC_IOADR_2, 0x140, ASC_IOADR_3, ASC_IOADR_4, - ASC_IOADR_5, ASC_IOADR_6, ASC_IOADR_7, ASC_IOADR_8 -}; -ASC_INITFUNC( -STATIC PortAddr -AscSearchIOPortAddr( - PortAddr iop_beg, - ushort bus_type -) -) -{ - if (bus_type & ASC_IS_VL) { - while ((iop_beg = AscSearchIOPortAddr11(iop_beg)) != 0) { - if (AscGetChipVersion(iop_beg, bus_type) <= ASC_CHIP_MAX_VER_VL) { - return (iop_beg); - } - } - return (0); + /* + * 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; } - if (bus_type & ASC_IS_ISA) { - if (_isa_pnp_inited == 0) { - AscSetISAPNPWaitForKey(); - _isa_pnp_inited++; - } - while ((iop_beg = AscSearchIOPortAddr11(iop_beg)) != 0) { - if ((AscGetChipVersion(iop_beg, bus_type) & ASC_CHIP_VER_ISA_BIT) != 0) { - return (iop_beg); - } + + /* + * '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; } - return (0); + /* + * 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); } - if (bus_type & ASC_IS_EISA) { - if ((iop_beg = AscSearchIOPortAddrEISA(iop_beg)) != 0) { - return (iop_beg); - } - return (0); + 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; } - return (0); + + /* + * 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_INITFUNC( -STATIC PortAddr -AscSearchIOPortAddr11( - PortAddr s_addr -) -) +/* + * 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) { - int i; - PortAddr iop_base; - for (i = 0; i < ASC_IOADR_TABLE_MAX_IX; i++) { - if (_asc_def_iop_base[i] > s_addr) { - break; - } + 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; } - for (; i < ASC_IOADR_TABLE_MAX_IX; i++) { - iop_base = _asc_def_iop_base[i]; - if (check_region(iop_base, ASC_IOADR_GAP) != 0) { - ASC_DBG1(1, - "AscSearchIOPortAddr11: check_region() failed I/O port %x\n", - iop_base); - continue; + + 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"); } - ASC_DBG1(1, "AscSearchIOPortAddr11: probing I/O port %x\n", iop_base); - if (AscFindSignature(iop_base)) { - return (iop_base); + 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; } - return (0); + + /* 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; } +/* + * Search for an AdvanSys PCI device in the PCI configuration space. + */ ASC_INITFUNC( -STATIC void -AscToggleIRQAct( - PortAddr iop_base -) +STATIC int +asc_srch_pci_dev(PCI_DEVICE *pciDevice) ) { - AscSetChipStatus(iop_base, CIW_IRQ_ACT); - AscSetChipStatus(iop_base, 0); - return; + int ret; + + ASC_DBG(2, "asc_srch_pci_dev: begin\n"); + + if (pci_scan_method == -1) { + pci_scan_method = asc_scan_method(); + } + pciDevice->type = pci_scan_method; + ASC_DBG1(2, "asc_srch_pci_dev: type %d\n", pciDevice->type); + + ret = asc_pci_find_dev(pciDevice); + ASC_DBG1(2, "asc_srch_pci_dev: asc_pci_find_dev() return %d\n", ret); + if (ret == PCI_DEVICE_FOUND) { + pciDevice->slotNumber = pciDevice->slotFound + 1; + pciDevice->startSlot = pciDevice->slotFound + 1; + } else { + if (pciDevice->bridge > pciDevice->busNumber) { + ASC_DBG2(2, "asc_srch_pci_dev: bridge %x, busNumber %x\n", + pciDevice->bridge, pciDevice->busNumber); + pciDevice->busNumber++; + pciDevice->slotNumber = 0; + pciDevice->startSlot = 0; + pciDevice->endSlot = 0x0f; + ret = asc_srch_pci_dev(pciDevice); + ASC_DBG1(2, "asc_srch_pci_dev: recursive call return %d\n", ret); + } + } + ASC_DBG1(2, "asc_srch_pci_dev: return %d\n", ret); + return ret; } +/* + * Determine the access method to be used for 'pciDevice'. + */ ASC_INITFUNC( -STATIC void -AscSetISAPNPWaitForKey( - void) +STATIC uchar +asc_scan_method(void) ) { - outp(ASC_ISA_PNP_PORT_ADDR, 0x02); - outp(ASC_ISA_PNP_PORT_WRITE, 0x02); - return; + ushort data; + PCI_DATA pciData; + uchar type; + uchar slot; + + ASC_DBG(2, "asc_scan_method: begin\n"); + memset(&pciData, 0, sizeof(pciData)); + for (type = 1; type < 3; type++) { + pciData.type = type; + for (slot = 0; slot < PCI_MAX_SLOT; slot++) { + pciData.slot = slot; + data = asc_get_cfg_word(&pciData); + if ((data != 0xFFFF) && (data != 0x0000)) { + ASC_DBG2(4, "asc_scan_method: data %x, type %d\n", data, type); + return (type); + } + } + } + ASC_DBG1(4, "asc_scan_method: type %d\n", type); + return (type); } +/* + * Check for an AdvanSys PCI device in 'pciDevice'. + * + * Return PCI_DEVICE_FOUND if found, otherwise return PCI_DEVICE_NOT_FOUND. + */ ASC_INITFUNC( -STATIC uchar -AscGetChipIRQ( - PortAddr iop_base, - ushort bus_type -) +STATIC int +asc_pci_find_dev(PCI_DEVICE *pciDevice) ) { - 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); - if ((chip_irq == 13) || (chip_irq > 15)) { - return (0); - } - return (chip_irq); - } - if ((bus_type & ASC_IS_VL) != 0) { - cfg_lsw = AscGetChipCfgLsw(iop_base); - chip_irq = (uchar) (((cfg_lsw >> 2) & 0x07)); - if ((chip_irq == 0) || - (chip_irq == 4) || - (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); - chip_irq = (uchar) (((cfg_lsw >> 2) & 0x03)); - if (chip_irq == 3) - chip_irq += (uchar) 2; - return ((uchar) (chip_irq + ASC_MIN_IRQ_NO)); -} + PCI_DATA pciData; + ushort vendorid, deviceid; + uchar classcode, subclass; + uchar lslot; -ASC_INITFUNC( -STATIC uchar -AscSetChipIRQ( - PortAddr iop_base, - uchar irq_no, - ushort bus_type -) -) -{ - 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; + ASC_DBG(3, "asc_pci_find_dev: begin\n"); + pciData.type = pciDevice->type; + pciData.bus = pciDevice->busNumber; + pciData.func = pciDevice->devFunc; + lslot = pciDevice->startSlot; + for (; lslot < pciDevice->endSlot; lslot++) { + pciData.slot = lslot; + pciData.offset = VENDORID_OFFSET; + vendorid = asc_get_cfg_word(&pciData); + ASC_DBG1(3, "asc_pci_find_dev: vendorid %x\n", vendorid); + if (vendorid != 0xffff) { + pciData.offset = DEVICEID_OFFSET; + deviceid = asc_get_cfg_word(&pciData); + ASC_DBG1(3, "asc_pci_find_dev: deviceid %x\n", deviceid); + 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_2300))) { + pciDevice->slotFound = lslot; + ASC_DBG(3, "asc_pci_find_dev: PCI_DEVICE_FOUND\n"); + return PCI_DEVICE_FOUND; } else { - irq_no -= (uchar) ((ASC_MIN_IRQ_NO - 1)); + pciData.offset = SUBCLASS_OFFSET; + subclass = asc_get_cfg_byte(&pciData); + pciData.offset = CLASSCODE_OFFSET; + classcode = asc_get_cfg_byte(&pciData); + if ((classcode & PCI_BASE_CLASS_BRIDGE_DEVICE) && + (subclass & PCI_SUB_CLASS_PCI_TO_PCI_BRIDGE_CONTROLLER)) { + pciDevice->bridge++; + } + ASC_DBG2(3, "asc_pci_find_dev: subclass %x, classcode %x\n", + subclass, classcode); } } - cfg_lsw = (ushort) (AscGetChipCfgLsw(iop_base) & 0xFFE3); - cfg_lsw |= (ushort) 0x0010; - AscSetChipCfgLsw(iop_base, cfg_lsw); - AscToggleIRQAct(iop_base); - cfg_lsw = (ushort) (AscGetChipCfgLsw(iop_base) & 0xFFE0); - cfg_lsw |= (ushort) ((irq_no & 0x07) << 2); - AscSetChipCfgLsw(iop_base, cfg_lsw); - AscToggleIRQAct(iop_base); - return (AscGetChipIRQ(iop_base, bus_type)); - } - if ((bus_type & (ASC_IS_ISA)) != 0) { - if (irq_no == 15) - irq_no -= (uchar) 2; - irq_no -= (uchar) ASC_MIN_IRQ_NO; - cfg_lsw = (ushort) (AscGetChipCfgLsw(iop_base) & 0xFFF3); - cfg_lsw |= (ushort) ((irq_no & 0x03) << 2); - AscSetChipCfgLsw(iop_base, cfg_lsw); - return (AscGetChipIRQ(iop_base, bus_type)); } - return (0); + return PCI_DEVICE_NOT_FOUND; } +/* + * Read PCI configuration data into 'pciConfig'. + */ ASC_INITFUNC( STATIC void -AscEnableIsaDma( - uchar dma_channel -) +asc_get_pci_cfg(PCI_DEVICE *pciDevice, PCI_CONFIG_SPACE *pciConfig) ) { - if (dma_channel < 4) { - outp(0x000B, (ushort) (0xC0 | dma_channel)); - outp(0x000A, dma_channel); - } else if (dma_channel < 8) { - outp(0x00D6, (ushort) (0xC0 | (dma_channel - 4))); - outp(0x00D4, (ushort) (dma_channel - 4)); + PCI_DATA pciData; + uchar counter; + uchar *localConfig; + + ASC_DBG1(4, "asc_get_pci_cfg: slot found - %d\n ", + pciDevice->slotFound); + + pciData.type = pciDevice->type; + pciData.bus = pciDevice->busNumber; + pciData.slot = pciDevice->slotFound; + pciData.func = pciDevice->devFunc; + localConfig = (uchar *) pciConfig; + + for (counter = 0; counter < sizeof(PCI_CONFIG_SPACE); counter++) { + pciData.offset = counter; + *localConfig = asc_get_cfg_byte(&pciData); + ASC_DBG1(4, "asc_get_pci_cfg: byte %x\n", *localConfig); + localConfig++; } - return; + ASC_DBG1(4, "asc_get_pci_cfg: counter %d\n", counter); } -STATIC int -AscIsrChipHalted( - REG ASC_DVC_VAR asc_ptr_type * asc_dvc +/* + * Read a word (16 bits) from the PCI configuration space. + * + * The configuration mechanism is checked for the correct access method. + */ +ASC_INITFUNC( +STATIC ushort +asc_get_cfg_word(PCI_DATA *pciData) ) { - EXT_MSG ext_msg; - EXT_MSG out_msg; - ushort halt_q_addr; - int sdtr_accept; - ushort int_halt_code; - ASC_SCSI_BIT_ID_TYPE scsi_busy; - ASC_SCSI_BIT_ID_TYPE target_id; - PortAddr iop_base; - uchar tag_code; - uchar q_status; - uchar halt_qp; - uchar sdtr_data; - uchar target_ix; - uchar q_cntl, tid_no; - uchar cur_dvc_qng; - uchar asyn_sdtr; - uchar scsi_status; - asc_board_t *boardp; + ushort tmp; + ulong address; + ulong lbus = pciData->bus; + ulong lslot = pciData->slot; + ulong lfunc = pciData->func; + uchar t2CFA, t2CF8; + ulong t1CF8, t1CFC; - ASC_ASSERT(asc_dvc->drv_ptr != 0); - boardp = (asc_board_t *) asc_dvc->drv_ptr; + ASC_DBG4(4, "asc_get_cfg_word: type %d, bus %lu, slot %lu, func %lu\n", + pciData->type, lbus, lslot, lfunc); - iop_base = asc_dvc->iop_base; - int_halt_code = AscReadLramWord(iop_base, ASCV_HALTCODE_W); + /* + * Check type of configuration mechanism. + */ + if (pciData->type == 2) { + /* + * Save registers to be restored later. + */ + t2CFA = inp(0xCFA); /* save PCI bus register */ + t2CF8 = inp(0xCF8); /* save config space enable register */ - halt_qp = AscReadLramByte(iop_base, ASCV_CURCDB_B); - halt_q_addr = ASC_QNO_TO_QADDR(halt_qp); - target_ix = AscReadLramByte(iop_base, - (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_TARGET_IX)); - q_cntl = AscReadLramByte(iop_base, - (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_CNTL)); - tid_no = ASC_TIX_TO_TID(target_ix); - target_id = (uchar) ASC_TID_TO_TARGET_ID(tid_no); - if (asc_dvc->pci_fix_asyn_xfer & target_id) { + /* + * Write the bus and enable registers. + */ + /* set for type 1 cycle, if needed */ + outp(0xCFA, pciData->bus); + /* set the function number */ + outp(0xCF8, 0x10 | (pciData->func << 1)) ; - asyn_sdtr = ASYN_SDTR_DATA_FIX_PCI_REV_AB; + /* + * Read the configuration space type 2 locations. + */ + tmp = (ushort) inpw(0xC000 | ((pciData->slot << 8) + pciData->offset)); + + outp(0xCFA, t2CFA); /* save PCI bus register */ + outp(0xCF8, t2CF8); /* save config space enable register */ } else { - asyn_sdtr = 0; - } - if (int_halt_code == ASC_HALT_DISABLE_ASYN_USE_SYN_FIX) { - if (asc_dvc->pci_fix_asyn_xfer & target_id) { - AscSetChipSDTR(iop_base, 0, tid_no); - boardp->sdtr_data[tid_no] = 0; - } - AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0); - return (0); - } else if (int_halt_code == ASC_HALT_ENABLE_ASYN_USE_SYN_FIX) { - if (asc_dvc->pci_fix_asyn_xfer & target_id) { - AscSetChipSDTR(iop_base, asyn_sdtr, tid_no); - boardp->sdtr_data[tid_no] = asyn_sdtr; - } - AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0); - return (0); - } else if (int_halt_code == ASC_HALT_EXTMSG_IN) { + /* + * Type 1 or 3 configuration mechanism. + * + * Save the CONFIG_ADDRESS and CONFIG_DATA register values. + */ + t1CF8 = inpl(0xCF8); + t1CFC = inpl(0xCFC); - AscMemWordCopyFromLram(iop_base, - ASCV_MSGIN_BEG, - (ushort *) & ext_msg, - (ushort) (sizeof (EXT_MSG) >> 1)); + /* + * enable <31>, bus = <23:16>, slot = <15:11>, + * func = <10:8>, reg = <7:2> + */ + address = (ulong) ((lbus << 16) | (lslot << 11) | + (lfunc << 8) | (pciData->offset & 0xFC) | 0x80000000L); - if (ext_msg.msg_type == MS_EXTEND && - ext_msg.msg_req == MS_SDTR_CODE && - ext_msg.msg_len == MS_SDTR_LEN) { - sdtr_accept = TRUE; - if ((ext_msg.req_ack_offset > ASC_SYN_MAX_OFFSET)) { + /* + * Write out the address to CONFIG_ADDRESS. + */ + outpl(0xCF8, address); - sdtr_accept = FALSE; - ext_msg.req_ack_offset = ASC_SYN_MAX_OFFSET; - } - if ((ext_msg.xfer_period < - asc_dvc->sdtr_period_tbl[asc_dvc->host_init_sdtr_index]) || - (ext_msg.xfer_period > - asc_dvc->sdtr_period_tbl[asc_dvc->max_sdtr_index])) { - sdtr_accept = FALSE; - ext_msg.xfer_period = - asc_dvc->sdtr_period_tbl[asc_dvc->host_init_sdtr_index]; - } - if (sdtr_accept) { - sdtr_data = AscCalSDTRData(asc_dvc, ext_msg.xfer_period, - ext_msg.req_ack_offset); - if ((sdtr_data == 0xFF)) { + /* + * Read in word from CONFIG_DATA. + */ + tmp = (ushort) ((inpl(0xCFC) >> + ((pciData->offset & 2) * 8)) & 0xFFFF); - q_cntl |= QC_MSG_OUT; - asc_dvc->init_sdtr &= ~target_id; - asc_dvc->sdtr_done &= ~target_id; - AscSetChipSDTR(iop_base, asyn_sdtr, tid_no); - boardp->sdtr_data[tid_no] = asyn_sdtr; - } - } - if (ext_msg.req_ack_offset == 0) { + /* + * Restore registers. + */ + outpl(0xCF8, t1CF8); + outpl(0xCFC, t1CFC); + } + ASC_DBG1(4, "asc_get_cfg_word: config data: %x\n", tmp); + return tmp; +} - q_cntl &= ~QC_MSG_OUT; - asc_dvc->init_sdtr &= ~target_id; - asc_dvc->sdtr_done &= ~target_id; - AscSetChipSDTR(iop_base, asyn_sdtr, tid_no); - } else { - if (sdtr_accept && (q_cntl & QC_MSG_OUT)) { +/* + * Reads a byte from the PCI configuration space. + * + * The configuration mechanism is checked for the correct access method. + */ +ASC_INITFUNC( +STATIC uchar +asc_get_cfg_byte(PCI_DATA *pciData) +) +{ + uchar tmp; + ulong address; + ulong lbus = pciData->bus, lslot = pciData->slot, lfunc = pciData->func; + uchar t2CFA, t2CF8; + ulong t1CF8, t1CFC; - q_cntl &= ~QC_MSG_OUT; - asc_dvc->sdtr_done |= target_id; - asc_dvc->init_sdtr |= target_id; - asc_dvc->pci_fix_asyn_xfer &= ~target_id; - sdtr_data = AscCalSDTRData(asc_dvc, ext_msg.xfer_period, - ext_msg.req_ack_offset); - AscSetChipSDTR(iop_base, sdtr_data, tid_no); - boardp->sdtr_data[tid_no] = sdtr_data; - } else { + ASC_DBG1(4, "asc_get_cfg_byte: type: %d\n", pciData->type); - q_cntl |= QC_MSG_OUT; - AscMsgOutSDTR(asc_dvc, - ext_msg.xfer_period, - ext_msg.req_ack_offset); - asc_dvc->pci_fix_asyn_xfer &= ~target_id; - sdtr_data = AscCalSDTRData(asc_dvc, ext_msg.xfer_period, - ext_msg.req_ack_offset); - AscSetChipSDTR(iop_base, sdtr_data, tid_no); - boardp->sdtr_data[tid_no] = sdtr_data; - asc_dvc->sdtr_done |= target_id; - asc_dvc->init_sdtr |= target_id; - } - } + /* + * Check type of configuration mechanism. + */ + if (pciData->type == 2) { + /* + * Save registers to be restored later. + */ + t2CFA = inp(0xCFA); /* save PCI bus register */ + t2CF8 = inp(0xCF8); /* save config space enable register */ - AscWriteLramByte(iop_base, - (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_CNTL), - q_cntl); - AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0); - return (0); - } else if (ext_msg.msg_type == MS_EXTEND && - ext_msg.msg_req == MS_WDTR_CODE && - ext_msg.msg_len == MS_WDTR_LEN) { + /* + * Write the bus and enable registers. + */ + /* set for type 1 cycle, if needed */ + outp(0xCFA, pciData->bus); + /* set the function number */ + outp(0xCF8, 0x10 | (pciData->func << 1)); - ext_msg.wdtr_width = 0; - AscMemWordCopyToLram(iop_base, - ASCV_MSGOUT_BEG, - (ushort *) & ext_msg, - (ushort) (sizeof (EXT_MSG) >> 1)); - q_cntl |= QC_MSG_OUT; - AscWriteLramByte(iop_base, - (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_CNTL), - q_cntl); - AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0); - return (0); - } else { + /* + * Read configuration space type 2 locations. + */ + tmp = inp(0xC000 | ((pciData->slot << 8) + pciData->offset)); - ext_msg.msg_type = M1_MSG_REJECT; - AscMemWordCopyToLram(iop_base, - ASCV_MSGOUT_BEG, - (ushort *) & ext_msg, - (ushort) (sizeof (EXT_MSG) >> 1)); - q_cntl |= QC_MSG_OUT; - AscWriteLramByte(iop_base, - (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_CNTL), - q_cntl); - AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0); - return (0); - } - } else if (int_halt_code == ASC_HALT_CHK_CONDITION) { + /* + * Restore registers. + */ + outp(0xCF8, t2CF8); /* restore the enable register */ + outp(0xCFA, t2CFA); /* restore PCI bus register */ + } else { + /* + * Type 1 or 3 configuration mechanism. + * + * Save CONFIG_ADDRESS and CONFIG_DATA register values. + */ + t1CF8 = inpl(0xCF8); + t1CFC = inpl(0xCFC); - q_cntl |= QC_REQ_SENSE; + /* + * enable <31>, bus = <23:16>, slot = <15:11>, func = <10:8>, + * reg = <7:2> + */ + address = (ulong) ((lbus << 16) | (lslot << 11) | + (lfunc << 8) | (pciData->offset & 0xFC) | 0x80000000L); -#if CC_CHK_COND_REDO_SDTR - if ((asc_dvc->init_sdtr & target_id) != 0) { + /* + * Write out address to CONFIG_ADDRESS. + */ + outpl(0xCF8, address); - asc_dvc->sdtr_done &= ~target_id; + /* + * Read in word from CONFIG_DATA. + */ + tmp = (uchar) ((inpl(0xCFC) >> ((pciData->offset & 3) * 8)) & 0xFF); - sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no); - q_cntl |= QC_MSG_OUT; - AscMsgOutSDTR(asc_dvc, - asc_dvc->sdtr_period_tbl[(sdtr_data >> 4) & - (uchar) (asc_dvc->max_sdtr_index - 1)], - (uchar) (sdtr_data & (uchar) ASC_SYN_MAX_OFFSET)); - } -#endif + /* + * Restore registers. + */ + outpl(0xCF8, t1CF8); + outpl(0xCFC, t1CFC); + } + ASC_DBG1(4, "asc_get_cfg_byte: config data: %x\n", tmp); + return tmp; +} - AscWriteLramByte(iop_base, - (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_CNTL), - q_cntl); +/* + * Write a byte to the PCI configuration space. + */ +ASC_INITFUNC( +STATIC void +asc_put_cfg_byte(PCI_DATA *pciData, uchar byte_data) +) +{ + ulong tmpl; + ulong address; + ulong lbus = pciData->bus, lslot = pciData->slot, lfunc = pciData->func; + uchar t2CFA, t2CF8; + ulong t1CF8, t1CFC; - tag_code = AscReadLramByte(iop_base, - (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_TAG_CODE)); - tag_code &= 0xDC; - if ( - (asc_dvc->pci_fix_asyn_xfer & target_id) - && !(asc_dvc->pci_fix_asyn_xfer_always & target_id) -) { + ASC_DBG2(4, "asc_put_cfg_byte: type: %d, byte_data %x\n", + pciData->type, byte_data); - tag_code |= (ASC_TAG_FLAG_DISABLE_DISCONNECT - | ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX); + /* + * Check type of configuration mechanism. + */ + if (pciData->type == 2) { - } - AscWriteLramByte(iop_base, - (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_TAG_CODE), - tag_code); + /* + * Save registers to be restored later. + */ + t2CFA = inp(0xCFA); /* save PCI bus register */ + t2CF8 = inp(0xCF8); /* save config space enable register */ - q_status = AscReadLramByte(iop_base, - (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_STATUS)); - q_status |= (QS_READY | QS_BUSY); - AscWriteLramByte(iop_base, - (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_STATUS), - q_status); + /* + * Write bus and enable registers. + */ + outp(0xCFA, pciData->bus); - scsi_busy = AscReadLramByte(iop_base, - (ushort) ASCV_SCSIBUSY_B); - scsi_busy &= ~target_id; - AscWriteLramByte(iop_base, (ushort) ASCV_SCSIBUSY_B, scsi_busy); + /* + * Set the function number. + */ + outp(0xCF8, 0x10 | (pciData->func << 1)); - AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0); - return (0); - } else if (int_halt_code == ASC_HALT_SDTR_REJECTED) { + /* + * Write the configuration space type 2 locations. + */ + outp(0xC000 | ((pciData->slot << 8) + pciData->offset), byte_data); - AscMemWordCopyFromLram(iop_base, - ASCV_MSGOUT_BEG, - (ushort *) & out_msg, - (ushort) (sizeof (EXT_MSG) >> 1)); + /* + * Restore registers. + */ + outp(0xCF8, t2CF8); /* restore the enable register */ + outp(0xCFA, t2CFA); /* restore PCI bus register */ + } else { - if ((out_msg.msg_type == MS_EXTEND) && - (out_msg.msg_len == MS_SDTR_LEN) && - (out_msg.msg_req == MS_SDTR_CODE)) { + /* + * Type 1 or 3 configuration mechanism. + * + * Save the CONFIG_ADDRESS and CONFIG_DATA register values. + */ + t1CF8 = inpl(0xCF8); + t1CFC = inpl(0xCFC); - asc_dvc->init_sdtr &= ~target_id; - asc_dvc->sdtr_done &= ~target_id; - AscSetChipSDTR(iop_base, asyn_sdtr, tid_no); - boardp->sdtr_data[tid_no] = asyn_sdtr; + /* + * enable <31>, bus = <23:16>, slot = <15:11>, func = <10:8>, + * reg = <7:2> + */ + address = (ulong) ((lbus << 16) | (lslot << 11) | (lfunc << 8) | + (pciData->offset & 0xFC) | 0x80000000L); + /* + * Write out address to CONFIG_ADDRESS. + */ + outpl(0xCF8, address); + + /* + * Write double word to CONFIG_DATA preserving the bytes + * in the double not written. + */ + tmpl = inpl(0xCFC) & ~(0xFF << ((pciData->offset & 3) * 8)); + outpl(0xCFC, tmpl | (byte_data << ((pciData->offset & 3) * 8))); + + /* + * Restore registers. + */ + outpl(0xCF8, t1CF8); + outpl(0xCFC, t1CFC); + } + ASC_DBG(4, "asc_put_cfg_byte: end\n"); +} + +/* + * Add a 'REQP' to the end of specified queue. Set 'tidmask' + * to indicate a command is queued for the device. + * + * 'flag' may be either ASC_FRONT or ASC_BACK. + * + * 'REQPNEXT(reqp)' returns reqp's next pointer. + */ +STATIC void +asc_enqueue(asc_queue_t *ascq, REQP reqp, int flag) +{ + int tid; + + 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 <= ADV_MAX_TID); + if (flag == ASC_FRONT) { + REQPNEXT(reqp) = ascq->q_first[tid]; + ascq->q_first[tid] = reqp; + /* If the queue was empty, set the last pointer. */ + if (ascq->q_last[tid] == NULL) { + ascq->q_last[tid] = reqp; } - q_cntl &= ~QC_MSG_OUT; - AscWriteLramByte(iop_base, - (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_CNTL), - q_cntl); - AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0); - return (0); - } else if (int_halt_code == ASC_HALT_SS_QUEUE_FULL) { + } else { /* ASC_BACK */ + if (ascq->q_last[tid] != NULL) { + REQPNEXT(ascq->q_last[tid]) = reqp; + } + ascq->q_last[tid] = reqp; + REQPNEXT(reqp) = NULL; + /* If the queue was empty, set the first pointer. */ + if (ascq->q_first[tid] == NULL) { + ascq->q_first[tid] = reqp; + } + } + /* The queue has at least one entry, set its bit. */ + ascq->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(2, "asc_enqueue: new q_max_cnt[%d] %d\n", + tid, ascq->q_max_cnt[tid]); + } + REQPTIME(reqp) = REQTIMESTAMP(); +#endif /* ADVANSYS_STATS */ + ASC_DBG1(3, "asc_enqueue: reqp %x\n", (unsigned) reqp); + return; +} - scsi_status = AscReadLramByte(iop_base, - (ushort) ((ushort) halt_q_addr + (ushort) ASC_SCSIQ_SCSI_STATUS)); - cur_dvc_qng = AscReadLramByte(iop_base, - (ushort) ((ushort) ASC_QADR_BEG + (ushort) target_ix)); - if ((cur_dvc_qng > 0) && - (asc_dvc->cur_dvc_qng[tid_no] > 0)) { +/* + * Return first queued 'REQP' on the specified queue for + * the specified target device. Clear the 'tidmask' bit for + * the device if no more commands are left queued for it. + * + * 'REQPNEXT(reqp)' returns reqp's next pointer. + */ +STATIC REQP +asc_dequeue(asc_queue_t *ascq, int tid) +{ + REQP reqp; - scsi_busy = AscReadLramByte(iop_base, - (ushort) ASCV_SCSIBUSY_B); - scsi_busy |= target_id; - AscWriteLramByte(iop_base, - (ushort) ASCV_SCSIBUSY_B, scsi_busy); - asc_dvc->queue_full_or_busy |= target_id; + ASC_DBG2(3, "asc_dequeue: ascq %x, tid %d\n", (unsigned) ascq, tid); + ASC_ASSERT(interrupts_enabled() == ASC_FALSE); + ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID); + if ((reqp = ascq->q_first[tid]) != NULL) { + 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 &= ~ADV_TID_TO_TIDMASK(tid); + ASC_ASSERT(ascq->q_last[tid] == reqp); + ascq->q_last[tid] = NULL; + } +#ifdef ADVANSYS_STATS + /* Maintain request queue statistics. */ + ascq->q_cur_cnt[tid]--; + ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0); + REQTIMESTAT("asc_dequeue", ascq, reqp, tid); +#endif /* ADVANSYS_STATS */ + } + ASC_DBG1(3, "asc_dequeue: reqp %x\n", (unsigned) reqp); + return reqp; +} - if (scsi_status == SS_QUEUE_FULL) { - if (cur_dvc_qng > ASC_MIN_TAGGED_CMD) { - cur_dvc_qng -= 1; - asc_dvc->max_dvc_qng[tid_no] = cur_dvc_qng; +/* + * Return a pointer to a singly linked list of all the requests queued + * for 'tid' on the 'asc_queue_t' pointed to by 'ascq'. + * + * If 'lastpp' is not NULL, '*lastpp' will be set to point to the + * the last request returned in the singly linked list. + * + * 'tid' should either be a valid target id or if it is ASC_TID_ALL, + * then all queued requests are concatenated into one list and + * returned. + * + * Note: If 'lastpp' is used to append a new list to the end of + * an old list, only change the old list last pointer if '*lastpp' + * (or the function return value) is not NULL, i.e. use a temporary + * variable for 'lastpp' and check its value after the function return + * before assigning it to the list last pointer. + * + * Unfortunately collecting queuing time statistics adds overhead to + * the function that isn't inherent to the function's algorithm. + */ +STATIC REQP +asc_dequeue_list(asc_queue_t *ascq, REQP *lastpp, int tid) +{ + REQP firstp, lastp; + int i; - AscWriteLramByte(iop_base, - (ushort) ((ushort) ASCV_MAX_DVC_QNG_BEG + - (ushort) tid_no), - cur_dvc_qng); + 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 <= ADV_MAX_TID)); - /* - * Set the device queue depth to the number of - * active requests when the QUEUE FULL condition - * was encountered. - */ - 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 > - cur_dvc_qng) { - boardp->device[tid_no]->queue_curr_depth = - cur_dvc_qng; - } -#endif /* ASC_QUEUE_FLOW_CONTROL */ + /* + * If 'tid' is not ASC_TID_ALL, return requests only for + * the specified 'tid'. If 'tid' is ASC_TID_ALL, return all + * requests for all tids. + */ + if (tid != ASC_TID_ALL) { + /* Return all requests for the specified 'tid'. */ + if ((ascq->q_tidmask & 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 &= ~ADV_TID_TO_TIDMASK(tid); +#ifdef ADVANSYS_STATS + { + REQP reqp; + ascq->q_cur_cnt[tid] = 0; + for (reqp = firstp; reqp; reqp = REQPNEXT(reqp)) { + REQTIMESTAT("asc_dequeue_list", ascq, reqp, tid); } } +#endif /* ADVANSYS_STATS */ } - AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0); - return (0); + } else { + /* Return all requests for all tids. */ + firstp = lastp = NULL; + 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]; + } else { + ASC_ASSERT(lastp != NULL); + REQPNEXT(lastp) = ascq->q_first[i]; + lastp = ascq->q_last[i]; + } + ascq->q_first[i] = ascq->q_last[i] = NULL; + ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(i); +#ifdef ADVANSYS_STATS + ascq->q_cur_cnt[i] = 0; +#endif /* ADVANSYS_STATS */ + } + } +#ifdef ADVANSYS_STATS + { + REQP reqp; + for (reqp = firstp; reqp; reqp = REQPNEXT(reqp)) { + REQTIMESTAT("asc_dequeue_list", ascq, reqp, reqp->target); + } + } +#endif /* ADVANSYS_STATS */ } - return (0); + if (lastpp) { + *lastpp = lastp; + } + ASC_DBG1(3, "asc_dequeue_list: firstp %x\n", (unsigned) firstp); + return firstp; } -STATIC uchar -_AscCopyLramScsiDoneQ( - PortAddr iop_base, - ushort q_addr, - REG ASC_QDONE_INFO * scsiq, - ulong max_dma_count -) +/* + * Remove the specified 'REQP' from the specified queue for + * the specified target device. Clear the 'tidmask' bit for the + * device if no more commands are left queued for it. + * + * 'REQPNEXT(reqp)' returns reqp's the next pointer. + * + * Return ASC_TRUE if the command was found and removed, + * otherwise return ASC_FALSE. + */ +STATIC int +asc_rmqueue(asc_queue_t *ascq, REQP reqp) { - 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; - scsiq->q_no = (uchar) (_val >> 8); - _val = AscReadLramWord(iop_base, - (ushort) (q_addr + (ushort) ASC_SCSIQ_B_CNTL)); - scsiq->cntl = (uchar) _val; - sg_queue_cnt = (uchar) (_val >> 8); - _val = AscReadLramWord(iop_base, - (ushort) (q_addr + (ushort) ASC_SCSIQ_B_SENSE_LEN)); - scsiq->sense_len = (uchar) _val; - scsiq->extra_bytes = (uchar) (_val >> 8); - scsiq->remain_bytes = AscReadLramWord(iop_base, - (ushort) (q_addr + (ushort) ASC_SCSIQ_DW_REMAIN_XFER_CNT)); - scsiq->remain_bytes &= max_dma_count; - return (sg_queue_cnt); -} + REQP currp, prevp; + int tid; + int ret = ASC_FALSE; -STATIC int -AscIsrQDone( - REG ASC_DVC_VAR asc_ptr_type * asc_dvc -) -{ - uchar next_qp; - uchar n_q_used; - uchar sg_list_qp; - uchar sg_queue_cnt; - uchar q_cnt; - uchar done_q_tail; - uchar tid_no; - ASC_SCSI_BIT_ID_TYPE scsi_busy; - ASC_SCSI_BIT_ID_TYPE target_id; - PortAddr iop_base; - ushort q_addr; - ushort sg_q_addr; - uchar cur_target_qng; - ASC_QDONE_INFO scsiq_buf; - 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; - scsiq = (ASC_QDONE_INFO *) & scsiq_buf; - done_q_tail = (uchar) AscGetVarDoneQTail(iop_base); - q_addr = ASC_QNO_TO_QADDR(done_q_tail); - next_qp = AscReadLramByte(iop_base, - (ushort) (q_addr + (ushort) ASC_SCSIQ_B_FWD)); - if (next_qp != ASC_QLINK_END) { - AscPutVarDoneQTail(iop_base, next_qp); - q_addr = ASC_QNO_TO_QADDR(next_qp); - sg_queue_cnt = _AscCopyLramScsiDoneQ(iop_base, q_addr, scsiq, - asc_dvc->max_dma_count); - AscWriteLramByte(iop_base, - (ushort) (q_addr + (ushort) ASC_SCSIQ_B_STATUS), - (uchar) (scsiq->q_status & (uchar) ~ (QS_READY | QS_ABORTED))); - tid_no = ASC_TIX_TO_TID(scsiq->d2.target_ix); - target_id = ASC_TIX_TO_TARGET_ID(scsiq->d2.target_ix); - if ((scsiq->cntl & QC_SG_HEAD) != 0) { - sg_q_addr = q_addr; - sg_list_qp = next_qp; - for (q_cnt = 0; q_cnt < sg_queue_cnt; q_cnt++) { - sg_list_qp = AscReadLramByte(iop_base, - (ushort) (sg_q_addr + (ushort) ASC_SCSIQ_B_FWD)); - sg_q_addr = ASC_QNO_TO_QADDR(sg_list_qp); - if (sg_list_qp == ASC_QLINK_END) { - AscSetLibErrorCode(asc_dvc, ASCQ_ERR_SG_Q_LINKS); - scsiq->d3.done_stat = QD_WITH_ERROR; - scsiq->d3.host_stat = QHSTA_D_QDONE_SG_LIST_CORRUPTED; - goto FATAL_ERR_QDONE; - } - AscWriteLramByte(iop_base, - (ushort) (sg_q_addr + (ushort) ASC_SCSIQ_B_STATUS), - QS_FREE); - } - n_q_used = sg_queue_cnt + 1; - AscPutVarDoneQTail(iop_base, sg_list_qp); - } - if (asc_dvc->queue_full_or_busy & target_id) { - cur_target_qng = AscReadLramByte(iop_base, - (ushort) ((ushort) ASC_QADR_BEG + (ushort) scsiq->d2.target_ix)); - if (cur_target_qng < asc_dvc->max_dvc_qng[tid_no]) { - scsi_busy = AscReadLramByte(iop_base, - (ushort) ASCV_SCSIBUSY_B); - scsi_busy &= ~target_id; - AscWriteLramByte(iop_base, - (ushort) ASCV_SCSIBUSY_B, scsi_busy); - asc_dvc->queue_full_or_busy &= ~target_id; - } - } - if (asc_dvc->cur_total_qng >= n_q_used) { - asc_dvc->cur_total_qng -= n_q_used; - if (asc_dvc->cur_dvc_qng[tid_no] != 0) { - asc_dvc->cur_dvc_qng[tid_no]--; - } - } else { - AscSetLibErrorCode(asc_dvc, ASCQ_ERR_CUR_QNG); - scsiq->d3.done_stat = QD_WITH_ERROR; - goto FATAL_ERR_QDONE; + 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 <= ADV_MAX_TID); + + /* + * Handle the common case of 'reqp' being the first + * entry on the queue. + */ + if (reqp == ascq->q_first[tid]) { + ret = ASC_TRUE; + ascq->q_first[tid] = REQPNEXT(reqp); + /* If the queue is now empty, clear its bit and the last pointer. */ + if (ascq->q_first[tid] == NULL) { + ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid); + ASC_ASSERT(ascq->q_last[tid] == reqp); + ascq->q_last[tid] = NULL; } - if ((scsiq->d2.srb_ptr == 0UL) || - ((scsiq->q_status & QS_ABORTED) != 0)) { - return (0x11); - } else if (scsiq->q_status == QS_DONE) { - false_overrun = FALSE; - if (scsiq->extra_bytes != 0) { - scsiq->remain_bytes += (ulong) scsiq->extra_bytes; - } - if (scsiq->d3.done_stat == QD_WITH_ERROR) { - if (scsiq->d3.host_stat == QHSTA_M_DATA_OVER_RUN) { - if ((scsiq->cntl & (QC_DATA_IN | QC_DATA_OUT)) == 0) { - scsiq->d3.done_stat = QD_NO_ERROR; - scsiq->d3.host_stat = QHSTA_NO_ERROR; - } else if (false_overrun) { - scsiq->d3.done_stat = QD_NO_ERROR; - scsiq->d3.host_stat = QHSTA_NO_ERROR; - } - } else if (scsiq->d3.host_stat == - QHSTA_M_HUNG_REQ_SCSI_BUS_RESET) { - AscStopChip(iop_base); - AscSetChipControl(iop_base, - (uchar) (CC_SCSI_RESET | CC_HALT)); - DvcDelayNanoSecond(asc_dvc, 30000); - 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 { - if ((AscReadLramByte(iop_base, - (ushort) (q_addr + (ushort) ASC_SCSIQ_CDB_BEG)) == - SCSICMD_StartStopUnit)) { - asc_dvc->unit_not_ready &= ~target_id; - if (scsiq->d3.done_stat != QD_NO_ERROR) { - asc_dvc->start_motor &= ~target_id; - } + } else if (ascq->q_first[tid] != NULL) { + ASC_ASSERT(ascq->q_last[tid] != NULL); + /* + * Because the case of 'reqp' being the first entry has been + * handled above and it is known the queue is not empty, if + * 'reqp' is found on the queue it is guaranteed the queue will + * not become empty and that 'q_first[tid]' will not be changed. + * + * Set 'prevp' to the first entry, 'currp' to the second entry, + * and search for 'reqp'. + */ + for (prevp = ascq->q_first[tid], currp = REQPNEXT(prevp); + currp; prevp = currp, currp = REQPNEXT(currp)) { + if (currp == reqp) { + ret = ASC_TRUE; + REQPNEXT(prevp) = REQPNEXT(currp); + REQPNEXT(reqp) = NULL; + if (ascq->q_last[tid] == reqp) { + ascq->q_last[tid] = prevp; } + break; } - return (1); - } else { - AscSetLibErrorCode(asc_dvc, ASCQ_ERR_Q_STATUS); - FATAL_ERR_QDONE: - if ((scsiq->cntl & QC_NO_CALLBACK) == 0) { - (*asc_isr_callback) (asc_dvc, scsiq); - } - return (0x80); } } - return (0); +#ifdef ADVANSYS_STATS + /* Maintain request queue statistics. */ + if (ret == ASC_TRUE) { + ascq->q_cur_cnt[tid]--; + REQTIMESTAT("asc_rmqueue", ascq, reqp, tid); + } + ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0); +#endif /* ADVANSYS_STATS */ + ASC_DBG2(3, "asc_rmqueue: reqp %x, ret %d\n", (unsigned) reqp, ret); + return ret; } +/* + * If the specified 'REQP' is queued on the specified queue for + * the specified target device, return ASC_TRUE. + */ STATIC int -AscISR( - REG ASC_DVC_VAR asc_ptr_type * asc_dvc -) +asc_isqueued(asc_queue_t *ascq, REQP reqp) { - ASC_CS_TYPE chipstat; - PortAddr iop_base; - ushort saved_ram_addr; - uchar ctrl_reg; - uchar saved_ctrl_reg; - 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) - || (asc_dvc->isr_callback == 0) -) { - return (ERR); - } - if (asc_dvc->in_critical_cnt != 0) { - AscSetLibErrorCode(asc_dvc, ASCQ_ERR_ISR_ON_CRITICAL); - return (ERR); - } - if (asc_dvc->is_in_int) { - AscSetLibErrorCode(asc_dvc, ASCQ_ERR_ISR_RE_ENTRY); - return (ERR); + REQP treqp; + int tid; + int ret = ASC_FALSE; + + 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 <= ADV_MAX_TID); + + for (treqp = ascq->q_first[tid]; treqp; treqp = REQPNEXT(treqp)) { + ASC_ASSERT(ascq->q_tidmask & ADV_TID_TO_TIDMASK(tid)); + if (treqp == reqp) { + ret = ASC_TRUE; + break; + } } - asc_dvc->is_in_int = TRUE; - ctrl_reg = AscGetChipControl(iop_base); - saved_ctrl_reg = ctrl_reg & (~(CC_SCSI_RESET | CC_CHIP_RESET | - CC_SINGLE_STEP | CC_DIAG | CC_TEST)); - chipstat = AscGetChipStatus(iop_base); - if (chipstat & CSW_SCSI_RESET_LATCH) { - if (!(asc_dvc->bus_type & (ASC_IS_VL | ASC_IS_EISA))) { - int_pending = TRUE; - asc_dvc->sdtr_done = 0; - saved_ctrl_reg &= (uchar) (~CC_HALT); - while (AscGetChipStatus(iop_base) & CSW_SCSI_RESET_ACTIVE) ; - AscSetChipControl(iop_base, (CC_CHIP_RESET | CC_HALT)); - AscSetChipControl(iop_base, CC_HALT); - AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT); - AscSetChipStatus(iop_base, 0); - chipstat = AscGetChipStatus(iop_base); - } - } - saved_ram_addr = AscGetChipLramAddr(iop_base); - host_flag = AscReadLramByte(iop_base, - 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)) { - if (AscIsrChipHalted(asc_dvc) == ERR) { - goto ISR_REPORT_QDONE_FATAL_ERROR; - } else { - saved_ctrl_reg &= (uchar) (~CC_HALT); - } - } else { - ISR_REPORT_QDONE_FATAL_ERROR: - if ((asc_dvc->dvc_cntl & ASC_CNTL_INT_MULTI_Q) != 0) { - while (((status = AscIsrQDone(asc_dvc)) & 0x01) != 0) { + ASC_DBG1(3, "asc_isqueued: ret %x\n", ret); + return ret; +} + +/* + * Execute as many queued requests as possible for the specified queue. + * + * Calls asc_execute_scsi_cmnd() to execute a REQP/Scsi_Cmnd. + */ +STATIC void +asc_execute_queue(asc_queue_t *ascq) +{ + ADV_SCSI_BIT_ID_TYPE scan_tidmask; + REQP reqp; + int i; + + ASC_DBG1(1, "asc_execute_queue: ascq %x\n", (unsigned) ascq); + ASC_ASSERT(interrupts_enabled() == ASC_FALSE); + /* + * Execute queued commands for devices attached to + * the current board in round-robin fashion. + */ + scan_tidmask = ascq->q_tidmask; + do { + 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 &= ~ADV_TID_TO_TIDMASK(i); + } else if (asc_execute_scsi_cmnd((Scsi_Cmnd *) reqp) + == ASC_BUSY) { + scan_tidmask &= ~ADV_TID_TO_TIDMASK(i); + /* Put the request back at front of the list. */ + asc_enqueue(ascq, reqp, ASC_FRONT); } - } else { - do { - if ((status = AscIsrQDone(asc_dvc)) == 1) { - break; - } - } while (status == 0x11); } - if ((status & 0x80) != 0) - int_pending = ERR; } -#if CC_ASCISR_CHECK_INT_PENDING + } while (scan_tidmask); + return; +} + +#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) +/* + * asc_prt_board_devices() + * + * Print driver information for devices attached to the board. + * + * 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_board_devices(struct Scsi_Host *shp, char *cp, int cplen) +{ + asc_board_t *boardp; + int leftlen; + int totlen; + int len; + int chip_scsi_id; + int i; + + boardp = ASC_BOARDP(shp); + leftlen = cplen; + totlen = len = 0; + + len = asc_prt_line(cp, leftlen, +"\nDevice Information for AdvanSys SCSI Host %d:\n", shp->host_no); + 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; + } + + len = asc_prt_line(cp, leftlen, "Target IDs Detected:"); + ASC_PRT_NEXT(); + 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(); + } } -#endif - AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag); - AscSetChipLramAddr(iop_base, saved_ram_addr); - AscSetChipControl(iop_base, saved_ctrl_reg); - asc_dvc->is_in_int = FALSE; - return (int_pending); + len = asc_prt_line(cp, leftlen, " (%X=Host Adapter)\n", chip_scsi_id); + ASC_PRT_NEXT(); + + return totlen; } +/* + * Display Wide Board BIOS Information. + */ STATIC int -AscScsiSetupCmdQ( - REG ASC_DVC_VAR asc_ptr_type * asc_dvc, - REG ASC_SCSI_REQ_Q * scsiq, - uchar * buf_addr, - ulong buf_len -) +asc_prt_adv_bios(struct Scsi_Host *shp, char *cp, int cplen) { - ulong phy_addr; - scsiq->r1.cntl = 0; - scsiq->r1.sg_queue_cnt = 0; - scsiq->r1.q_no = 0; - scsiq->r1.extra_bytes = 0; - scsiq->r3.scsi_stat = 0; - scsiq->r3.scsi_msg = 0; - scsiq->r3.host_stat = 0; - scsiq->r3.done_stat = 0; - scsiq->r2.vm_id = 0; - scsiq->r1.data_cnt = buf_len; - scsiq->cdbptr = (uchar *) scsiq->cdb; - scsiq->sense_ptr = (uchar *) scsiq->sense ; - scsiq->r1.sense_len = ASC_MIN_SENSE_LEN ; - scsiq->r2.tag_code = (uchar) M2_QTAG_MSG_SIMPLE; - scsiq->r2.flag = (uchar) ASC_FLAG_SCSIQ_REQ; - scsiq->r2.srb_ptr = (ulong) scsiq; - scsiq->r1.status = (uchar) QS_READY; - scsiq->r1.data_addr = 0L; - if (buf_len != 0L) { - if ((phy_addr = AscGetOnePhyAddr(asc_dvc, - (uchar *) buf_addr, scsiq->r1.data_cnt)) == 0L) { - return (ERR); + 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; } - scsiq->r1.data_addr = phy_addr; } - if ((phy_addr = AscGetOnePhyAddr(asc_dvc, - (uchar *) scsiq->sense_ptr, - (ulong) scsiq->r1.sense_len)) == 0L) { - return (ERR); + 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(); } - scsiq->r1.sense_addr = phy_addr ; - return (0); + + return totlen; } -STATIC uchar _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, -}; +/* + * 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; -STATIC ushort _mcode_size ASC_INITDATA = sizeof(_mcode_buf); -STATIC ulong _mcode_chksum ASC_INITDATA = 0x01297F32UL; + if ((serialnum[1] & 0xFE00) != ((ushort) 0xAA << 8)) { + return ASC_FALSE; + } else { + /* + * First word - 6 digits. + */ + w = serialnum[0]; -#define ASC_SYN_OFFSET_ONE_DISABLE_LIST 16 -STATIC uchar _syn_offset_one_disable_cmd[ASC_SYN_OFFSET_ONE_DISABLE_LIST] = -{ - SCSICMD_Inquiry, - SCSICMD_RequestSense, - SCSICMD_ReadCapacity, - SCSICMD_ReadTOC, - SCSICMD_ModeSelect6, - SCSICMD_ModeSense6, - SCSICMD_ModeSelect10, - SCSICMD_ModeSense10, - 0xFF, - 0xFF, - 0xFF, - 0xFF, - 0xFF, - 0xFF, - 0xFF, - 0xFF -}; + /* 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_asc_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 -AscExeScsiQueue( - REG ASC_DVC_VAR asc_ptr_type * asc_dvc, - REG ASC_SCSI_Q * scsiq -) +asc_prt_asc_board_eeprom(struct Scsi_Host *shp, char *cp, int cplen) { - PortAddr iop_base; - int last_int_level; - int sta; - int n_q_required; - int disable_syn_offset_one_fix; - int i; - ulong addr; - ASC_EXE_CALLBACK asc_exe_callback; - ushort sg_entry_cnt = 0; - ushort sg_entry_cnt_minus_one = 0; - uchar target_ix; - uchar tid_no; - uchar sdtr_data; - uchar extra_bytes; - uchar scsi_cmd; - 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; - if (asc_dvc->err_code != 0) - return (ERR); - if (scsiq == (ASC_SCSI_Q *) 0L) { - AscSetLibErrorCode(asc_dvc, ASCQ_ERR_SCSIQ_NULL_PTR); - return (ERR); - } - scsiq->q1.q_no = 0; - if ((scsiq->q2.tag_code & ASC_TAG_FLAG_EXTRA_BYTES) == 0) { - scsiq->q1.extra_bytes = 0; - } - sta = 0; - target_ix = scsiq->q2.target_ix; - tid_no = ASC_TIX_TO_TID(target_ix); - n_q_required = 1; - if (scsiq->cdbptr[0] == SCSICMD_RequestSense) { - if ((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) { - asc_dvc->sdtr_done &= ~scsiq->q1.target_id ; - sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no); - AscMsgOutSDTR(asc_dvc, - asc_dvc->sdtr_period_tbl[(sdtr_data >> 4) & - (uchar) (asc_dvc->max_sdtr_index - 1)], - (uchar) (sdtr_data & (uchar) ASC_SYN_MAX_OFFSET)); - scsiq->q1.cntl |= (QC_MSG_OUT | QC_URGENT); + asc_board_t *boardp; + ASC_DVC_VAR *asc_dvc_varp; + int leftlen; + int totlen; + int len; + ASCEEP_CONFIG *ep; + int i; + int isa_dma_speed[] = { 10, 8, 7, 6, 5, 4, 3, 2 }; + uchar serialstr[13]; + + boardp = ASC_BOARDP(shp); + asc_dvc_varp = &boardp->dvc_var.asc_dvc_var; + ep = &boardp->eep_config.asc_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((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(); } } - last_int_level = DvcEnterCritical(); - if (asc_dvc->in_critical_cnt != 0) { - DvcLeaveCritical(last_int_level); - AscSetLibErrorCode(asc_dvc, ASCQ_ERR_CRITICAL_RE_ENTRY); - return (ERR); + + 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", i); + ASC_PRT_NEXT(); } - asc_dvc->in_critical_cnt++; - if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) { - if ((sg_entry_cnt = sg_head->entry_cnt) == 0) { - asc_dvc->in_critical_cnt--; - DvcLeaveCritical(last_int_level); - return (ERR); - } - if (sg_entry_cnt > ASC_MAX_SG_LIST) { - return (ERR); - } - if (sg_entry_cnt == 1) { - scsiq->q1.data_addr = sg_head->sg_list[0].addr; - scsiq->q1.data_cnt = sg_head->sg_list[0].bytes; - 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 + 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(); } - scsi_cmd = scsiq->cdbptr[0]; - disable_syn_offset_one_fix = FALSE; - if ((asc_dvc->pci_fix_asyn_xfer & scsiq->q1.target_id) && - !(asc_dvc->pci_fix_asyn_xfer_always & scsiq->q1.target_id)) { - if (scsiq->q1.cntl & QC_SG_HEAD) { - data_cnt = 0; - for (i = 0; i < sg_entry_cnt; i++) { - data_cnt += sg_head->sg_list[i].bytes; - } - } else { - data_cnt = scsiq->q1.data_cnt; - } - if (data_cnt != 0UL) { - if (data_cnt < 512UL) { - disable_syn_offset_one_fix = TRUE; - } else { - for (i = 0; i < ASC_SYN_OFFSET_ONE_DISABLE_LIST; i++) { - disable_cmd = _syn_offset_one_disable_cmd[i]; - if (disable_cmd == 0xFF) { - break; - } - if (scsi_cmd == disable_cmd) { - disable_syn_offset_one_fix = TRUE; - break; - } - } - } - } + 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 <= ASC_MAX_TID; i++) { + len = asc_prt_line(cp, leftlen, " %c", + (ep->use_cmd_qng & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); + ASC_PRT_NEXT(); } - if (disable_syn_offset_one_fix) { - scsiq->q2.tag_code &= ~M2_QTAG_MSG_SIMPLE; - scsiq->q2.tag_code |= (ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX | - ASC_TAG_FLAG_DISABLE_DISCONNECT); - } else { - scsiq->q2.tag_code &= 0x23; + 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 <= ASC_MAX_TID; i++) { + len = asc_prt_line(cp, leftlen, " %c", + (ep->start_motor & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); + ASC_PRT_NEXT(); } - if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) { - if (asc_dvc->bug_fix_cntl) { - if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) { - if ((scsi_cmd == SCSICMD_Read6) || - (scsi_cmd == SCSICMD_Read10)) { - addr = sg_head->sg_list[sg_entry_cnt_minus_one].addr + - sg_head->sg_list[sg_entry_cnt_minus_one].bytes; - extra_bytes = (uchar) ((ushort) addr & 0x0003); - if ((extra_bytes != 0) && - ((scsiq->q2.tag_code & ASC_TAG_FLAG_EXTRA_BYTES) - == 0)) { - scsiq->q2.tag_code |= ASC_TAG_FLAG_EXTRA_BYTES; - scsiq->q1.extra_bytes = extra_bytes; - sg_head->sg_list[sg_entry_cnt_minus_one].bytes -= - (ulong) extra_bytes; - } - } - } - } - sg_head->entry_to_copy = sg_head->entry_cnt; - n_q_required = AscSgListToQueue(sg_entry_cnt); - if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, n_q_required) >= - (uint) n_q_required) || ((scsiq->q1.cntl & QC_URGENT) != 0)) { - if ((sta = AscSendScsiQueue(asc_dvc, scsiq, - n_q_required)) == 1) { - asc_dvc->in_critical_cnt--; - if (asc_exe_callback != 0) { - (*asc_exe_callback) (asc_dvc, scsiq); - } - DvcLeaveCritical(last_int_level); - return (sta); - } - } - } else { - if (asc_dvc->bug_fix_cntl) { - if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) { - if ((scsi_cmd == SCSICMD_Read6) || - (scsi_cmd == SCSICMD_Read10)) { - addr = scsiq->q1.data_addr + scsiq->q1.data_cnt; - extra_bytes = (uchar) ((ushort) addr & 0x0003); - if ((extra_bytes != 0) && - ((scsiq->q2.tag_code & ASC_TAG_FLAG_EXTRA_BYTES) - == 0)) { - if (((ushort) scsiq->q1.data_cnt & 0x01FF) == 0) { - scsiq->q2.tag_code |= ASC_TAG_FLAG_EXTRA_BYTES; - scsiq->q1.data_cnt -= (ulong) extra_bytes; - scsiq->q1.extra_bytes = extra_bytes; - } - } - } - } - } - n_q_required = 1; - if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, 1) >= 1) || - ((scsiq->q1.cntl & QC_URGENT) != 0)) { - if ((sta = AscSendScsiQueue(asc_dvc, scsiq, - n_q_required)) == 1) { - asc_dvc->in_critical_cnt--; - if (asc_exe_callback != 0) { - (*asc_exe_callback) (asc_dvc, scsiq); - } - DvcLeaveCritical(last_int_level); - return (sta); - } - } + 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 <= ASC_MAX_TID; i++) { + len = asc_prt_line(cp, leftlen, " %c", + (ep->init_sdtr & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); + ASC_PRT_NEXT(); } - asc_dvc->in_critical_cnt--; - DvcLeaveCritical(last_int_level); - return (sta); + len = asc_prt_line(cp, leftlen, "\n"); + ASC_PRT_NEXT(); + + if (asc_dvc_varp->bus_type & ASC_IS_ISA) { + len = asc_prt_line(cp, leftlen, +" Host ISA DMA speed: %d MB/S\n", + isa_dma_speed[ep->isa_dma_speed]); + ASC_PRT_NEXT(); + } + + return totlen; } +/* + * 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 -AscSendScsiQueue( - REG ASC_DVC_VAR asc_ptr_type * asc_dvc, - REG ASC_SCSI_Q * scsiq, - uchar n_q_required -) +asc_prt_adv_board_eeprom(struct Scsi_Host *shp, char *cp, int cplen) { - PortAddr iop_base; - uchar free_q_head; - uchar next_qp; - 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); - sta = 0; - free_q_head = (uchar) AscGetVarFreeQHead(iop_base); - if (n_q_required > 1) { - if ((next_qp = AscAllocMultipleFreeQueue(iop_base, - free_q_head, (uchar) (n_q_required))) - != (uchar) ASC_QLINK_END) { - asc_dvc->last_q_shortage = 0; - scsiq->sg_head->queue_cnt = n_q_required - 1; - 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]++; - } - return (sta); - } - } else if (n_q_required == 1) { - if ((next_qp = AscAllocFreeQueue(iop_base, - free_q_head)) != ASC_QLINK_END) { - 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]++; - } - return (sta); - } + 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(); } - return (sta); -} -STATIC int -AscSgListToQueue( - int sg_list -) -{ - 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++; - return (n_sg_list_qs + 1); -} + 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; + } -STATIC uint -AscGetNumOfFreeQueue( - REG ASC_DVC_VAR asc_ptr_type * asc_dvc, - uchar target_ix, - uchar n_qs -) -{ - uint cur_used_qs; - 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) || - (asc_dvc->queue_full_or_busy & target_id)) { - return (0); + 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(); } - if (n_qs == 1) { - cur_used_qs = (uint) asc_dvc->cur_total_qng + - (uint) asc_dvc->last_q_shortage + - (uint) ASC_MIN_FREE_Q; - } else { - cur_used_qs = (uint) asc_dvc->cur_total_qng + - (uint) ASC_MIN_FREE_Q; + 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(); } - if ((uint) (cur_used_qs + n_qs) <= (uint) asc_dvc->max_total_qng) { - cur_free_qs = (uint) asc_dvc->max_total_qng - cur_used_qs; - if (asc_dvc->cur_dvc_qng[tid_no] >= - asc_dvc->max_dvc_qng[tid_no]) { - return (0); - } - return (cur_free_qs); + 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(); } - if (n_qs > 1) { - if ((n_qs > asc_dvc->last_q_shortage) && (n_qs <= (asc_dvc->max_total_qng - ASC_MIN_FREE_Q))) { - asc_dvc->last_q_shortage = n_qs; - } + 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(); } - return (0); -} + len = asc_prt_line(cp, leftlen, "\n"); + ASC_PRT_NEXT(); -STATIC int -AscPutReadyQueue( - REG ASC_DVC_VAR asc_ptr_type * asc_dvc, - REG ASC_SCSI_Q * scsiq, - uchar q_no -) -{ - ushort q_addr; - uchar tid_no; - uchar sdtr_data; - 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)) { - tid_no = ASC_TIX_TO_TID(scsiq->q2.target_ix); - sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no); - syn_period_ix = (sdtr_data >> 4) & (asc_dvc->max_sdtr_index - 1); - syn_offset = sdtr_data & ASC_SYN_MAX_OFFSET; - AscMsgOutSDTR(asc_dvc, - asc_dvc->sdtr_period_tbl[syn_period_ix], - syn_offset); - scsiq->q1.cntl |= QC_MSG_OUT; + 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(); } - q_addr = ASC_QNO_TO_QADDR(q_no); - if ((scsiq->q1.target_id & asc_dvc->use_tagged_qng) == 0) { - scsiq->q2.tag_code &= ~M2_QTAG_MSG_SIMPLE; + 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(); } - scsiq->q1.status = QS_FREE; - AscMemWordCopyToLram(iop_base, - (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); - } + 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(); } -#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)); - return (1); + 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, + * cf. asc_prt_line(). + * + * Return the number of characters copied into 'cp'. No more than + * 'cplen' characters will be copied to 'cp'. + */ STATIC int -AscPutReadySgListQueue( - REG ASC_DVC_VAR asc_ptr_type * asc_dvc, - REG ASC_SCSI_Q * scsiq, - uchar q_no -) +asc_prt_driver_conf(struct Scsi_Host *shp, char *cp, int cplen) { - int sta; - int i; - ASC_SG_HEAD *sg_head; - ASC_SG_LIST_Q scsi_sg_q; - ulong saved_data_addr; - ulong saved_data_cnt; - PortAddr iop_base; - ushort sg_list_dwords; - ushort sg_index; - 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; - saved_data_cnt = scsiq->q1.data_cnt; - scsiq->q1.data_addr = sg_head->sg_list[0].addr; - scsiq->q1.data_cnt = sg_head->sg_list[0].bytes; - sg_entry_cnt = sg_head->entry_cnt - 1; - if (sg_entry_cnt != 0) { - scsiq->q1.cntl |= QC_SG_HEAD; - q_addr = ASC_QNO_TO_QADDR(q_no); - sg_index = 1; - scsiq->q1.sg_queue_cnt = sg_head->queue_cnt; - scsi_sg_q.sg_head_qp = q_no; - scsi_sg_q.cntl = QCSG_SG_XFER_LIST; - for (i = 0; i < sg_head->queue_cnt; i++) { - scsi_sg_q.seq_no = i + 1; - if (sg_entry_cnt > ASC_SG_LIST_PER_Q) { - sg_list_dwords = (uchar) (ASC_SG_LIST_PER_Q * 2); - sg_entry_cnt -= ASC_SG_LIST_PER_Q; - if (i == 0) { - scsi_sg_q.sg_list_cnt = ASC_SG_LIST_PER_Q; - scsi_sg_q.sg_cur_list_cnt = ASC_SG_LIST_PER_Q; - } else { - scsi_sg_q.sg_list_cnt = ASC_SG_LIST_PER_Q - 1; - scsi_sg_q.sg_cur_list_cnt = ASC_SG_LIST_PER_Q - 1; - } - } else { - scsi_sg_q.cntl |= QCSG_SG_XFER_END; - sg_list_dwords = sg_entry_cnt << 1; - if (i == 0) { - scsi_sg_q.sg_list_cnt = sg_entry_cnt; - scsi_sg_q.sg_cur_list_cnt = sg_entry_cnt; - } else { - scsi_sg_q.sg_list_cnt = sg_entry_cnt - 1; - scsi_sg_q.sg_cur_list_cnt = sg_entry_cnt - 1; - } - sg_entry_cnt = 0; - } - next_qp = AscReadLramByte(iop_base, - (ushort) (q_addr + ASC_SCSIQ_B_FWD)); - scsi_sg_q.q_no = next_qp; - q_addr = ASC_QNO_TO_QADDR(next_qp); - AscMemWordCopyToLram(iop_base, - (ushort) (q_addr + ASC_SCSIQ_SGHD_CPY_BEG), - (ushort *) & scsi_sg_q, - (ushort) (sizeof (ASC_SG_LIST_Q) >> 1)); - AscMemDWordCopyToLram(iop_base, - (ushort) (q_addr + ASC_SGQ_LIST_BEG), - (ulong *) & sg_head->sg_list[sg_index], - (ushort) sg_list_dwords); - sg_index += ASC_SG_LIST_PER_Q; - } - } else { - scsiq->q1.cntl &= ~QC_SG_HEAD; - } - sta = AscPutReadyQueue(asc_dvc, scsiq, q_no); - scsiq->q1.data_addr = saved_data_addr; - scsiq->q1.data_cnt = saved_data_cnt; - return (sta); -} + asc_board_t *boardp; + 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 */ -STATIC int -AscAbortSRB( - REG ASC_DVC_VAR asc_ptr_type * asc_dvc, - ulong srb_ptr -) -{ - 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; - asc_dvc->unit_not_ready = 0xFF; - AscWaitISRDone(asc_dvc); - if (AscStopQueueExe(iop_base) == 1) { - if (AscRiscHaltedAbortSRB(asc_dvc, srb_ptr) == 1) { - sta = 1; - AscCleanUpBusyQueue(iop_base); - AscStartQueueExe(iop_base); - } else { - sta = 0; - AscStartQueueExe(iop_base); - } + boardp = ASC_BOARDP(shp); + + leftlen = cplen; + totlen = len = 0; + + len = asc_prt_line(cp, leftlen, +"\nLinux Driver Configuration and Information for AdvanSys SCSI Host %d:\n", + shp->host_no); + ASC_PRT_NEXT(); + + len = asc_prt_line(cp, leftlen, +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,89) +" host_busy %u, last_reset %u, max_id %u, max_lun %u\n", + shp->host_busy, shp->last_reset, shp->max_id, shp->max_lun); +#else /* version >= v1.3.89 */ +" host_busy %u, last_reset %u, max_id %u, max_lun %u, max_channel %u\n", + shp->host_busy, shp->last_reset, shp->max_id, shp->max_lun, + shp->max_channel); +#endif /* version >= v1.3.89 */ + ASC_PRT_NEXT(); + + len = asc_prt_line(cp, leftlen, +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,57) +" can_queue %d, this_id %d, sg_tablesize %u, cmd_per_lun %u\n", + shp->can_queue, shp->this_id, shp->sg_tablesize, shp->cmd_per_lun); +#else /* version >= v1.3.57 */ +" unique_id %d, can_queue %d, this_id %d, sg_tablesize %u, cmd_per_lun %u\n", + shp->unique_id, shp->can_queue, shp->this_id, shp->sg_tablesize, + shp->cmd_per_lun); +#endif /* version >= v1.3.57 */ + ASC_PRT_NEXT(); + + len = asc_prt_line(cp, leftlen, +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,57) +" unchecked_isa_dma %d, loaded_as_module %d\n", + shp->unchecked_isa_dma, shp->loaded_as_module); +#else /* version >= v1.3.57 */ +" unchecked_isa_dma %d, use_clustering %d, loaded_as_module %d\n", + shp->unchecked_isa_dma, shp->use_clustering, shp->loaded_as_module); +#endif /* version >= v1.3.57 */ + ASC_PRT_NEXT(); + + 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; } - asc_dvc->unit_not_ready = saved_unit_not_ready; - return (sta); -} #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) -STATIC int -AscResetDevice( - REG ASC_DVC_VAR asc_ptr_type * asc_dvc, - uchar target_ix -) -{ - PortAddr iop_base; - int sta; - uchar tid_no; - ASC_SCSI_BIT_ID_TYPE target_id; - int i; - ASC_SCSI_REQ_Q scsiq_buf; - ASC_SCSI_REQ_Q *scsiq; - uchar *buf; - ASC_SCSI_BIT_ID_TYPE saved_unit_not_ready; - iop_base = asc_dvc->iop_base; - tid_no = ASC_TIX_TO_TID(target_ix); - target_id = ASC_TID_TO_TARGET_ID(tid_no); - saved_unit_not_ready = asc_dvc->unit_not_ready; - asc_dvc->unit_not_ready = target_id; - sta = ERR; - AscWaitTixISRDone(asc_dvc, target_ix); - if (AscStopQueueExe(iop_base) == 1) { - if (AscRiscHaltedAbortTIX(asc_dvc, target_ix) == 1) { - AscCleanUpBusyQueue(iop_base); - AscStartQueueExe(iop_base); - AscWaitTixISRDone(asc_dvc, target_ix); - sta = TRUE; - scsiq = (ASC_SCSI_REQ_Q *) & scsiq_buf; - buf = (uchar *) & scsiq_buf; - for (i = 0; i < sizeof (ASC_SCSI_REQ_Q); i++) { - *buf++ = 0x00; + 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; } - scsiq->r1.status = (uchar) QS_READY; - scsiq->r2.cdb_len = 6; - scsiq->r2.tag_code = M2_QTAG_MSG_SIMPLE; - scsiq->r1.target_id = target_id; - scsiq->r2.target_ix = ASC_TIDLUN_TO_IX(tid_no, 0); - scsiq->cdbptr = (uchar *) scsiq->cdb; - scsiq->r1.cntl = QC_NO_CALLBACK | QC_MSG_OUT | QC_URGENT; - AscWriteLramByte(asc_dvc->iop_base, ASCV_MSGOUT_BEG, - M1_BUS_DVC_RESET); - asc_dvc->unit_not_ready &= ~target_id; - asc_dvc->sdtr_done |= target_id; - if (AscExeScsiQueue(asc_dvc, (ASC_SCSI_Q *) scsiq) - == 1) { - asc_dvc->unit_not_ready = target_id; - DvcSleepMilliSecond(1000); - _AscWaitQDone(iop_base, (ASC_SCSI_Q *) scsiq); - if (AscStopQueueExe(iop_base) == 1) { - AscCleanUpDiscQueue(iop_base); - AscStartQueueExe(iop_base); - if (asc_dvc->pci_fix_asyn_xfer & target_id) { - AscSetRunChipSynRegAtID(iop_base, tid_no, - ASYN_SDTR_DATA_FIX_PCI_REV_AB); - } - AscWaitTixISRDone(asc_dvc, target_ix); - } - } else { - sta = 0; + if (boardp->device[i] == NULL) { + continue; } - asc_dvc->sdtr_done &= ~target_id; - } else { - sta = ERR; - AscStartQueueExe(iop_base); + len = asc_prt_line(cp, leftlen, " %X:%d", + i, boardp->device[i]->queue_depth); + ASC_PRT_NEXT(); } + len = asc_prt_line(cp, leftlen, "\n"); + ASC_PRT_NEXT(); } - asc_dvc->unit_not_ready = saved_unit_not_ready; - return (sta); -} #endif /* version >= v1.3.89 */ -STATIC int -AscResetSB( - REG ASC_DVC_VAR asc_ptr_type * asc_dvc -) -{ - 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); - DvcSleepMilliSecond((ulong) ((ushort) asc_dvc->scsi_reset_wait * 1000)); - AscReInitLram(asc_dvc); - for (i = 0; i <= ASC_MAX_TID; i++) { - asc_dvc->cur_dvc_qng[i] = 0; - if (asc_dvc->pci_fix_asyn_xfer & (ASC_SCSI_BIT_ID_TYPE) (0x01 << i)) { - AscSetChipSynRegAtID(iop_base, i, ASYN_SDTR_DATA_FIX_PCI_REV_AB); +#if ASC_QUEUE_FLOW_CONTROL + 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(); } - } - asc_dvc->err_code = 0; - AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR); - if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) { - sta = ERR; - } - if (AscStartChip(iop_base) == 0) { - sta = ERR; - } - AscStartQueueExe(iop_base); - asc_dvc->unit_not_ready = 0; - asc_dvc->queue_full_or_busy = 0; - return (sta); -} + len = asc_prt_line(cp, leftlen, "\n"); + ASC_PRT_NEXT(); -STATIC int -AscSetRunChipSynRegAtID( - PortAddr iop_base, - uchar tid_no, - uchar sdtr_data -) -{ - int sta = FALSE; - if (AscHostReqRiscHalt(iop_base)) { - sta = AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data); - AscStartChip(iop_base); - return (sta); + 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, "\n"); + ASC_PRT_NEXT(); } - return (sta); +#endif /* ASC_QUEUE_FLOW_CONTROL */ + + return totlen; } +/* + * asc_prt_asc_board_info() + * + * Print dynamic board configuration information. + * + * 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 -AscSetChipSynRegAtID( - PortAddr iop_base, - uchar id, - uchar sdtr_data -) +asc_prt_asc_board_info(struct Scsi_Host *shp, char *cp, int cplen) { - ASC_SCSI_BIT_ID_TYPE org_id; - int i; - int sta; - sta = TRUE; - AscSetBank(iop_base, 1); - org_id = AscReadChipDvcID(iop_base); + asc_board_t *boardp; + int leftlen; + int totlen; + int len; + ASC_DVC_VAR *v; + ASC_DVC_CFG *c; + int i; + + boardp = ASC_BOARDP(shp); + v = &boardp->dvc_var.asc_dvc_var; + c = &boardp->dvc_cfg.asc_dvc_cfg; + + leftlen = cplen; + totlen = len = 0; + + len = asc_prt_line(cp, leftlen, +"\nAsc Library Configuration and Statistics for AdvanSys SCSI Host %d:\n", + shp->host_no); + ASC_PRT_NEXT(); + + len = asc_prt_line(cp, leftlen, +" 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 %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); + ASC_PRT_NEXT(); + + len = asc_prt_line(cp, leftlen, +" Command Queuing:"); + ASC_PRT_NEXT(); for (i = 0; i <= ASC_MAX_TID; i++) { - if (org_id == (0x01 << i)) - break; + 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 & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); + ASC_PRT_NEXT(); } - org_id = i; - AscWriteChipDvcID(iop_base, id); - if (AscReadChipDvcID(iop_base) == (0x01 << id)) { - AscSetBank(iop_base, 0); - AscSetChipSyn(iop_base, sdtr_data); - if (AscGetChipSyn(iop_base) != sdtr_data) { - sta = FALSE; + len = asc_prt_line(cp, leftlen, "\n"); + ASC_PRT_NEXT(); + + /* Current number of commands waiting for a device. */ + len = asc_prt_line(cp, leftlen, +" Command Queue Pending:"); + ASC_PRT_NEXT(); + for (i = 0; i <= ASC_MAX_TID; i++) { + if ((boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id == i) || + ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { + continue; } - } else { - sta = FALSE; + len = asc_prt_line(cp, leftlen, " %d:%u", i, v->cur_dvc_qng[i]); + ASC_PRT_NEXT(); } - AscSetBank(iop_base, 1); - AscWriteChipDvcID(iop_base, org_id); - AscSetBank(iop_base, 0); - return (sta); -} + len = asc_prt_line(cp, leftlen, "\n"); + ASC_PRT_NEXT(); -STATIC int -AscReInitLram( - REG ASC_DVC_VAR asc_ptr_type * asc_dvc -) -{ - AscInitLram(asc_dvc); - AscInitQLinkVar(asc_dvc); - return (0); -} + /* Current limit on number of commands that can be sent to a device. */ + len = asc_prt_line(cp, leftlen, +" Command Queue Limit:"); + ASC_PRT_NEXT(); + for (i = 0; i <= ASC_MAX_TID; i++) { + 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]); + ASC_PRT_NEXT(); + } + len = asc_prt_line(cp, leftlen, "\n"); + ASC_PRT_NEXT(); -STATIC ushort -AscInitLram( - REG ASC_DVC_VAR asc_ptr_type * asc_dvc -) -{ - uchar i; - 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, - (ushort) (((int) (asc_dvc->max_total_qng + 2 + 1) * 64) >> 1) -); - i = ASC_MIN_ACTIVE_QNO; - s_addr = ASC_QADR_BEG + ASC_QBLK_SIZE; - AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_FWD), - (uchar) (i + 1)); - AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_BWD), - (uchar) (asc_dvc->max_total_qng)); - AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_QNO), - (uchar) i); - i++; - s_addr += ASC_QBLK_SIZE; - for (; i < asc_dvc->max_total_qng; i++, s_addr += ASC_QBLK_SIZE) { - AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_FWD), - (uchar) (i + 1)); - AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_BWD), - (uchar) (i - 1)); - AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_QNO), - (uchar) i); + /* Indicate whether the device has returned queue full status. */ + len = asc_prt_line(cp, leftlen, +" Command Queue Full:"); + ASC_PRT_NEXT(); + for (i = 0; i <= ASC_MAX_TID; i++) { + 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 & ADV_TID_TO_TIDMASK(i)) { + len = asc_prt_line(cp, leftlen, " %d:Y-%d", + i, boardp->queue_full_cnt[i]); + } else { + len = asc_prt_line(cp, leftlen, " %d:N", i); + } + ASC_PRT_NEXT(); } - AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_FWD), - (uchar) ASC_QLINK_END); - AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_BWD), - (uchar) (asc_dvc->max_total_qng - 1)); - AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_QNO), - (uchar) asc_dvc->max_total_qng); - i++; - s_addr += ASC_QBLK_SIZE; - for (; i <= (uchar) (asc_dvc->max_total_qng + 3); - i++, s_addr += ASC_QBLK_SIZE) { - AscWriteLramByte(iop_base, - (ushort) (s_addr + (ushort) ASC_SCSIQ_B_FWD), i); - AscWriteLramByte(iop_base, - (ushort) (s_addr + (ushort) ASC_SCSIQ_B_BWD), i); - AscWriteLramByte(iop_base, - (ushort) (s_addr + (ushort) ASC_SCSIQ_B_QNO), i); + 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 <= ASC_MAX_TID; i++) { + 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 & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); + ASC_PRT_NEXT(); } - return (warn_code); -} + len = asc_prt_line(cp, leftlen, "\n"); + ASC_PRT_NEXT(); -STATIC ushort -AscInitQLinkVar( - REG ASC_DVC_VAR asc_ptr_type * asc_dvc -) -{ - 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); - AscPutVarFreeQHead(iop_base, 1); - AscPutVarDoneQTail(iop_base, asc_dvc->max_total_qng); - AscWriteLramByte(iop_base, ASCV_BUSY_QHEAD_B, - (uchar) ((int) asc_dvc->max_total_qng + 1)); - AscWriteLramByte(iop_base, ASCV_DISC1_QHEAD_B, - (uchar) ((int) asc_dvc->max_total_qng + 2)); - AscWriteLramByte(iop_base, (ushort) ASCV_TOTAL_READY_Q_B, - asc_dvc->max_total_qng); - AscWriteLramWord(iop_base, ASCV_ASCDVC_ERR_CODE_W, 0); - AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0); - AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, 0); - AscWriteLramByte(iop_base, ASCV_SCSIBUSY_B, 0); - AscWriteLramByte(iop_base, ASCV_WTM_FLAG_B, 0); - AscPutQDoneInProgress(iop_base, 0); - lram_addr = ASC_QADR_BEG; - for (i = 0; i < 32; i++, lram_addr += 2) { - AscWriteLramWord(iop_base, lram_addr, 0); + for (i = 0; i <= ASC_MAX_TID; i++) { + uchar syn_period_ix; + + 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 & 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); + ASC_PRT_NEXT(); + + len = asc_prt_line(cp, leftlen, + " Transfer Period Factor: %d (%d.%d Mhz),", + v->sdtr_period_tbl[syn_period_ix], + 250 / v->sdtr_period_tbl[syn_period_ix], + ASC_TENTHS(250, v->sdtr_period_tbl[syn_period_ix])); + ASC_PRT_NEXT(); + + len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d\n", + boardp->sdtr_data[i] & ASC_SYN_MAX_OFFSET); + ASC_PRT_NEXT(); } - return (0); + + return totlen; } +/* + * asc_prt_adv_board_info() + * + * Print dynamic board configuration information. + * + * 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 -AscSetLibErrorCode( - REG ASC_DVC_VAR asc_ptr_type * asc_dvc, - ushort err_code -) +asc_prt_adv_board_info(struct Scsi_Host *shp, char *cp, int cplen) { - if (asc_dvc->err_code == 0) { - asc_dvc->err_code = err_code; - AscWriteLramWord(asc_dvc->iop_base, ASCV_ASCDVC_ERR_CODE_W, - err_code); - } - return (err_code); -} + 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; + 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; -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) -STATIC int -_AscWaitQDone( - PortAddr iop_base, - REG ASC_SCSI_Q * scsiq -) -{ - 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 { - q_status = AscReadLramByte(iop_base, q_addr + ASC_SCSIQ_B_STATUS); - DvcSleepMilliSecond(100L); - if (count++ > 30) { - return (0); + leftlen = cplen; + totlen = len = 0; + + 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; } - } while ((q_status & QS_READY) != 0); - return (1); -} -#endif /* version >= v1.3.89 */ -STATIC uchar -AscMsgOutSDTR( - REG ASC_DVC_VAR asc_ptr_type * asc_dvc, - uchar sdtr_period, - uchar sdtr_offset -) -{ - EXT_MSG sdtr_buf; - uchar sdtr_period_index; - PortAddr iop_base; + 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(); - iop_base = asc_dvc->iop_base; - sdtr_buf.msg_type = MS_EXTEND; - sdtr_buf.msg_len = MS_SDTR_LEN; - sdtr_buf.msg_req = MS_SDTR_CODE; - sdtr_buf.xfer_period = sdtr_period; - sdtr_offset &= ASC_SYN_MAX_OFFSET; - sdtr_buf.req_ack_offset = sdtr_offset; - if ((sdtr_period_index = - AscGetSynPeriodIndex(asc_dvc, sdtr_period)) <= - asc_dvc->max_sdtr_index) { - AscMemWordCopyToLram(iop_base, - ASCV_MSGOUT_BEG, - (ushort *) & sdtr_buf, - (ushort) (sizeof (EXT_MSG) >> 1)); - return ((sdtr_period_index << 4) | sdtr_offset); - } else { + 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; + } - sdtr_buf.req_ack_offset = 0; - AscMemWordCopyToLram(iop_base, - ASCV_MSGOUT_BEG, - (ushort *) & sdtr_buf, - (ushort) (sizeof (EXT_MSG) >> 1)); - return (0); + 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(); -STATIC uchar -AscCalSDTRData( - REG ASC_DVC_VAR asc_ptr_type * asc_dvc, - uchar sdtr_period, - uchar syn_offset -) -{ - uchar byte; - uchar sdtr_period_ix; - sdtr_period_ix = AscGetSynPeriodIndex(asc_dvc, sdtr_period); - if ( - (sdtr_period_ix > asc_dvc->max_sdtr_index) -) { - return (0xFF); + 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(); } - byte = (sdtr_period_ix << 4) | (syn_offset & ASC_SYN_MAX_OFFSET); - return (byte); -} + len = asc_prt_line(cp, leftlen, "\n"); + ASC_PRT_NEXT(); -STATIC void -AscSetChipSDTR( - PortAddr iop_base, - uchar sdtr_data, - uchar tid_no -) -{ - AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data); - AscPutMCodeSDTRDoneAtID(iop_base, tid_no, sdtr_data); - return; -} + 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; + } -STATIC uchar -AscGetSynPeriodIndex( - ASC_DVC_VAR asc_ptr_type * asc_dvc, - ruchar syn_time -) -{ - ruchar *period_table; - 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 ; - if ((syn_time <= period_table[max_index])) { - for (i = min_index; i < (max_index - 1); i++) { - if (syn_time <= period_table[i]) { - return ((uchar) i); - } + 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; } - return ((uchar) max_index); - } else { - return ((uchar) (max_index + 1)); + + 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(); -STATIC uchar -AscAllocFreeQueue( - PortAddr iop_base, - uchar free_q_head -) -{ - 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)); - next_qp = AscReadLramByte(iop_base, - (ushort) (q_addr + ASC_SCSIQ_B_FWD)); - if (((q_status & QS_READY) == 0) && (next_qp != ASC_QLINK_END)) { - return (next_qp); + 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(); } - return (ASC_QLINK_END); + 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; } -STATIC uchar -AscAllocMultipleFreeQueue( - PortAddr iop_base, - uchar free_q_head, - uchar n_free_q -) +/* + * 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) { - uchar i; - for (i = 0; i < n_free_q; i++) { - if ((free_q_head = AscAllocFreeQueue(iop_base, free_q_head)) - == ASC_QLINK_END) { - return (ASC_QLINK_END); - } + 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 (free_q_head); + 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 -AscRiscHaltedAbortSRB( - REG ASC_DVC_VAR asc_ptr_type * asc_dvc, - ulong srb_ptr -) +asc_prt_line(char *buf, int buflen, char *fmt, ...) { - PortAddr iop_base; - ushort q_addr; - uchar q_no; - ASC_QDONE_INFO scsiq_buf; - 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(); - scsiq = (ASC_QDONE_INFO *) & scsiq_buf; - for (q_no = ASC_MIN_ACTIVE_QNO; q_no <= asc_dvc->max_total_qng; - q_no++) { - q_addr = ASC_QNO_TO_QADDR(q_no); - scsiq->d2.srb_ptr = AscReadLramDWord(iop_base, - (ushort) (q_addr + (ushort) ASC_SCSIQ_D_SRBPTR)); - if (scsiq->d2.srb_ptr == srb_ptr) { - _AscCopyLramScsiDoneQ(iop_base, q_addr, scsiq, asc_dvc->max_dma_count); - if (((scsiq->q_status & QS_READY) != 0) - && ((scsiq->q_status & QS_ABORTED) == 0) - && ((scsiq->cntl & QCSG_SG_XFER_LIST) == 0)) { - scsiq->q_status |= QS_ABORTED; - scsiq->d3.done_stat = QD_ABORTED_BY_HOST; - AscWriteLramDWord(iop_base, - (ushort) (q_addr + (ushort) ASC_SCSIQ_D_SRBPTR), - 0L); - AscWriteLramByte(iop_base, - (ushort) (q_addr + (ushort) ASC_SCSIQ_B_STATUS), - scsiq->q_status); - (*asc_isr_callback) (asc_dvc, scsiq); - return (1); - } - } - } - DvcLeaveCritical(last_int_level); - return (0); -} + va_list args; + int ret; + char s[ASC_PRTLINE_SIZE]; -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) -STATIC int -AscRiscHaltedAbortTIX( - REG ASC_DVC_VAR asc_ptr_type * asc_dvc, - uchar target_ix -) -{ - PortAddr iop_base; - ushort q_addr; - uchar q_no; - ASC_QDONE_INFO scsiq_buf; - 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(); - scsiq = (ASC_QDONE_INFO *) & scsiq_buf; - for (q_no = ASC_MIN_ACTIVE_QNO; q_no <= asc_dvc->max_total_qng; - q_no++) { - q_addr = ASC_QNO_TO_QADDR(q_no); - _AscCopyLramScsiDoneQ(iop_base, q_addr, scsiq, asc_dvc->max_dma_count); - if (((scsiq->q_status & QS_READY) != 0) && - ((scsiq->q_status & QS_ABORTED) == 0) && - ((scsiq->cntl & QCSG_SG_XFER_LIST) == 0)) { - if (scsiq->d2.target_ix == target_ix) { - scsiq->q_status |= QS_ABORTED; - scsiq->d3.done_stat = QD_ABORTED_BY_HOST; - AscWriteLramDWord(iop_base, - (ushort) (q_addr + (ushort) ASC_SCSIQ_D_SRBPTR), - 0L); - AscWriteLramByte(iop_base, - (ushort) (q_addr + (ushort) ASC_SCSIQ_B_STATUS), - scsiq->q_status); - (*asc_isr_callback) (asc_dvc, scsiq); - } - } + 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); } - DvcLeaveCritical(last_int_level); - return (1); + va_end(args); + return ret; } -#endif /* version >= v1.3.89 */ +#endif /* version >= v1.3.0 */ -STATIC int -AscHostReqRiscHalt( - PortAddr iop_base -) -{ - 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); - AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, - ASC_STOP_HOST_REQ_RISC_HALT | ASC_STOP_REQ_RISC_STOP -); - do { - if (AscIsChipHalted(iop_base)) { - sta = 1; - break; - } - DvcSleepMilliSecond(100); - } while (count++ < 20); - AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, saved_stop_code); - return (sta); -} -STATIC int -AscStopQueueExe( - PortAddr iop_base -) +/* + * --- Functions Required by the Asc Library + */ + +/* + * Delay for 'n' milliseconds. Don't use the 'jiffies' + * global variable which is incremented once every 5 ms + * from a timer interrupt, because this function may be + * called when interrupts are disabled. + */ +STATIC void +DvcSleepMilliSecond(ulong n) { - int count; - count = 0; - if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) == 0) { - AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, - ASC_STOP_REQ_RISC_STOP); - do { - if ( - AscReadLramByte(iop_base, ASCV_STOP_CODE_B) & - ASC_STOP_ACK_RISC_STOP) { - return (1); - } - DvcSleepMilliSecond(100); - } while (count++ < 20); + ulong i; + + ASC_DBG1(4, "DvcSleepMilliSecond: %lu\n", n); + for (i = 0; i < n; i++) { + udelay(1000); } - return (0); } STATIC int -AscStartQueueExe( - PortAddr iop_base -) +DvcEnterCritical(void) { - if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) != 0) { - AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, 0); - } - return (1); + int flags; + + save_flags(flags); + cli(); + return flags; } -STATIC int -AscCleanUpBusyQueue( - PortAddr iop_base -) +STATIC void +DvcLeaveCritical(int flags) { - int count; - uchar stop_code; - count = 0; - if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) != 0) { - AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, - ASC_STOP_CLEAN_UP_BUSY_Q); - do { - stop_code = AscReadLramByte(iop_base, ASCV_STOP_CODE_B); - if ((stop_code & ASC_STOP_CLEAN_UP_BUSY_Q) == 0) - break; - DvcSleepMilliSecond(100); - } while (count++ < 20); - } - return (1); + restore_flags(flags); } -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) -STATIC int -AscCleanUpDiscQueue( - PortAddr iop_base -) +STATIC ulong +DvcGetSGList(ASC_DVC_VAR *asc_dvc_sg, uchar *buf_addr, ulong buf_len, + ASC_SG_HEAD *asc_sg_head_ptr) { - int count; - uchar stop_code; - count = 0; - if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) != 0) { - AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, - ASC_STOP_CLEAN_UP_DISC_Q); - do { - stop_code = AscReadLramByte(iop_base, ASCV_STOP_CODE_B); - if ((stop_code & ASC_STOP_CLEAN_UP_DISC_Q) == 0) - break; - DvcSleepMilliSecond(100); - } while (count++ < 20); - } - return (1); + ulong buf_size; + + buf_size = buf_len; + asc_sg_head_ptr->entry_cnt = 1; +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0) + asc_sg_head_ptr->sg_list[0].addr = (ulong) buf_addr; +#else /* version >= v2.0.0 */ + asc_sg_head_ptr->sg_list[0].addr = virt_to_bus(buf_addr); +#endif /* version >= v2.0.0 */ + asc_sg_head_ptr->sg_list[0].bytes = buf_size; + return buf_size; } -#endif /* version >= v1.3.89 */ -STATIC int -AscWaitTixISRDone( - ASC_DVC_VAR asc_ptr_type * asc_dvc, - uchar target_ix -) +/* + * void + * DvcPutScsiQ(PortAddr iop_base, ushort s_addr, ushort *outbuf, int words) + * + * Calling/Exit State: + * none + * + * Description: + * Output an ASC_SCSI_Q structure to the chip + */ +STATIC void +DvcPutScsiQ(PortAddr iop_base, ushort s_addr, ushort *outbuf, int words) { - uchar cur_req; - uchar tid_no; - tid_no = ASC_TIX_TO_TID(target_ix); - while (TRUE) { - if ((cur_req = asc_dvc->cur_dvc_qng[tid_no]) == 0) { - break; - } - DvcSleepMilliSecond(1000L); - if (asc_dvc->cur_dvc_qng[tid_no] == cur_req) { - break; + int i; + + ASC_DBG_PRT_HEX(2, "DvcPutScsiQ", (uchar *) outbuf, 2 * words); + AscSetChipLramAddr(iop_base, s_addr); + for (i = 0; i < words; i++, outbuf++) { + if (i == 2 || i == 10) { + continue; } + AscSetChipLramDataNoSwap(iop_base, *outbuf); } - return (1); } -STATIC int -AscWaitISRDone( - REG ASC_DVC_VAR asc_ptr_type * asc_dvc -) +/* + * void + * DvcGetQinfo(PortAddr iop_base, ushort s_addr, ushort *inbuf, int words) + * + * Calling/Exit State: + * none + * + * Description: + * Input an ASC_QDONE_INFO structure from the chip + */ +STATIC void +DvcGetQinfo(PortAddr iop_base, ushort s_addr, ushort *inbuf, int words) { - int tid; - for (tid = 0; tid <= ASC_MAX_TID; tid++) { - AscWaitTixISRDone(asc_dvc, ASC_TID_TO_TIX(tid)); + int i; + + AscSetChipLramAddr(iop_base, s_addr); + for (i = 0; i < words; i++, inbuf++) { + if (i == 5) { + continue; + } + *inbuf = AscGetChipLramDataNoSwap(iop_base); } - return (1); + ASC_DBG_PRT_HEX(2, "DvcGetQinfo", (uchar *) inbuf, 2 * words); } -STATIC ulong -AscGetOnePhyAddr( - REG ASC_DVC_VAR asc_ptr_type * asc_dvc, - uchar * buf_addr, - ulong buf_size -) +/* + * void DvcOutPortWords(ushort iop_base, ushort &outbuf, int words) + * + * Calling/Exit State: + * none + * + * Description: + * output a buffer to an i/o port address + */ +STATIC void +DvcOutPortWords(ushort iop_base, ushort *outbuf, int words) { - 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) { - return (0L); - } - if (sg_head.entry_cnt > 1) { - return (0L); - } - return (sg_head.sg_list[0].addr); + int i; + + for (i = 0; i < words; i++, outbuf++) + outpw(iop_base, *outbuf); } +/* + * void DvcInPortWords(ushort iop_base, ushort &outbuf, int words) + * + * Calling/Exit State: + * none + * + * Description: + * input a buffer from an i/o port address + */ STATIC void -DvcDelayNanoSecond( - ASC_DVC_VAR asc_ptr_type * asc_dvc, - ulong nano_sec -) +DvcInPortWords(ushort iop_base, ushort *inbuf, int words) { - ulong loop; - PortAddr iop_base; - iop_base = asc_dvc->iop_base; - loop = nano_sec / 90; - loop++; - while (loop-- != 0) { - inp(iop_base); + int i; + + for (i = 0; i < words; i++, inbuf++) + *inbuf = inpw(iop_base); +} + +/* + * void DvcOutPortDWords(PortAddr port, ulong *pdw, int dwords) + * + * Calling/Exit State: + * none + * + * Description: + * output a buffer of 32-bit integers to an i/o port address in + * 16 bit integer units + */ +STATIC void +DvcOutPortDWords(PortAddr port, ulong *pdw, int dwords) +{ + int i; + int words; + ushort *pw; + + pw = (ushort *) pdw; + words = dwords << 1; + for(i = 0; i < words; i++, pw++) { + outpw(port, *pw); } return; } +/* + * Read a PCI configuration byte. + */ ASC_INITFUNC( -STATIC ulong -AscGetEisaProductID( - PortAddr iop_base -) +STATIC uchar +DvcReadPCIConfigByte( + ASC_DVC_VAR asc_ptr_type *asc_dvc, + ushort offset) ) { - 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); - product_id = ((ulong) product_id_high << 16) | (ulong) product_id_low; - return (product_id); + 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 PortAddr -AscSearchIOPortAddrEISA( - PortAddr iop_base -) +STATIC void +DvcWritePCIConfigByte( + ASC_DVC_VAR asc_ptr_type *asc_dvc, + ushort offset, + uchar byte_data) ) { - ulong eisa_product_id; - if (iop_base == 0) { - iop_base = ASC_EISA_MIN_IOP_ADDR; - } else { - if (iop_base == ASC_EISA_MAX_IOP_ADDR) - return (0); - if ((iop_base & 0x0050) == 0x0050) { - iop_base += ASC_EISA_BIG_IOP_GAP; - } else { - iop_base += ASC_EISA_SMALL_IOP_GAP; - } - } - while (iop_base <= ASC_EISA_MAX_IOP_ADDR) { - eisa_product_id = AscGetEisaProductID(iop_base); - if ((eisa_product_id == ASC_EISA_ID_740) || - (eisa_product_id == ASC_EISA_ID_750)) { - if (AscFindSignature(iop_base)) { - inpw(iop_base + 4); - return (iop_base); - } - } - if (iop_base == ASC_EISA_MAX_IOP_ADDR) - return (0); - if ((iop_base & 0x0050) == 0x0050) { - iop_base += ASC_EISA_BIG_IOP_GAP; - } else { - iop_base += ASC_EISA_SMALL_IOP_GAP; - } - } - return (0); + 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); } -STATIC int -AscStartChip( - PortAddr iop_base +/* + * Return the BIOS address of the adapter at the specified + * I/O port and with the specified bus type. + */ +ASC_INITFUNC( +STATIC ushort +AscGetChipBiosAddress( + PortAddr iop_base, + ushort bus_type +) ) { - AscSetChipControl(iop_base, 0); - if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) { - return (0); + ushort cfg_lsw ; + ushort bios_addr ; + + /* + * The PCI BIOS is re-located by the motherboard BIOS. Because + * of this the driver can not determine where a PCI BIOS is + * loaded and executes. + */ + if (bus_type & ASC_IS_PCI) + { + return(0); } - return (1); + + if((bus_type & ASC_IS_EISA) != 0) + { + cfg_lsw = AscGetEisaChipCfg(iop_base) ; + cfg_lsw &= 0x000F ; + bios_addr = (ushort)(ASC_BIOS_MIN_ADDR + + (cfg_lsw * ASC_BIOS_BANK_SIZE)) ; + return(bios_addr) ; + }/* if */ + + cfg_lsw = AscGetChipCfgLsw(iop_base) ; + + /* + * ISA PnP uses the top bit as the 32K BIOS flag + */ + if (bus_type == ASC_IS_ISAPNP) + { + cfg_lsw &= 0x7FFF; + }/* if */ + + bios_addr = (ushort)(((cfg_lsw >> 12) * ASC_BIOS_BANK_SIZE) + + ASC_BIOS_MIN_ADDR) ; + return(bios_addr) ; } -STATIC int -AscStopChip( - PortAddr iop_base -) + +/* + * --- 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) { - 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); - AscSetChipIH(iop_base, INS_RFLAG_WTM); - if ((AscGetChipStatus(iop_base) & CSW_HALTED) == 0) { - return (0); - } - return (1); + 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; } -STATIC int -AscIsChipHalted( - PortAddr iop_base +/* + * Read a PCI configuration byte. + */ +ASC_INITFUNC( +STATIC uchar +DvcAdvReadPCIConfigByte( + ADV_DVC_VAR *asc_dvc, + ushort offset) ) { - if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) { - if ((AscGetChipControl(iop_base) & CC_HALT) != 0) { - return (1); - } - } - return (0); -} + PCI_DATA pciData; -STATIC void -AscSetChipIH( - PortAddr iop_base, - ushort ins_code -) -{ - AscSetBank(iop_base, 1); - AscWriteChipIH(iop_base, ins_code); - AscSetBank(iop_base, 0); - return; + 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 -AscAckInterrupt( - PortAddr iop_base +DvcAdvWritePCIConfigByte( + ADV_DVC_VAR *asc_dvc, + ushort offset, + uchar byte_data) ) { - uchar host_flag; - uchar risc_flag; - ushort loop; - loop = 0; - do { - risc_flag = AscReadLramByte(iop_base, ASCV_RISC_FLAG_B); - if (loop++ > 0x7FFF) { - break; - } - } while ((risc_flag & ASC_RISC_FLAG_GEN_INT) != 0); - host_flag = AscReadLramByte(iop_base, ASCV_HOST_FLAG_B) & (~ASC_HOST_FLAG_ACK_INT); - AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, - (uchar) (host_flag | ASC_HOST_FLAG_ACK_INT)); - AscSetChipStatus(iop_base, CIW_INT_ACK); - loop = 0; - while (AscGetChipStatus(iop_base) & CSW_INT_PENDING) { - AscSetChipStatus(iop_base, CIW_INT_ACK); - if (loop++ > 3) { - break; - } - } - AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag); - return; -} + PCI_DATA pciData; -STATIC void -AscDisableInterrupt( - PortAddr iop_base -) -{ - ushort cfg; - cfg = AscGetChipCfgLsw(iop_base); - AscSetChipCfgLsw(iop_base, cfg & (~ASC_CFG0_HOST_INT_ON)); - return; + 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); } -STATIC void -AscEnableInterrupt( - PortAddr iop_base -) +/* + * --- Tracing and Debugging Functions + */ + +#ifdef ADVANSYS_STATS +/* + * asc_prt_board_stats() + * + * 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_board_stats(struct Scsi_Host *shp, char *cp, int cplen) { - ushort cfg; - cfg = AscGetChipCfgLsw(iop_base); - AscSetChipCfgLsw(iop_base, cfg | ASC_CFG0_HOST_INT_ON); - return; -} + int leftlen; + int totlen; + int len; + 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; + boardp = ASC_BOARDP(shp); + s = &boardp->asc_stats; -STATIC void -AscSetBank( - PortAddr iop_base, - uchar bank -) -{ - uchar val; - val = AscGetChipControl(iop_base) & - (~(CC_SINGLE_STEP | CC_TEST | CC_DIAG | CC_SCSI_RESET | CC_CHIP_RESET)); - if (bank == 1) { - val |= CC_BANK_ONE; - } else if (bank == 2) { - val |= CC_DIAG | CC_BANK_ONE; + len = asc_prt_line(cp, leftlen, +"\nLinux Driver Statistics for AdvanSys SCSI Host %d:\n", shp->host_no); + ASC_PRT_NEXT(); + + len = asc_prt_line(cp, leftlen, +" command %lu, queuecommand %lu, abort %lu, reset %lu, biosparam %lu\n", + s->command, s->queuecommand, s->abort, s->reset, s->biosparam); + ASC_PRT_NEXT(); + + len = asc_prt_line(cp, leftlen, +" interrupt %lu, callback %lu, done %lu\n", + s->interrupt, s->callback, s->done); + ASC_PRT_NEXT(); + + len = asc_prt_line(cp, leftlen, +" 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 { - val &= ~CC_BANK_ONE; + 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); } - AscSetChipControl(iop_base, val); - return; -} + ASC_PRT_NEXT(); + /* + * Display data transfer statistics. + */ + if (s->cont_cnt > 0) { + len = asc_prt_line(cp, leftlen, " cont_cnt %lu, ", s->cont_cnt); + ASC_PRT_NEXT(); + len = asc_prt_line(cp, leftlen, "cont_xfer %lu.%01lu kb ", + s->cont_xfer/2, + ASC_TENTHS(s->cont_xfer, 2)); + ASC_PRT_NEXT(); -STATIC int -AscResetChipAndScsiBus( - PortAddr 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); - AscSetChipIH(iop_base, INS_RFLAG_WTM); - AscSetChipIH(iop_base, INS_HALT); - AscSetChipControl(iop_base, CC_CHIP_RESET | CC_HALT); - AscSetChipControl(iop_base, CC_HALT); - DvcSleepMilliSecond(200); - AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT); - AscSetChipStatus(iop_base, 0); - return (AscIsChipHalted(iop_base)); -} + /* Contiguous transfer average size */ + len = asc_prt_line(cp, leftlen, "avg_xfer %lu.%01lu kb\n", + (s->cont_xfer/2)/s->cont_cnt, + ASC_TENTHS((s->cont_xfer/2), s->cont_cnt)); + ASC_PRT_NEXT(); + } -ASC_INITFUNC( -STATIC ulong -AscGetMaxDmaCount( - ushort bus_type -) -) -{ - if (bus_type & ASC_IS_ISA) - return (ASC_MAX_ISA_DMA_COUNT); - else if (bus_type & (ASC_IS_EISA | ASC_IS_VL)) - return (ASC_MAX_VL_DMA_COUNT); - return (ASC_MAX_PCI_DMA_COUNT); -} + if (s->sg_cnt > 0) { -ASC_INITFUNC( -STATIC ushort -AscGetIsaDmaChannel( - PortAddr iop_base -) -) -{ - ushort channel; - channel = AscGetChipCfgLsw(iop_base) & 0x0003; - if (channel == 0x03) - return (0); - else if (channel == 0x00) - return (7); - return (channel + 4); -} + len = asc_prt_line(cp, leftlen, " sg_cnt %lu, sg_elem %lu, ", + s->sg_cnt, s->sg_elem); + ASC_PRT_NEXT(); -ASC_INITFUNC( -STATIC ushort -AscSetIsaDmaChannel( - PortAddr iop_base, - ushort dma_channel -) -) -{ - ushort cfg_lsw; - uchar value; - if ((dma_channel >= 5) && (dma_channel <= 7)) { - if (dma_channel == 7) - value = 0x00; - else - value = dma_channel - 4; - cfg_lsw = AscGetChipCfgLsw(iop_base) & 0xFFFC; - cfg_lsw |= value; - AscSetChipCfgLsw(iop_base, cfg_lsw); - return (AscGetIsaDmaChannel(iop_base)); + len = asc_prt_line(cp, leftlen, "sg_xfer %lu.%01lu kb\n", + s->sg_xfer/2, + ASC_TENTHS(s->sg_xfer, 2)); + ASC_PRT_NEXT(); + + /* Scatter gather transfer statistics */ + len = asc_prt_line(cp, leftlen, " avg_num_elem %lu.%01lu, ", + s->sg_elem/s->sg_cnt, + ASC_TENTHS(s->sg_elem, s->sg_cnt)); + ASC_PRT_NEXT(); + + len = asc_prt_line(cp, leftlen, "avg_elem_size %lu.%01lu kb, ", + (s->sg_xfer/2)/s->sg_elem, + ASC_TENTHS((s->sg_xfer/2), s->sg_elem)); + ASC_PRT_NEXT(); + + len = asc_prt_line(cp, leftlen, "avg_xfer_size %lu.%01lu kb\n", + (s->sg_xfer/2)/s->sg_cnt, + ASC_TENTHS((s->sg_xfer/2), s->sg_cnt)); + ASC_PRT_NEXT(); } - return (0); -} -ASC_INITFUNC( -STATIC uchar -AscSetIsaDmaSpeed( - PortAddr iop_base, - uchar speed_value -) -) -{ - speed_value &= 0x07; - AscSetBank(iop_base, 1); - AscWriteChipDmaSpeed(iop_base, speed_value); - AscSetBank(iop_base, 0); - return (AscGetIsaDmaSpeed(iop_base)); -} - -ASC_INITFUNC( -STATIC uchar -AscGetIsaDmaSpeed( - PortAddr iop_base -) -) -{ - uchar speed_value; - AscSetBank(iop_base, 1); - speed_value = AscReadChipDmaSpeed(iop_base); - speed_value &= 0x07; - AscSetBank(iop_base, 0); - return (speed_value); -} - -ASC_INITFUNC( -STATIC ushort -AscReadPCIConfigWord( - ASC_DVC_VAR asc_ptr_type *asc_dvc, - ushort pci_config_offset) -) -{ - uchar lsb, msb; - - lsb = DvcReadPCIConfigByte(asc_dvc, pci_config_offset); - msb = DvcReadPCIConfigByte(asc_dvc, pci_config_offset + 1); - return ((ushort) ((msb << 8) | lsb)); -} + /* + * Display request queuing statistics. + */ + len = asc_prt_line(cp, leftlen, +" Active and Waiting Request Queues (Time Unit: %d HZ):\n", HZ); + ASC_PRT_NEXT(); -ASC_INITFUNC( -STATIC ushort -AscInitGetConfig( - ASC_DVC_VAR asc_ptr_type * asc_dvc -) -) -{ - ushort warn_code; - PortAddr iop_base; - ushort PCIDeviceID; - ushort PCIVendorID; - uchar PCIRevisionID; - uchar prevCmdRegBits; + active = &ASC_BOARDP(shp)->active; + waiting = &ASC_BOARDP(shp)->waiting; - warn_code = 0; - iop_base = asc_dvc->iop_base; - asc_dvc->init_state = ASC_INIT_STATE_BEG_GET_CFG; - if (asc_dvc->err_code != 0) { - return (UW_ERR); + 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 (asc_dvc->bus_type == ASC_IS_PCI) { - PCIVendorID = AscReadPCIConfigWord(asc_dvc, - AscPCIConfigVendorIDRegister); - - PCIDeviceID = AscReadPCIConfigWord(asc_dvc, - AscPCIConfigDeviceIDRegister); - PCIRevisionID = DvcReadPCIConfigByte(asc_dvc, - AscPCIConfigRevisionIDRegister); + for (i = 0; i <= ADV_MAX_TID; i++) { - if (PCIVendorID != ASC_PCI_VENDORID) { - warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE; + if ((chip_scsi_id == i) || + ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { + continue; } - prevCmdRegBits = DvcReadPCIConfigByte(asc_dvc, - AscPCIConfigCommandRegister); - if ((prevCmdRegBits & AscPCICmdRegBits_IOMemBusMaster) != - AscPCICmdRegBits_IOMemBusMaster) { - DvcWritePCIConfigByte(asc_dvc, - AscPCIConfigCommandRegister, - (prevCmdRegBits | - AscPCICmdRegBits_IOMemBusMaster)); + 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(); - if ((DvcReadPCIConfigByte(asc_dvc, - AscPCIConfigCommandRegister) - & AscPCICmdRegBits_IOMemBusMaster) - != AscPCICmdRegBits_IOMemBusMaster) { - warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE; - } - } - if ((PCIDeviceID == ASC_PCI_DEVICEID_1200A) || - (PCIDeviceID == ASC_PCI_DEVICEID_1200B)) { - DvcWritePCIConfigByte(asc_dvc, - AscPCIConfigLatencyTimer, 0x00); - if (DvcReadPCIConfigByte(asc_dvc, AscPCIConfigLatencyTimer) - != 0x00) { - warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE; - } - } else if (PCIDeviceID == ASC_PCI_DEVICEID_ULTRA) { - if (DvcReadPCIConfigByte(asc_dvc, - AscPCIConfigLatencyTimer) < 0x20) { - DvcWritePCIConfigByte(asc_dvc, - AscPCIConfigLatencyTimer, 0x20); + len = asc_prt_line(cp, leftlen, +" active: cnt [cur %d, max %d, tot %u], time [min %d, max %d, avg %lu.%01lu]\n", + active->q_cur_cnt[i], active->q_max_cnt[i], + active->q_tot_cnt[i], + active->q_min_tim[i], active->q_max_tim[i], + (active->q_tot_cnt[i] == 0) ? 0 : + (active->q_tot_tim[i]/active->q_tot_cnt[i]), + (active->q_tot_cnt[i] == 0) ? 0 : + ASC_TENTHS(active->q_tot_tim[i], active->q_tot_cnt[i])); + ASC_PRT_NEXT(); - if (DvcReadPCIConfigByte(asc_dvc, - AscPCIConfigLatencyTimer) < 0x20) { - warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE; - } - } + len = asc_prt_line(cp, leftlen, +" waiting: cnt [cur %d, max %d, tot %u], time [min %u, max %u, avg %lu.%01lu]\n", + waiting->q_cur_cnt[i], waiting->q_max_cnt[i], + waiting->q_tot_cnt[i], + waiting->q_min_tim[i], waiting->q_max_tim[i], + (waiting->q_tot_cnt[i] == 0) ? 0 : + (waiting->q_tot_tim[i]/waiting->q_tot_cnt[i]), + (waiting->q_tot_cnt[i] == 0) ? 0 : + ASC_TENTHS(waiting->q_tot_tim[i], waiting->q_tot_cnt[i])); + ASC_PRT_NEXT(); } } - if (AscFindSignature(iop_base)) { - warn_code |= AscInitAscDvcVar(asc_dvc); - warn_code |= AscInitFromEEP(asc_dvc); - asc_dvc->init_state |= ASC_INIT_STATE_END_GET_CFG; - if (asc_dvc->scsi_reset_wait > ASC_MAX_SCSI_RESET_WAIT) { - asc_dvc->scsi_reset_wait = ASC_MAX_SCSI_RESET_WAIT; - } - } else { - asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE; - } - return(warn_code); + return totlen; } +#endif /* ADVANSYS_STATS */ -ASC_INITFUNC( -STATIC ushort -AscInitSetConfig( - ASC_DVC_VAR asc_ptr_type * asc_dvc -) -) +#ifdef ADVANSYS_DEBUG +/* + * asc_prt_scsi_host() + */ +STATIC void +asc_prt_scsi_host(struct Scsi_Host *s) { - ushort warn_code; - warn_code = 0; - asc_dvc->init_state |= ASC_INIT_STATE_BEG_SET_CFG; - if (asc_dvc->err_code != 0) - return (UW_ERR); - if (AscFindSignature(asc_dvc->iop_base)) { - warn_code |= AscInitFromAscDvcVar(asc_dvc); - asc_dvc->init_state |= ASC_INIT_STATE_END_SET_CFG; + 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); + + 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); + + printk( +" wish_block %d, base %x, io_port %d, n_io_port %d, irq %d, dma_channel %d,\n", + s->wish_block, (unsigned) s->base, s->io_port, s->n_io_port, + s->irq, s->dma_channel); + + printk( +" this_id %d, can_queue %d,\n", s->this_id, s->can_queue); + + printk( +" cmd_per_lun %d, sg_tablesize %d, unchecked_isa_dma %d, loaded_as_module %d\n", + s->cmd_per_lun, s->sg_tablesize, s->unchecked_isa_dma, + s->loaded_as_module); + + 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_dvc->err_code = ASC_IERR_BAD_SIGNATURE; + 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); } - return (warn_code); } -ASC_INITFUNC( -STATIC ushort -AscInitFromAscDvcVar( - ASC_DVC_VAR asc_ptr_type * asc_dvc -) -) +/* + * asc_prt_scsi_cmnd() + */ +STATIC void +asc_prt_scsi_cmnd(Scsi_Cmnd *s) { - PortAddr iop_base; - 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; - cfg_msw = AscGetChipCfgMsw(iop_base); - if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) { - cfg_msw &= (~(ASC_CFG_MSW_CLR_MASK)); - warn_code |= ASC_WARN_CFG_MSW_RECOVER; - AscSetChipCfgMsw(iop_base, cfg_msw); - } - if ((asc_dvc->cfg->cmd_qng_enabled & asc_dvc->cfg->disc_enable) != - asc_dvc->cfg->cmd_qng_enabled) { - asc_dvc->cfg->disc_enable = asc_dvc->cfg->cmd_qng_enabled; - warn_code |= ASC_WARN_CMD_QNG_CONFLICT; - } - if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) { - warn_code |= ASC_WARN_AUTO_CONFIG; - } - if ((asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL)) != 0) { - if (AscSetChipIRQ(iop_base, asc_dvc->irq_no, asc_dvc->bus_type) - != asc_dvc->irq_no) { - asc_dvc->err_code |= ASC_IERR_SET_IRQ_NO; - } - } - 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) || - (pci_device_id == ASC_PCI_DEVICE_ID_REV_B)) { - asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_IF_NOT_DWB; - asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_ASYN_USE_SYN; - } - } - } else if (asc_dvc->bus_type == ASC_IS_ISAPNP) { - if (AscGetChipVersion(iop_base, asc_dvc->bus_type) - == ASC_CHIP_VER_ASYN_BUG) { - asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_ASYN_USE_SYN; - } - } - if (AscSetChipScsiID(iop_base, asc_dvc->cfg->chip_scsi_id) != - asc_dvc->cfg->chip_scsi_id) { - asc_dvc->err_code |= ASC_IERR_SET_SCSI_ID; - } + printk("Scsi_Cmnd at addr %x\n", (unsigned) s); + +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0) + printk( +" host %x, device %x, target %u, lun %u\n", + (unsigned) s->host, (unsigned) s->device, s->target, s->lun); +#else /* version >= v1.3.0 */ + printk( +" host %x, device %x, target %u, lun %u, channel %u,\n", + (unsigned) s->host, (unsigned) s->device, s->target, s->lun, + s->channel); +#endif /* version >= v1.3.0 */ + + asc_prt_hex(" CDB", s->cmnd, s->cmd_len); + + printk( +" use_sg %u, sglist_len %u, abort_reason %x\n", + s->use_sg, s->sglist_len, s->abort_reason); + +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,89) + printk( +" retries %d, allowed %d\n", + s->retries, s->allowed); +#else /* version >= v1.3.89 */ + printk( +" serial_number %x, serial_number_at_timeout %x, retries %d, allowed %d\n", + (unsigned) s->serial_number, (unsigned) s->serial_number_at_timeout, + s->retries, s->allowed); +#endif /* version >= v1.3.89 */ + + printk( +" timeout_per_command %d, timeout_total %d, timeout %d\n", + s->timeout_per_command, s->timeout_total, s->timeout); + + printk( +" internal_timeout %u, flags %u, this_count %d\n", + s->internal_timeout, s->flags, s->this_count); + + printk( +" scsi_done %x, done %x, host_scribble %x, result %x\n", + (unsigned) s->scsi_done, (unsigned) s->done, + (unsigned) s->host_scribble, s->result); + + printk( +" tag %u, pid %u\n", + (unsigned) s->tag, (unsigned) s->pid); +} + +/* + * asc_prt_asc_dvc_var() + */ +STATIC void +asc_prt_asc_dvc_var(ASC_DVC_VAR *h) +{ + printk("ASC_DVC_VAR at addr %x\n", (unsigned) h); + + printk( +" iop_base %x, err_code %x, dvc_cntl %x, bug_fix_cntl %d,\n", + h->iop_base, h->err_code, h->dvc_cntl, h->bug_fix_cntl); + + printk( +" bus_type %d, isr_callback %x, exe_callback %x, init_sdtr %x,\n", + h->bus_type, (unsigned) h->isr_callback, (unsigned) h->exe_callback, + (unsigned) h->init_sdtr); + + printk( +" sdtr_done %x, use_tagged_qng %x, unit_not_ready %x, chip_no %x,\n", + (unsigned) h->sdtr_done, (unsigned) h->use_tagged_qng, + (unsigned) h->unit_not_ready, (unsigned) h->chip_no); + + printk( +" queue_full_or_busy %x, start_motor %x, scsi_reset_wait %x, irq_no %x,\n", + (unsigned) h->queue_full_or_busy, (unsigned) h->start_motor, + (unsigned) h->scsi_reset_wait, (unsigned) h->irq_no); + + printk( +" is_in_int %x, max_total_qng %x, cur_total_qng %x, in_critical_cnt %x,\n", + (unsigned) h->is_in_int, (unsigned) h->max_total_qng, + (unsigned) h->cur_total_qng, (unsigned) h->in_critical_cnt); + + printk( +" last_q_shortage %x, init_state %x, no_scam %x, pci_fix_asyn_xfer %x,\n", + (unsigned) h->last_q_shortage, (unsigned) h->init_state, + (unsigned) h->no_scam, (unsigned) h->pci_fix_asyn_xfer); + + printk( +" cfg %x, saved_ptr2func %x\n", + (unsigned) h->cfg, (unsigned) h->saved_ptr2func); +} + +/* + * asc_prt_asc_dvc_cfg() + */ +STATIC void +asc_prt_asc_dvc_cfg(ASC_DVC_CFG *h) +{ + printk("ASC_DVC_CFG at addr %x\n", (unsigned) h); + + printk( +" can_tagged_qng %x, cmd_qng_enabled %x, disc_enable %x, res %x,\n", + h->can_tagged_qng, h->cmd_qng_enabled, h->disc_enable, h->res); + + printk( +" chip_scsi_id %d, isa_dma_speed %d, isa_dma_channel %d, chip_version %d,\n", + h->chip_scsi_id, h->isa_dma_speed, h->isa_dma_channel, + h->chip_version); + + printk( +" 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( +" mcode_version %d, overrun_buf %x\n", + h->mcode_version, (unsigned) h->overrun_buf); +} + +/* + * asc_prt_asc_scsi_q() + */ +STATIC void +asc_prt_asc_scsi_q(ASC_SCSI_Q *q) +{ + ASC_SG_HEAD *sgp; + int i; + + printk("ASC_SCSI_Q at addr %x\n", (unsigned) q); + + printk( +" target_ix %u, target_lun %u, srb_ptr %x, tag_code %u,\n", + q->q2.target_ix, q->q1.target_lun, + (unsigned) q->q2.srb_ptr, q->q2.tag_code); + + printk( +" data_addr %x, data_cnt %lu, sense_addr %x, sense_len %u,\n", + (unsigned) q->q1.data_addr, q->q1.data_cnt, + (unsigned) q->q1.sense_addr, q->q1.sense_len); + + printk( +" cdbptr %x, cdb_len %u, sg_head %x, sg_queue_cnt %u\n", + (unsigned) q->cdbptr, q->q2.cdb_len, + (unsigned) q->sg_head, q->q1.sg_queue_cnt); + + if (q->sg_head) { + sgp = q->sg_head; + printk("ASC_SG_HEAD at addr %x\n", (unsigned) sgp); + printk(" entry_cnt %u, queue_cnt %u\n", sgp->entry_cnt, sgp->queue_cnt); + for (i = 0; i < sgp->entry_cnt; i++) { + printk(" [%u]: addr %x, bytes %lu\n", + i, (unsigned) sgp->sg_list[i].addr, sgp->sg_list[i].bytes); + } + + } +} + +/* + * asc_prt_asc_qdone_info() + */ +STATIC void +asc_prt_asc_qdone_info(ASC_QDONE_INFO *q) +{ + printk("ASC_QDONE_INFO at addr %x\n", (unsigned) q); + printk( +" srb_ptr %x, target_ix %u, cdb_len %u, tag_code %u, done_stat %x\n", + (unsigned) q->d2.srb_ptr, q->d2.target_ix, q->d2.cdb_len, + q->d2.tag_code, q->d3.done_stat); + printk( +" host_stat %x, scsi_stat %x, scsi_msg %x\n", + q->d3.host_stat, q->d3.scsi_stat, q->d3.scsi_msg); +} + +/* + * asc_prt_adv_dvc_var() + * + * Display an ADV_DVC_VAR structure. + */ +STATIC void +asc_prt_adv_dvc_var(ADV_DVC_VAR *h) +{ + printk(" ADV_DVC_VAR at addr 0x%lx\n", (ulong) h); + + 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); + + 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); + + 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]); + } + + switch (m) { + case 0: + default: + break; + case 1: + printk(" %2.2X", + (unsigned) s[i+(j*4)]); + break; + case 2: + printk(" %2.2X%2.2X", + (unsigned) s[i+(j*4)], + (unsigned) s[i+(j*4)+1]); + break; + case 3: + printk(" %2.2X%2.2X%2.2X", + (unsigned) s[i+(j*4)+1], + (unsigned) s[i+(j*4)+2], + (unsigned) s[i+(j*4)+3]); + break; + } + + printk("\n"); + } +} +#endif /* ADVANSYS_DEBUG */ + +#ifdef ADVANSYS_ASSERT +/* + * interrupts_enabled() + * + * Return 1 if interrupts are enabled, otherwise return 0. + */ +STATIC int +interrupts_enabled(void) +{ + int flags; + + save_flags(flags); + if (flags & 0x0200) { + return ASC_TRUE; + } else { + return ASC_FALSE; + } +} +#endif /* ADVANSYS_ASSERT */ + + +/* + * --- Asc Library Functions + */ + +ASC_INITFUNC( +STATIC ushort +AscGetEisaChipCfg( + PortAddr iop_base +) +) +{ + 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)); +} + +ASC_INITFUNC( +STATIC uchar +AscSetChipScsiID( + PortAddr iop_base, + uchar new_host_id +) +) +{ + ushort cfg_lsw; + + if (AscGetChipScsiID(iop_base) == new_host_id) { + return (new_host_id); + } + cfg_lsw = AscGetChipCfgLsw(iop_base); + cfg_lsw &= 0xF8FF; + cfg_lsw |= (ushort) ((new_host_id & ASC_MAX_TID) << 8); + AscSetChipCfgLsw(iop_base, cfg_lsw); + return (AscGetChipScsiID(iop_base)); +} + +ASC_INITFUNC( +STATIC uchar +AscGetChipScsiCtrl( + PortAddr iop_base +) +) +{ + uchar sc; + + AscSetBank(iop_base, 1); + sc = inp(iop_base + IOP_REG_SC); + AscSetBank(iop_base, 0); + return (sc); +} + +ASC_INITFUNC( +STATIC uchar +AscGetChipVersion( + PortAddr iop_base, + ushort bus_type +) +) +{ + if ((bus_type & ASC_IS_EISA) != 0) { + PortAddr eisa_iop; + uchar revision; + eisa_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) | + (PortAddr) ASC_EISA_REV_IOP_MASK; + revision = inp(eisa_iop); + return ((uchar) ((ASC_CHIP_MIN_VER_EISA - 1) + revision)); + } + return (AscGetChipVerNo(iop_base)); +} + +ASC_INITFUNC( +STATIC ushort +AscGetChipBusType( + PortAddr iop_base +) +) +{ + ushort chip_ver; + + chip_ver = AscGetChipVerNo(iop_base); + if ( + (chip_ver >= ASC_CHIP_MIN_VER_VL) + && (chip_ver <= ASC_CHIP_MAX_VER_VL) +) { + if ( + ((iop_base & 0x0C30) == 0x0C30) + || ((iop_base & 0x0C50) == 0x0C50) +) { + return (ASC_IS_EISA); + } + return (ASC_IS_VL); + } + if ((chip_ver >= ASC_CHIP_MIN_VER_ISA) && + (chip_ver <= ASC_CHIP_MAX_VER_ISA)) { + if (chip_ver >= ASC_CHIP_MIN_VER_ISA_PNP) { + return (ASC_IS_ISAPNP); + } + return (ASC_IS_ISA); + } else if ((chip_ver >= ASC_CHIP_MIN_VER_PCI) && + (chip_ver <= ASC_CHIP_MAX_VER_PCI)) { + return (ASC_IS_PCI); + } + return (0); +} + +ASC_INITFUNC( +STATIC ulong +AscLoadMicroCode( + PortAddr iop_base, + ushort s_addr, + ushort *mcode_buf, + ushort mcode_size +) +) +{ + 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); + chksum = AscMemSumLramWord(iop_base, s_addr, mcode_word_size); + mcode_chksum = (ushort) AscMemSumLramWord(iop_base, + (ushort) ASC_CODE_SEC_BEG, + (ushort) ((mcode_size - s_addr - (ushort) ASC_CODE_SEC_BEG) / 2)); + AscWriteLramWord(iop_base, ASCV_MCODE_CHKSUM_W, mcode_chksum); + AscWriteLramWord(iop_base, ASCV_MCODE_SIZE_W, mcode_size); + return (chksum); +} + +ASC_INITFUNC( +STATIC int +AscFindSignature( + PortAddr iop_base +) +) +{ + ushort sig_word; + + if (AscGetChipSignatureByte(iop_base) == (uchar) ASC_1000_ID1B) { + sig_word = AscGetChipSignatureWord(iop_base); + if ((sig_word == (ushort) ASC_1000_ID0W) || + (sig_word == (ushort) ASC_1000_ID0W_FIX)) { + return (1); + } + } + return (0); +} + +STATIC uchar _isa_pnp_inited ASC_INITDATA = 0; +STATIC PortAddr _asc_def_iop_base[ASC_IOADR_TABLE_MAX_IX] ASC_INITDATA = +{ + 0x100, ASC_IOADR_1, 0x120, ASC_IOADR_2, 0x140, ASC_IOADR_3, ASC_IOADR_4, + ASC_IOADR_5, ASC_IOADR_6, ASC_IOADR_7, ASC_IOADR_8 +}; + +ASC_INITFUNC( +STATIC PortAddr +AscSearchIOPortAddr( + PortAddr iop_beg, + ushort bus_type +) +) +{ + if (bus_type & ASC_IS_VL) { + while ((iop_beg = AscSearchIOPortAddr11(iop_beg)) != 0) { + if (AscGetChipVersion(iop_beg, bus_type) <= ASC_CHIP_MAX_VER_VL) { + return (iop_beg); + } + } + return (0); + } + if (bus_type & ASC_IS_ISA) { + if (_isa_pnp_inited == 0) { + AscSetISAPNPWaitForKey(); + _isa_pnp_inited++; + } + while ((iop_beg = AscSearchIOPortAddr11(iop_beg)) != 0) { + if ((AscGetChipVersion(iop_beg, bus_type) & ASC_CHIP_VER_ISA_BIT) != 0) { + return (iop_beg); + } + } + return (0); + } + if (bus_type & ASC_IS_EISA) { + if ((iop_beg = AscSearchIOPortAddrEISA(iop_beg)) != 0) { + return (iop_beg); + } + return (0); + } + return (0); +} + +ASC_INITFUNC( +STATIC PortAddr +AscSearchIOPortAddr11( + PortAddr s_addr +) +) +{ + int i; + PortAddr iop_base; + + for (i = 0; i < ASC_IOADR_TABLE_MAX_IX; i++) { + if (_asc_def_iop_base[i] > s_addr) { + break; + } + } + for (; i < ASC_IOADR_TABLE_MAX_IX; i++) { + iop_base = _asc_def_iop_base[i]; + if (check_region(iop_base, ASC_IOADR_GAP) != 0) { + ASC_DBG1(1, + "AscSearchIOPortAddr11: check_region() failed I/O port %x\n", + iop_base); + continue; + } + ASC_DBG1(1, "AscSearchIOPortAddr11: probing I/O port %x\n", iop_base); + if (AscFindSignature(iop_base)) { + return (iop_base); + } + } + return (0); +} + +ASC_INITFUNC( +STATIC void +AscToggleIRQAct( + PortAddr iop_base +) +) +{ + AscSetChipStatus(iop_base, CIW_IRQ_ACT); + AscSetChipStatus(iop_base, 0); + return; +} + +ASC_INITFUNC( +STATIC void +AscSetISAPNPWaitForKey( + void) +) +{ + outp(ASC_ISA_PNP_PORT_ADDR, 0x02); + outp(ASC_ISA_PNP_PORT_WRITE, 0x02); + return; +} + +ASC_INITFUNC( +STATIC uchar +AscGetChipIRQ( + PortAddr iop_base, + ushort bus_type +) +) +{ + 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); + if ((chip_irq == 13) || (chip_irq > 15)) { + return (0); + } + return (chip_irq); + } + if ((bus_type & ASC_IS_VL) != 0) { + cfg_lsw = AscGetChipCfgLsw(iop_base); + chip_irq = (uchar) (((cfg_lsw >> 2) & 0x07)); + if ((chip_irq == 0) || + (chip_irq == 4) || + (chip_irq == 7)) { + return (0); + } + return ((uchar) (chip_irq + (ASC_MIN_IRQ_NO - 1))); + } + cfg_lsw = AscGetChipCfgLsw(iop_base); + chip_irq = (uchar) (((cfg_lsw >> 2) & 0x03)); + if (chip_irq == 3) + chip_irq += (uchar) 2; + return ((uchar) (chip_irq + ASC_MIN_IRQ_NO)); +} + +ASC_INITFUNC( +STATIC uchar +AscSetChipIRQ( + PortAddr iop_base, + uchar irq_no, + ushort bus_type +) +) +{ + ushort cfg_lsw; + + if ((bus_type & ASC_IS_VL) != 0) { + if (irq_no != 0) { + if ((irq_no < ASC_MIN_IRQ_NO) || (irq_no > ASC_MAX_IRQ_NO)) { + irq_no = 0; + } else { + irq_no -= (uchar) ((ASC_MIN_IRQ_NO - 1)); + } + } + cfg_lsw = (ushort) (AscGetChipCfgLsw(iop_base) & 0xFFE3); + cfg_lsw |= (ushort) 0x0010; + AscSetChipCfgLsw(iop_base, cfg_lsw); + AscToggleIRQAct(iop_base); + cfg_lsw = (ushort) (AscGetChipCfgLsw(iop_base) & 0xFFE0); + cfg_lsw |= (ushort) ((irq_no & 0x07) << 2); + AscSetChipCfgLsw(iop_base, cfg_lsw); + AscToggleIRQAct(iop_base); + return (AscGetChipIRQ(iop_base, bus_type)); + } + if ((bus_type & (ASC_IS_ISA)) != 0) { + if (irq_no == 15) + irq_no -= (uchar) 2; + irq_no -= (uchar) ASC_MIN_IRQ_NO; + cfg_lsw = (ushort) (AscGetChipCfgLsw(iop_base) & 0xFFF3); + cfg_lsw |= (ushort) ((irq_no & 0x03) << 2); + AscSetChipCfgLsw(iop_base, cfg_lsw); + return (AscGetChipIRQ(iop_base, bus_type)); + } + return (0); +} + +ASC_INITFUNC( +STATIC void +AscEnableIsaDma( + uchar dma_channel +) +) +{ + if (dma_channel < 4) { + outp(0x000B, (ushort) (0xC0 | dma_channel)); + outp(0x000A, dma_channel); + } else if (dma_channel < 8) { + outp(0x00D6, (ushort) (0xC0 | (dma_channel - 4))); + outp(0x00D4, (ushort) (dma_channel - 4)); + } + return; +} + +STATIC int +AscIsrChipHalted( + REG ASC_DVC_VAR asc_ptr_type * asc_dvc +) +{ + EXT_MSG ext_msg; + EXT_MSG out_msg; + ushort halt_q_addr; + int sdtr_accept; + ushort int_halt_code; + ASC_SCSI_BIT_ID_TYPE scsi_busy; + ASC_SCSI_BIT_ID_TYPE target_id; + PortAddr iop_base; + uchar tag_code; + uchar q_status; + uchar halt_qp; + uchar sdtr_data; + uchar target_ix; + uchar q_cntl, tid_no; + uchar cur_dvc_qng; + uchar asyn_sdtr; + uchar scsi_status; + asc_board_t *boardp; + + ASC_ASSERT(asc_dvc->drv_ptr != 0); + boardp = (asc_board_t *) asc_dvc->drv_ptr; + + iop_base = asc_dvc->iop_base; + int_halt_code = AscReadLramWord(iop_base, ASCV_HALTCODE_W); + + halt_qp = AscReadLramByte(iop_base, ASCV_CURCDB_B); + halt_q_addr = ASC_QNO_TO_QADDR(halt_qp); + target_ix = AscReadLramByte(iop_base, + (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_TARGET_IX)); + q_cntl = AscReadLramByte(iop_base, + (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_CNTL)); + tid_no = ASC_TIX_TO_TID(target_ix); + target_id = (uchar) ASC_TID_TO_TARGET_ID(tid_no); + if (asc_dvc->pci_fix_asyn_xfer & target_id) { + + asyn_sdtr = ASYN_SDTR_DATA_FIX_PCI_REV_AB; + } else { + asyn_sdtr = 0; + } + if (int_halt_code == ASC_HALT_DISABLE_ASYN_USE_SYN_FIX) { + if (asc_dvc->pci_fix_asyn_xfer & target_id) { + AscSetChipSDTR(iop_base, 0, tid_no); + boardp->sdtr_data[tid_no] = 0; + } + AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0); + return (0); + } else if (int_halt_code == ASC_HALT_ENABLE_ASYN_USE_SYN_FIX) { + if (asc_dvc->pci_fix_asyn_xfer & target_id) { + AscSetChipSDTR(iop_base, asyn_sdtr, tid_no); + boardp->sdtr_data[tid_no] = asyn_sdtr; + } + AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0); + return (0); + } else if (int_halt_code == ASC_HALT_EXTMSG_IN) { + + AscMemWordCopyFromLram(iop_base, + ASCV_MSGIN_BEG, + (ushort *) & ext_msg, + (ushort) (sizeof (EXT_MSG) >> 1)); + + if (ext_msg.msg_type == MS_EXTEND && + ext_msg.msg_req == MS_SDTR_CODE && + ext_msg.msg_len == MS_SDTR_LEN) { + sdtr_accept = TRUE; + if ((ext_msg.req_ack_offset > ASC_SYN_MAX_OFFSET)) { + + sdtr_accept = FALSE; + ext_msg.req_ack_offset = ASC_SYN_MAX_OFFSET; + } + if ((ext_msg.xfer_period < + asc_dvc->sdtr_period_tbl[asc_dvc->host_init_sdtr_index]) || + (ext_msg.xfer_period > + asc_dvc->sdtr_period_tbl[asc_dvc->max_sdtr_index])) { + sdtr_accept = FALSE; + ext_msg.xfer_period = + asc_dvc->sdtr_period_tbl[asc_dvc->host_init_sdtr_index]; + } + if (sdtr_accept) { + sdtr_data = AscCalSDTRData(asc_dvc, ext_msg.xfer_period, + ext_msg.req_ack_offset); + if ((sdtr_data == 0xFF)) { + + q_cntl |= QC_MSG_OUT; + asc_dvc->init_sdtr &= ~target_id; + asc_dvc->sdtr_done &= ~target_id; + AscSetChipSDTR(iop_base, asyn_sdtr, tid_no); + boardp->sdtr_data[tid_no] = asyn_sdtr; + } + } + if (ext_msg.req_ack_offset == 0) { + + q_cntl &= ~QC_MSG_OUT; + asc_dvc->init_sdtr &= ~target_id; + asc_dvc->sdtr_done &= ~target_id; + AscSetChipSDTR(iop_base, asyn_sdtr, tid_no); + } else { + if (sdtr_accept && (q_cntl & QC_MSG_OUT)) { + + q_cntl &= ~QC_MSG_OUT; + asc_dvc->sdtr_done |= target_id; + asc_dvc->init_sdtr |= target_id; + asc_dvc->pci_fix_asyn_xfer &= ~target_id; + sdtr_data = AscCalSDTRData(asc_dvc, ext_msg.xfer_period, + ext_msg.req_ack_offset); + AscSetChipSDTR(iop_base, sdtr_data, tid_no); + boardp->sdtr_data[tid_no] = sdtr_data; + } else { + + q_cntl |= QC_MSG_OUT; + AscMsgOutSDTR(asc_dvc, + ext_msg.xfer_period, + ext_msg.req_ack_offset); + asc_dvc->pci_fix_asyn_xfer &= ~target_id; + sdtr_data = AscCalSDTRData(asc_dvc, ext_msg.xfer_period, + ext_msg.req_ack_offset); + AscSetChipSDTR(iop_base, sdtr_data, tid_no); + boardp->sdtr_data[tid_no] = sdtr_data; + asc_dvc->sdtr_done |= target_id; + asc_dvc->init_sdtr |= target_id; + } + } + + AscWriteLramByte(iop_base, + (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_CNTL), + q_cntl); + AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0); + return (0); + } else if (ext_msg.msg_type == MS_EXTEND && + ext_msg.msg_req == MS_WDTR_CODE && + ext_msg.msg_len == MS_WDTR_LEN) { + + ext_msg.wdtr_width = 0; + AscMemWordCopyToLram(iop_base, + ASCV_MSGOUT_BEG, + (ushort *) & ext_msg, + (ushort) (sizeof (EXT_MSG) >> 1)); + q_cntl |= QC_MSG_OUT; + AscWriteLramByte(iop_base, + (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_CNTL), + q_cntl); + AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0); + return (0); + } else { + + ext_msg.msg_type = M1_MSG_REJECT; + AscMemWordCopyToLram(iop_base, + ASCV_MSGOUT_BEG, + (ushort *) & ext_msg, + (ushort) (sizeof (EXT_MSG) >> 1)); + q_cntl |= QC_MSG_OUT; + AscWriteLramByte(iop_base, + (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_CNTL), + q_cntl); + AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0); + return (0); + } + } else if (int_halt_code == ASC_HALT_CHK_CONDITION) { + + q_cntl |= QC_REQ_SENSE; + + if ((asc_dvc->init_sdtr & target_id) != 0) { + + asc_dvc->sdtr_done &= ~target_id; + + sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no); + q_cntl |= QC_MSG_OUT; + AscMsgOutSDTR(asc_dvc, + asc_dvc->sdtr_period_tbl[(sdtr_data >> 4) & + (uchar) (asc_dvc->max_sdtr_index - 1)], + (uchar) (sdtr_data & (uchar) ASC_SYN_MAX_OFFSET)); + } + + AscWriteLramByte(iop_base, + (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_CNTL), + q_cntl); + + tag_code = AscReadLramByte(iop_base, + (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_TAG_CODE)); + tag_code &= 0xDC; + if ( + (asc_dvc->pci_fix_asyn_xfer & target_id) + && !(asc_dvc->pci_fix_asyn_xfer_always & target_id) +) { + + tag_code |= (ASC_TAG_FLAG_DISABLE_DISCONNECT + | ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX); + + } + AscWriteLramByte(iop_base, + (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_TAG_CODE), + tag_code); + + q_status = AscReadLramByte(iop_base, + (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_STATUS)); + q_status |= (QS_READY | QS_BUSY); + AscWriteLramByte(iop_base, + (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_STATUS), + q_status); + + scsi_busy = AscReadLramByte(iop_base, + (ushort) ASCV_SCSIBUSY_B); + scsi_busy &= ~target_id; + AscWriteLramByte(iop_base, (ushort) ASCV_SCSIBUSY_B, scsi_busy); + + AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0); + return (0); + } else if (int_halt_code == ASC_HALT_SDTR_REJECTED) { + + AscMemWordCopyFromLram(iop_base, + ASCV_MSGOUT_BEG, + (ushort *) & out_msg, + (ushort) (sizeof (EXT_MSG) >> 1)); + + if ((out_msg.msg_type == MS_EXTEND) && + (out_msg.msg_len == MS_SDTR_LEN) && + (out_msg.msg_req == MS_SDTR_CODE)) { + + asc_dvc->init_sdtr &= ~target_id; + asc_dvc->sdtr_done &= ~target_id; + AscSetChipSDTR(iop_base, asyn_sdtr, tid_no); + boardp->sdtr_data[tid_no] = asyn_sdtr; + } + q_cntl &= ~QC_MSG_OUT; + AscWriteLramByte(iop_base, + (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_CNTL), + q_cntl); + AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0); + return (0); + } else if (int_halt_code == ASC_HALT_SS_QUEUE_FULL) { + + scsi_status = AscReadLramByte(iop_base, + (ushort) ((ushort) halt_q_addr + (ushort) ASC_SCSIQ_SCSI_STATUS)); + cur_dvc_qng = AscReadLramByte(iop_base, + (ushort) ((ushort) ASC_QADR_BEG + (ushort) target_ix)); + if ((cur_dvc_qng > 0) && + (asc_dvc->cur_dvc_qng[tid_no] > 0)) { + + scsi_busy = AscReadLramByte(iop_base, + (ushort) ASCV_SCSIBUSY_B); + scsi_busy |= target_id; + AscWriteLramByte(iop_base, + (ushort) ASCV_SCSIBUSY_B, scsi_busy); + asc_dvc->queue_full_or_busy |= target_id; + + if (scsi_status == SS_QUEUE_FULL) { + if (cur_dvc_qng > ASC_MIN_TAGGED_CMD) { + cur_dvc_qng -= 1; + asc_dvc->max_dvc_qng[tid_no] = cur_dvc_qng; + + AscWriteLramByte(iop_base, + (ushort) ((ushort) ASCV_MAX_DVC_QNG_BEG + + (ushort) tid_no), + cur_dvc_qng); + + /* + * Set the device queue depth to the number of + * active requests when the QUEUE FULL condition + * was encountered. + */ + boardp->queue_full |= target_id; + boardp->queue_full_cnt[tid_no] = cur_dvc_qng; +#if ASC_QUEUE_FLOW_CONTROL + 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; + } +#endif /* ASC_QUEUE_FLOW_CONTROL */ + } + } + } + AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0); + return (0); + } + return (0); +} + +STATIC uchar +_AscCopyLramScsiDoneQ( + PortAddr iop_base, + ushort q_addr, + REG ASC_QDONE_INFO * scsiq, + ulong max_dma_count +) +{ + 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)); + _val = AscReadLramWord(iop_base, + (ushort) (q_addr + (ushort) ASC_SCSIQ_B_STATUS)); + scsiq->q_status = (uchar) _val; + scsiq->q_no = (uchar) (_val >> 8); + _val = AscReadLramWord(iop_base, + (ushort) (q_addr + (ushort) ASC_SCSIQ_B_CNTL)); + scsiq->cntl = (uchar) _val; + sg_queue_cnt = (uchar) (_val >> 8); + _val = AscReadLramWord(iop_base, + (ushort) (q_addr + (ushort) ASC_SCSIQ_B_SENSE_LEN)); + scsiq->sense_len = (uchar) _val; + scsiq->extra_bytes = (uchar) (_val >> 8); + scsiq->remain_bytes = AscReadLramWord(iop_base, + (ushort) (q_addr + (ushort) ASC_SCSIQ_DW_REMAIN_XFER_CNT)); + scsiq->remain_bytes &= max_dma_count; + return (sg_queue_cnt); +} + +STATIC int +AscIsrQDone( + REG ASC_DVC_VAR asc_ptr_type * asc_dvc +) +{ + uchar next_qp; + uchar n_q_used; + uchar sg_list_qp; + uchar sg_queue_cnt; + uchar q_cnt; + uchar done_q_tail; + uchar tid_no; + ASC_SCSI_BIT_ID_TYPE scsi_busy; + ASC_SCSI_BIT_ID_TYPE target_id; + PortAddr iop_base; + ushort q_addr; + ushort sg_q_addr; + uchar cur_target_qng; + ASC_QDONE_INFO scsiq_buf; + 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; + scsiq = (ASC_QDONE_INFO *) & scsiq_buf; + done_q_tail = (uchar) AscGetVarDoneQTail(iop_base); + q_addr = ASC_QNO_TO_QADDR(done_q_tail); + next_qp = AscReadLramByte(iop_base, + (ushort) (q_addr + (ushort) ASC_SCSIQ_B_FWD)); + if (next_qp != ASC_QLINK_END) { + AscPutVarDoneQTail(iop_base, next_qp); + q_addr = ASC_QNO_TO_QADDR(next_qp); + sg_queue_cnt = _AscCopyLramScsiDoneQ(iop_base, q_addr, scsiq, + asc_dvc->max_dma_count); + AscWriteLramByte(iop_base, + (ushort) (q_addr + (ushort) ASC_SCSIQ_B_STATUS), + (uchar) (scsiq->q_status & (uchar) ~ (QS_READY | QS_ABORTED))); + tid_no = ASC_TIX_TO_TID(scsiq->d2.target_ix); + target_id = ASC_TIX_TO_TARGET_ID(scsiq->d2.target_ix); + if ((scsiq->cntl & QC_SG_HEAD) != 0) { + sg_q_addr = q_addr; + sg_list_qp = next_qp; + for (q_cnt = 0; q_cnt < sg_queue_cnt; q_cnt++) { + sg_list_qp = AscReadLramByte(iop_base, + (ushort) (sg_q_addr + (ushort) ASC_SCSIQ_B_FWD)); + sg_q_addr = ASC_QNO_TO_QADDR(sg_list_qp); + if (sg_list_qp == ASC_QLINK_END) { + AscSetLibErrorCode(asc_dvc, ASCQ_ERR_SG_Q_LINKS); + scsiq->d3.done_stat = QD_WITH_ERROR; + scsiq->d3.host_stat = QHSTA_D_QDONE_SG_LIST_CORRUPTED; + goto FATAL_ERR_QDONE; + } + AscWriteLramByte(iop_base, + (ushort) (sg_q_addr + (ushort) ASC_SCSIQ_B_STATUS), + QS_FREE); + } + n_q_used = sg_queue_cnt + 1; + AscPutVarDoneQTail(iop_base, sg_list_qp); + } + if (asc_dvc->queue_full_or_busy & target_id) { + cur_target_qng = AscReadLramByte(iop_base, + (ushort) ((ushort) ASC_QADR_BEG + (ushort) scsiq->d2.target_ix)); + if (cur_target_qng < asc_dvc->max_dvc_qng[tid_no]) { + scsi_busy = AscReadLramByte(iop_base, + (ushort) ASCV_SCSIBUSY_B); + scsi_busy &= ~target_id; + AscWriteLramByte(iop_base, + (ushort) ASCV_SCSIBUSY_B, scsi_busy); + asc_dvc->queue_full_or_busy &= ~target_id; + } + } + if (asc_dvc->cur_total_qng >= n_q_used) { + asc_dvc->cur_total_qng -= n_q_used; + if (asc_dvc->cur_dvc_qng[tid_no] != 0) { + asc_dvc->cur_dvc_qng[tid_no]--; + } + } else { + AscSetLibErrorCode(asc_dvc, ASCQ_ERR_CUR_QNG); + scsiq->d3.done_stat = QD_WITH_ERROR; + goto FATAL_ERR_QDONE; + } + if ((scsiq->d2.srb_ptr == 0UL) || + ((scsiq->q_status & QS_ABORTED) != 0)) { + return (0x11); + } else if (scsiq->q_status == QS_DONE) { + false_overrun = FALSE; + if (scsiq->extra_bytes != 0) { + scsiq->remain_bytes += (ulong) scsiq->extra_bytes; + } + if (scsiq->d3.done_stat == QD_WITH_ERROR) { + if (scsiq->d3.host_stat == QHSTA_M_DATA_OVER_RUN) { + if ((scsiq->cntl & (QC_DATA_IN | QC_DATA_OUT)) == 0) { + scsiq->d3.done_stat = QD_NO_ERROR; + scsiq->d3.host_stat = QHSTA_NO_ERROR; + } else if (false_overrun) { + scsiq->d3.done_stat = QD_NO_ERROR; + scsiq->d3.host_stat = QHSTA_NO_ERROR; + } + } else if (scsiq->d3.host_stat == + QHSTA_M_HUNG_REQ_SCSI_BUS_RESET) { + AscStopChip(iop_base); + AscSetChipControl(iop_base, + (uchar) (CC_SCSI_RESET | CC_HALT)); + 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 ((scsiq->cntl & QC_NO_CALLBACK) == 0) { + (*asc_isr_callback) (asc_dvc, scsiq); + } else { + if ((AscReadLramByte(iop_base, + (ushort) (q_addr + (ushort) ASC_SCSIQ_CDB_BEG)) == + SCSICMD_StartStopUnit)) { + asc_dvc->unit_not_ready &= ~target_id; + if (scsiq->d3.done_stat != QD_NO_ERROR) { + asc_dvc->start_motor &= ~target_id; + } + } + } + return (1); + } else { + AscSetLibErrorCode(asc_dvc, ASCQ_ERR_Q_STATUS); + FATAL_ERR_QDONE: + if ((scsiq->cntl & QC_NO_CALLBACK) == 0) { + (*asc_isr_callback) (asc_dvc, scsiq); + } + return (0x80); + } + } + return (0); +} + +STATIC int +AscISR( + REG ASC_DVC_VAR asc_ptr_type * asc_dvc +) +{ + ASC_CS_TYPE chipstat; + PortAddr iop_base; + ushort saved_ram_addr; + uchar ctrl_reg; + uchar saved_ctrl_reg; + 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) + || (asc_dvc->isr_callback == 0) +) { + return (ERR); + } + if (asc_dvc->in_critical_cnt != 0) { + AscSetLibErrorCode(asc_dvc, ASCQ_ERR_ISR_ON_CRITICAL); + return (ERR); + } + if (asc_dvc->is_in_int) { + AscSetLibErrorCode(asc_dvc, ASCQ_ERR_ISR_RE_ENTRY); + return (ERR); + } + asc_dvc->is_in_int = TRUE; + ctrl_reg = AscGetChipControl(iop_base); + saved_ctrl_reg = ctrl_reg & (~(CC_SCSI_RESET | CC_CHIP_RESET | + CC_SINGLE_STEP | CC_DIAG | CC_TEST)); + chipstat = AscGetChipStatus(iop_base); + if (chipstat & CSW_SCSI_RESET_LATCH) { + if (!(asc_dvc->bus_type & (ASC_IS_VL | ASC_IS_EISA))) { + int_pending = TRUE; + asc_dvc->sdtr_done = 0; + saved_ctrl_reg &= (uchar) (~CC_HALT); + while (AscGetChipStatus(iop_base) & CSW_SCSI_RESET_ACTIVE) ; + AscSetChipControl(iop_base, (CC_CHIP_RESET | CC_HALT)); + AscSetChipControl(iop_base, CC_HALT); + AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT); + AscSetChipStatus(iop_base, 0); + chipstat = AscGetChipStatus(iop_base); + } + } + saved_ram_addr = AscGetChipLramAddr(iop_base); + host_flag = AscReadLramByte(iop_base, + 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 ((chipstat & CSW_INT_PENDING) + || (int_pending) +) { + AscAckInterrupt(iop_base); + int_pending = TRUE; + if ((chipstat & CSW_HALTED) && + (ctrl_reg & CC_SINGLE_STEP)) { + if (AscIsrChipHalted(asc_dvc) == ERR) { + goto ISR_REPORT_QDONE_FATAL_ERROR; + } else { + saved_ctrl_reg &= (uchar) (~CC_HALT); + } + } else { + ISR_REPORT_QDONE_FATAL_ERROR: + if ((asc_dvc->dvc_cntl & ASC_CNTL_INT_MULTI_Q) != 0) { + while (((status = AscIsrQDone(asc_dvc)) & 0x01) != 0) { + } + } else { + do { + if ((status = AscIsrQDone(asc_dvc)) == 1) { + break; + } + } while (status == 0x11); + } + if ((status & 0x80) != 0) + int_pending = ERR; + } + } + AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag); + AscSetChipLramAddr(iop_base, saved_ram_addr); + AscSetChipControl(iop_base, saved_ctrl_reg); + asc_dvc->is_in_int = FALSE; + return (int_pending); +} + +STATIC int +AscScsiSetupCmdQ( + REG ASC_DVC_VAR asc_ptr_type * asc_dvc, + REG ASC_SCSI_REQ_Q * scsiq, + uchar * buf_addr, + ulong buf_len +) +{ + ulong phy_addr; + + scsiq->r1.cntl = 0; + scsiq->r1.sg_queue_cnt = 0; + scsiq->r1.q_no = 0; + scsiq->r1.extra_bytes = 0; + scsiq->r3.scsi_stat = 0; + scsiq->r3.scsi_msg = 0; + scsiq->r3.host_stat = 0; + scsiq->r3.done_stat = 0; + scsiq->r2.vm_id = 0; + scsiq->r1.data_cnt = buf_len; + scsiq->cdbptr = (uchar *) scsiq->cdb; + scsiq->sense_ptr = (uchar *) scsiq->sense ; + scsiq->r1.sense_len = ASC_MIN_SENSE_LEN ; + scsiq->r2.tag_code = (uchar) M2_QTAG_MSG_SIMPLE; + scsiq->r2.flag = (uchar) ASC_FLAG_SCSIQ_REQ; + scsiq->r2.srb_ptr = (ulong) scsiq; + scsiq->r1.status = (uchar) QS_READY; + scsiq->r1.data_addr = 0L; + if (buf_len != 0L) { + if ((phy_addr = AscGetOnePhyAddr(asc_dvc, + (uchar *) buf_addr, scsiq->r1.data_cnt)) == 0L) { + return (ERR); + } + scsiq->r1.data_addr = phy_addr; + } + if ((phy_addr = AscGetOnePhyAddr(asc_dvc, + (uchar *) scsiq->sense_ptr, + (ulong) scsiq->r1.sense_len)) == 0L) { + return (ERR); + } + scsiq->r1.sense_addr = phy_addr ; + return (0); +} + +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, 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 _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] = +{ + SCSICMD_Inquiry, + SCSICMD_RequestSense, + SCSICMD_ReadCapacity, + SCSICMD_ReadTOC, + SCSICMD_ModeSelect6, + SCSICMD_ModeSense6, + SCSICMD_ModeSelect10, + SCSICMD_ModeSense10, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF +}; + +STATIC int +AscExeScsiQueue( + REG ASC_DVC_VAR asc_ptr_type * asc_dvc, + REG ASC_SCSI_Q * scsiq +) +{ + PortAddr iop_base; + int last_int_level; + int sta; + int n_q_required; + int disable_syn_offset_one_fix; + int i; + ulong addr; + ASC_EXE_CALLBACK asc_exe_callback; + ushort sg_entry_cnt = 0; + ushort sg_entry_cnt_minus_one = 0; + uchar target_ix; + uchar tid_no; + uchar sdtr_data; + uchar extra_bytes; + uchar scsi_cmd; + 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; + if (asc_dvc->err_code != 0) + return (ERR); + if (scsiq == (ASC_SCSI_Q *) 0L) { + AscSetLibErrorCode(asc_dvc, ASCQ_ERR_SCSIQ_NULL_PTR); + return (ERR); + } + scsiq->q1.q_no = 0; + if ((scsiq->q2.tag_code & ASC_TAG_FLAG_EXTRA_BYTES) == 0) { + scsiq->q1.extra_bytes = 0; + } + sta = 0; + target_ix = scsiq->q2.target_ix; + tid_no = ASC_TIX_TO_TID(target_ix); + n_q_required = 1; + if (scsiq->cdbptr[0] == SCSICMD_RequestSense) { + if ((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) { + asc_dvc->sdtr_done &= ~scsiq->q1.target_id ; + sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no); + AscMsgOutSDTR(asc_dvc, + asc_dvc->sdtr_period_tbl[(sdtr_data >> 4) & + (uchar) (asc_dvc->max_sdtr_index - 1)], + (uchar) (sdtr_data & (uchar) ASC_SYN_MAX_OFFSET)); + scsiq->q1.cntl |= (QC_MSG_OUT | QC_URGENT); + } + } + last_int_level = DvcEnterCritical(); + if (asc_dvc->in_critical_cnt != 0) { + DvcLeaveCritical(last_int_level); + AscSetLibErrorCode(asc_dvc, ASCQ_ERR_CRITICAL_RE_ENTRY); + return (ERR); + } + asc_dvc->in_critical_cnt++; + if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) { + if ((sg_entry_cnt = sg_head->entry_cnt) == 0) { + asc_dvc->in_critical_cnt--; + DvcLeaveCritical(last_int_level); + return (ERR); + } + if (sg_entry_cnt > ASC_MAX_SG_LIST) { + return (ERR); + } + if (sg_entry_cnt == 1) { + scsiq->q1.data_addr = sg_head->sg_list[0].addr; + scsiq->q1.data_cnt = sg_head->sg_list[0].bytes; + scsiq->q1.cntl &= ~(QC_SG_HEAD | QC_SG_SWAP_QUEUE); + } + sg_entry_cnt_minus_one = sg_entry_cnt - 1; + } + scsi_cmd = scsiq->cdbptr[0]; + disable_syn_offset_one_fix = FALSE; + if ((asc_dvc->pci_fix_asyn_xfer & scsiq->q1.target_id) && + !(asc_dvc->pci_fix_asyn_xfer_always & scsiq->q1.target_id)) { + if (scsiq->q1.cntl & QC_SG_HEAD) { + data_cnt = 0; + for (i = 0; i < sg_entry_cnt; i++) { + data_cnt += sg_head->sg_list[i].bytes; + } + } else { + data_cnt = scsiq->q1.data_cnt; + } + if (data_cnt != 0UL) { + if (data_cnt < 512UL) { + disable_syn_offset_one_fix = TRUE; + } else { + for (i = 0; i < ASC_SYN_OFFSET_ONE_DISABLE_LIST; i++) { + disable_cmd = _syn_offset_one_disable_cmd[i]; + if (disable_cmd == 0xFF) { + break; + } + if (scsi_cmd == disable_cmd) { + disable_syn_offset_one_fix = TRUE; + break; + } + } + } + } + } + if (disable_syn_offset_one_fix) { + scsiq->q2.tag_code &= ~M2_QTAG_MSG_SIMPLE; + scsiq->q2.tag_code |= (ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX | + ASC_TAG_FLAG_DISABLE_DISCONNECT); + } else { + scsiq->q2.tag_code &= 0x23; + } + if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) { + if (asc_dvc->bug_fix_cntl) { + if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) { + if ((scsi_cmd == SCSICMD_Read6) || + (scsi_cmd == SCSICMD_Read10)) { + addr = sg_head->sg_list[sg_entry_cnt_minus_one].addr + + sg_head->sg_list[sg_entry_cnt_minus_one].bytes; + extra_bytes = (uchar) ((ushort) addr & 0x0003); + if ((extra_bytes != 0) && + ((scsiq->q2.tag_code & ASC_TAG_FLAG_EXTRA_BYTES) + == 0)) { + scsiq->q2.tag_code |= ASC_TAG_FLAG_EXTRA_BYTES; + scsiq->q1.extra_bytes = extra_bytes; + sg_head->sg_list[sg_entry_cnt_minus_one].bytes -= + (ulong) extra_bytes; + } + } + } + } + sg_head->entry_to_copy = sg_head->entry_cnt; + n_q_required = AscSgListToQueue(sg_entry_cnt); + if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, n_q_required) >= + (uint) n_q_required) || ((scsiq->q1.cntl & QC_URGENT) != 0)) { + if ((sta = AscSendScsiQueue(asc_dvc, scsiq, + n_q_required)) == 1) { + asc_dvc->in_critical_cnt--; + if (asc_exe_callback != 0) { + (*asc_exe_callback) (asc_dvc, scsiq); + } + DvcLeaveCritical(last_int_level); + return (sta); + } + } + } else { + if (asc_dvc->bug_fix_cntl) { + if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) { + if ((scsi_cmd == SCSICMD_Read6) || + (scsi_cmd == SCSICMD_Read10)) { + addr = scsiq->q1.data_addr + scsiq->q1.data_cnt; + extra_bytes = (uchar) ((ushort) addr & 0x0003); + if ((extra_bytes != 0) && + ((scsiq->q2.tag_code & ASC_TAG_FLAG_EXTRA_BYTES) + == 0)) { + if (((ushort) scsiq->q1.data_cnt & 0x01FF) == 0) { + scsiq->q2.tag_code |= ASC_TAG_FLAG_EXTRA_BYTES; + scsiq->q1.data_cnt -= (ulong) extra_bytes; + scsiq->q1.extra_bytes = extra_bytes; + } + } + } + } + } + n_q_required = 1; + if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, 1) >= 1) || + ((scsiq->q1.cntl & QC_URGENT) != 0)) { + if ((sta = AscSendScsiQueue(asc_dvc, scsiq, + n_q_required)) == 1) { + asc_dvc->in_critical_cnt--; + if (asc_exe_callback != 0) { + (*asc_exe_callback) (asc_dvc, scsiq); + } + DvcLeaveCritical(last_int_level); + return (sta); + } + } + } + asc_dvc->in_critical_cnt--; + DvcLeaveCritical(last_int_level); + return (sta); +} + +STATIC int +AscSendScsiQueue( + REG ASC_DVC_VAR asc_ptr_type * asc_dvc, + REG ASC_SCSI_Q * scsiq, + uchar n_q_required +) +{ + PortAddr iop_base; + uchar free_q_head; + uchar next_qp; + 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); + sta = 0; + free_q_head = (uchar) AscGetVarFreeQHead(iop_base); + if (n_q_required > 1) { + if ((next_qp = AscAllocMultipleFreeQueue(iop_base, + free_q_head, (uchar) (n_q_required))) + != (uchar) ASC_QLINK_END) { + asc_dvc->last_q_shortage = 0; + scsiq->sg_head->queue_cnt = n_q_required - 1; + scsiq->q1.q_no = free_q_head; + if ((sta = AscPutReadySgListQueue(asc_dvc, scsiq, + free_q_head)) == 1) { + AscPutVarFreeQHead(iop_base, next_qp); + asc_dvc->cur_total_qng += (uchar) (n_q_required); + asc_dvc->cur_dvc_qng[tid_no]++; + } + return (sta); + } + } else if (n_q_required == 1) { + if ((next_qp = AscAllocFreeQueue(iop_base, + free_q_head)) != ASC_QLINK_END) { + scsiq->q1.q_no = free_q_head; + if ((sta = AscPutReadyQueue(asc_dvc, scsiq, + free_q_head)) == 1) { + AscPutVarFreeQHead(iop_base, next_qp); + asc_dvc->cur_total_qng++; + asc_dvc->cur_dvc_qng[tid_no]++; + } + return (sta); + } + } + return (sta); +} + +STATIC int +AscSgListToQueue( + int sg_list +) +{ + 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++; + return (n_sg_list_qs + 1); +} + + +STATIC uint +AscGetNumOfFreeQueue( + REG ASC_DVC_VAR asc_ptr_type * asc_dvc, + uchar target_ix, + uchar n_qs +) +{ + uint cur_used_qs; + 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) || + (asc_dvc->queue_full_or_busy & target_id)) { + return (0); + } + if (n_qs == 1) { + cur_used_qs = (uint) asc_dvc->cur_total_qng + + (uint) asc_dvc->last_q_shortage + + (uint) ASC_MIN_FREE_Q; + } else { + cur_used_qs = (uint) asc_dvc->cur_total_qng + + (uint) ASC_MIN_FREE_Q; + } + if ((uint) (cur_used_qs + n_qs) <= (uint) asc_dvc->max_total_qng) { + cur_free_qs = (uint) asc_dvc->max_total_qng - cur_used_qs; + if (asc_dvc->cur_dvc_qng[tid_no] >= + asc_dvc->max_dvc_qng[tid_no]) { + return (0); + } + return (cur_free_qs); + } + if (n_qs > 1) { + if ((n_qs > asc_dvc->last_q_shortage) && (n_qs <= (asc_dvc->max_total_qng - ASC_MIN_FREE_Q))) { + asc_dvc->last_q_shortage = n_qs; + } + } + return (0); +} + +STATIC int +AscPutReadyQueue( + REG ASC_DVC_VAR asc_ptr_type * asc_dvc, + REG ASC_SCSI_Q * scsiq, + uchar q_no +) +{ + ushort q_addr; + uchar tid_no; + uchar sdtr_data; + 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)) { + tid_no = ASC_TIX_TO_TID(scsiq->q2.target_ix); + sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no); + syn_period_ix = (sdtr_data >> 4) & (asc_dvc->max_sdtr_index - 1); + syn_offset = sdtr_data & ASC_SYN_MAX_OFFSET; + AscMsgOutSDTR(asc_dvc, + asc_dvc->sdtr_period_tbl[syn_period_ix], + syn_offset); + scsiq->q1.cntl |= QC_MSG_OUT; + } + q_addr = ASC_QNO_TO_QADDR(q_no); + if ((scsiq->q1.target_id & asc_dvc->use_tagged_qng) == 0) { + scsiq->q2.tag_code &= ~M2_QTAG_MSG_SIMPLE; + } + scsiq->q1.status = QS_FREE; + AscMemWordCopyToLram(iop_base, + (ushort) (q_addr + (ushort) ASC_SCSIQ_CDB_BEG), + (ushort *) scsiq->cdbptr, + (ushort) ((ushort) scsiq->q2.cdb_len >> 1)); + 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))); + AscWriteLramWord(iop_base, + (ushort) (q_addr + (ushort) ASC_SCSIQ_B_STATUS), + (ushort) (((ushort) scsiq->q1.q_no << 8) | (ushort) QS_READY)); + return (1); +} + +STATIC int +AscPutReadySgListQueue( + REG ASC_DVC_VAR asc_ptr_type * asc_dvc, + REG ASC_SCSI_Q * scsiq, + uchar q_no +) +{ + int sta; + int i; + ASC_SG_HEAD *sg_head; + ASC_SG_LIST_Q scsi_sg_q; + ulong saved_data_addr; + ulong saved_data_cnt; + PortAddr iop_base; + ushort sg_list_dwords; + ushort sg_index; + 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; + saved_data_cnt = scsiq->q1.data_cnt; + scsiq->q1.data_addr = sg_head->sg_list[0].addr; + scsiq->q1.data_cnt = sg_head->sg_list[0].bytes; + sg_entry_cnt = sg_head->entry_cnt - 1; + if (sg_entry_cnt != 0) { + scsiq->q1.cntl |= QC_SG_HEAD; + q_addr = ASC_QNO_TO_QADDR(q_no); + sg_index = 1; + scsiq->q1.sg_queue_cnt = sg_head->queue_cnt; + scsi_sg_q.sg_head_qp = q_no; + scsi_sg_q.cntl = QCSG_SG_XFER_LIST; + for (i = 0; i < sg_head->queue_cnt; i++) { + scsi_sg_q.seq_no = i + 1; + if (sg_entry_cnt > ASC_SG_LIST_PER_Q) { + sg_list_dwords = (uchar) (ASC_SG_LIST_PER_Q * 2); + sg_entry_cnt -= ASC_SG_LIST_PER_Q; + if (i == 0) { + scsi_sg_q.sg_list_cnt = ASC_SG_LIST_PER_Q; + scsi_sg_q.sg_cur_list_cnt = ASC_SG_LIST_PER_Q; + } else { + scsi_sg_q.sg_list_cnt = ASC_SG_LIST_PER_Q - 1; + scsi_sg_q.sg_cur_list_cnt = ASC_SG_LIST_PER_Q - 1; + } + } else { + scsi_sg_q.cntl |= QCSG_SG_XFER_END; + sg_list_dwords = sg_entry_cnt << 1; + if (i == 0) { + scsi_sg_q.sg_list_cnt = sg_entry_cnt; + scsi_sg_q.sg_cur_list_cnt = sg_entry_cnt; + } else { + scsi_sg_q.sg_list_cnt = sg_entry_cnt - 1; + scsi_sg_q.sg_cur_list_cnt = sg_entry_cnt - 1; + } + sg_entry_cnt = 0; + } + next_qp = AscReadLramByte(iop_base, + (ushort) (q_addr + ASC_SCSIQ_B_FWD)); + scsi_sg_q.q_no = next_qp; + q_addr = ASC_QNO_TO_QADDR(next_qp); + AscMemWordCopyToLram(iop_base, + (ushort) (q_addr + ASC_SCSIQ_SGHD_CPY_BEG), + (ushort *) & scsi_sg_q, + (ushort) (sizeof (ASC_SG_LIST_Q) >> 1)); + AscMemDWordCopyToLram(iop_base, + (ushort) (q_addr + ASC_SGQ_LIST_BEG), + (ulong *) & sg_head->sg_list[sg_index], + (ushort) sg_list_dwords); + sg_index += ASC_SG_LIST_PER_Q; + } + } else { + scsiq->q1.cntl &= ~QC_SG_HEAD; + } + sta = AscPutReadyQueue(asc_dvc, scsiq, q_no); + scsiq->q1.data_addr = saved_data_addr; + scsiq->q1.data_cnt = saved_data_cnt; + return (sta); +} + +STATIC int +AscAbortSRB( + REG ASC_DVC_VAR asc_ptr_type * asc_dvc, + ulong srb_ptr +) +{ + 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; + asc_dvc->unit_not_ready = 0xFF; + AscWaitISRDone(asc_dvc); + if (AscStopQueueExe(iop_base) == 1) { + if (AscRiscHaltedAbortSRB(asc_dvc, srb_ptr) == 1) { + sta = 1; + AscCleanUpBusyQueue(iop_base); + AscStartQueueExe(iop_base); + } else { + sta = 0; + AscStartQueueExe(iop_base); + } + } + asc_dvc->unit_not_ready = saved_unit_not_ready; + return (sta); +} + +#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) +STATIC int +AscResetDevice( + REG ASC_DVC_VAR asc_ptr_type * asc_dvc, + uchar target_ix +) +{ + PortAddr iop_base; + int sta; + uchar tid_no; + + ASC_SCSI_BIT_ID_TYPE target_id; + int i; + ASC_SCSI_REQ_Q scsiq_buf; + ASC_SCSI_REQ_Q *scsiq; + uchar *buf; + ASC_SCSI_BIT_ID_TYPE saved_unit_not_ready; + iop_base = asc_dvc->iop_base; + tid_no = ASC_TIX_TO_TID(target_ix); + target_id = ASC_TID_TO_TARGET_ID(tid_no); + saved_unit_not_ready = asc_dvc->unit_not_ready; + asc_dvc->unit_not_ready = target_id; + sta = ERR; + AscWaitTixISRDone(asc_dvc, target_ix); + if (AscStopQueueExe(iop_base) == 1) { + if (AscRiscHaltedAbortTIX(asc_dvc, target_ix) == 1) { + AscCleanUpBusyQueue(iop_base); + AscStartQueueExe(iop_base); + AscWaitTixISRDone(asc_dvc, target_ix); + sta = TRUE; + scsiq = (ASC_SCSI_REQ_Q *) & scsiq_buf; + buf = (uchar *) & scsiq_buf; + for (i = 0; i < sizeof (ASC_SCSI_REQ_Q); i++) { + *buf++ = 0x00; + } + scsiq->r1.status = (uchar) QS_READY; + scsiq->r2.cdb_len = 6; + scsiq->r2.tag_code = M2_QTAG_MSG_SIMPLE; + scsiq->r1.target_id = target_id; + scsiq->r2.target_ix = ASC_TIDLUN_TO_IX(tid_no, 0); + scsiq->cdbptr = (uchar *) scsiq->cdb; + scsiq->r1.cntl = QC_NO_CALLBACK | QC_MSG_OUT | QC_URGENT; + AscWriteLramByte(asc_dvc->iop_base, ASCV_MSGOUT_BEG, + M1_BUS_DVC_RESET); + asc_dvc->unit_not_ready &= ~target_id; + asc_dvc->sdtr_done |= target_id; + if (AscExeScsiQueue(asc_dvc, (ASC_SCSI_Q *) scsiq) + == 1) { + asc_dvc->unit_not_ready = target_id; + DvcSleepMilliSecond(1000); + _AscWaitQDone(iop_base, (ASC_SCSI_Q *) scsiq); + if (AscStopQueueExe(iop_base) == 1) { + AscCleanUpDiscQueue(iop_base); + AscStartQueueExe(iop_base); + if (asc_dvc->pci_fix_asyn_xfer & target_id) { + AscSetRunChipSynRegAtID(iop_base, tid_no, + ASYN_SDTR_DATA_FIX_PCI_REV_AB); + } + AscWaitTixISRDone(asc_dvc, target_ix); + } + } else { + sta = 0; + } + asc_dvc->sdtr_done &= ~target_id; + } else { + sta = ERR; + AscStartQueueExe(iop_base); + } + } + asc_dvc->unit_not_ready = saved_unit_not_ready; + return (sta); +} +#endif /* version >= v1.3.89 */ + +STATIC int +AscResetSB( + REG ASC_DVC_VAR asc_ptr_type * asc_dvc +) +{ + 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(asc_dvc); + DvcSleepMilliSecond((ulong) ((ushort) asc_dvc->scsi_reset_wait * 1000)); + AscReInitLram(asc_dvc); + for (i = 0; i <= ASC_MAX_TID; i++) { + asc_dvc->cur_dvc_qng[i] = 0; + if (asc_dvc->pci_fix_asyn_xfer & (ASC_SCSI_BIT_ID_TYPE) (0x01 << i)) { + AscSetChipSynRegAtID(iop_base, i, ASYN_SDTR_DATA_FIX_PCI_REV_AB); + } + } + asc_dvc->err_code = 0; + AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR); + if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) { + sta = ERR; + } + if (AscStartChip(iop_base) == 0) { + sta = ERR; + } + AscStartQueueExe(iop_base); + asc_dvc->unit_not_ready = 0; + asc_dvc->queue_full_or_busy = 0; + return (sta); +} + +STATIC int +AscSetRunChipSynRegAtID( + PortAddr iop_base, + uchar tid_no, + uchar sdtr_data +) +{ + int sta = FALSE; + + if (AscHostReqRiscHalt(iop_base)) { + sta = AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data); + AscStartChip(iop_base); + return (sta); + } + return (sta); +} + +STATIC int +AscSetChipSynRegAtID( + PortAddr iop_base, + uchar id, + uchar sdtr_data +) +{ + ASC_SCSI_BIT_ID_TYPE org_id; + int i; + int sta = TRUE; + + AscSetBank(iop_base, 1); + org_id = AscReadChipDvcID(iop_base); + for (i = 0; i <= ASC_MAX_TID; i++) { + if (org_id == (0x01 << i)) + break; + } + org_id = i; + AscWriteChipDvcID(iop_base, id); + if (AscReadChipDvcID(iop_base) == (0x01 << id)) { + AscSetBank(iop_base, 0); + AscSetChipSyn(iop_base, sdtr_data); + if (AscGetChipSyn(iop_base) != sdtr_data) { + sta = FALSE; + } + } else { + sta = FALSE; + } + AscSetBank(iop_base, 1); + AscWriteChipDvcID(iop_base, org_id); + AscSetBank(iop_base, 0); + return (sta); +} + +STATIC int +AscReInitLram( + REG ASC_DVC_VAR asc_ptr_type * asc_dvc +) +{ + AscInitLram(asc_dvc); + AscInitQLinkVar(asc_dvc); + return (0); +} + +STATIC ushort +AscInitLram( + REG ASC_DVC_VAR asc_ptr_type * asc_dvc +) +{ + uchar i; + 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, + (ushort) (((int) (asc_dvc->max_total_qng + 2 + 1) * 64) >> 1) +); + i = ASC_MIN_ACTIVE_QNO; + s_addr = ASC_QADR_BEG + ASC_QBLK_SIZE; + AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_FWD), + (uchar) (i + 1)); + AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_BWD), + (uchar) (asc_dvc->max_total_qng)); + AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_QNO), + (uchar) i); + i++; + s_addr += ASC_QBLK_SIZE; + for (; i < asc_dvc->max_total_qng; i++, s_addr += ASC_QBLK_SIZE) { + AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_FWD), + (uchar) (i + 1)); + AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_BWD), + (uchar) (i - 1)); + AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_QNO), + (uchar) i); + } + AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_FWD), + (uchar) ASC_QLINK_END); + AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_BWD), + (uchar) (asc_dvc->max_total_qng - 1)); + AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_QNO), + (uchar) asc_dvc->max_total_qng); + i++; + s_addr += ASC_QBLK_SIZE; + for (; i <= (uchar) (asc_dvc->max_total_qng + 3); + i++, s_addr += ASC_QBLK_SIZE) { + AscWriteLramByte(iop_base, + (ushort) (s_addr + (ushort) ASC_SCSIQ_B_FWD), i); + AscWriteLramByte(iop_base, + (ushort) (s_addr + (ushort) ASC_SCSIQ_B_BWD), i); + AscWriteLramByte(iop_base, + (ushort) (s_addr + (ushort) ASC_SCSIQ_B_QNO), i); + } + return (warn_code); +} + +STATIC ushort +AscInitQLinkVar( + REG ASC_DVC_VAR asc_ptr_type * asc_dvc +) +{ + 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); + AscPutVarFreeQHead(iop_base, 1); + AscPutVarDoneQTail(iop_base, asc_dvc->max_total_qng); + AscWriteLramByte(iop_base, ASCV_BUSY_QHEAD_B, + (uchar) ((int) asc_dvc->max_total_qng + 1)); + AscWriteLramByte(iop_base, ASCV_DISC1_QHEAD_B, + (uchar) ((int) asc_dvc->max_total_qng + 2)); + AscWriteLramByte(iop_base, (ushort) ASCV_TOTAL_READY_Q_B, + asc_dvc->max_total_qng); + AscWriteLramWord(iop_base, ASCV_ASCDVC_ERR_CODE_W, 0); + AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0); + AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, 0); + AscWriteLramByte(iop_base, ASCV_SCSIBUSY_B, 0); + AscWriteLramByte(iop_base, ASCV_WTM_FLAG_B, 0); + AscPutQDoneInProgress(iop_base, 0); + lram_addr = ASC_QADR_BEG; + for (i = 0; i < 32; i++, lram_addr += 2) { + AscWriteLramWord(iop_base, lram_addr, 0); + } + return (0); +} + +STATIC int +AscSetLibErrorCode( + REG ASC_DVC_VAR asc_ptr_type * asc_dvc, + ushort err_code +) +{ + if (asc_dvc->err_code == 0) { + asc_dvc->err_code = err_code; + AscWriteLramWord(asc_dvc->iop_base, ASCV_ASCDVC_ERR_CODE_W, + err_code); + } + return (err_code); +} + + +#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) +STATIC int +_AscWaitQDone( + PortAddr iop_base, + REG ASC_SCSI_Q * scsiq +) +{ + 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 { + q_status = AscReadLramByte(iop_base, q_addr + ASC_SCSIQ_B_STATUS); + DvcSleepMilliSecond(100L); + if (count++ > 30) { + return (0); + } + } while ((q_status & QS_READY) != 0); + return (1); +} +#endif /* version >= v1.3.89 */ + +STATIC uchar +AscMsgOutSDTR( + REG ASC_DVC_VAR asc_ptr_type * asc_dvc, + uchar sdtr_period, + uchar sdtr_offset +) +{ + EXT_MSG sdtr_buf; + uchar sdtr_period_index; + PortAddr iop_base; + + iop_base = asc_dvc->iop_base; + sdtr_buf.msg_type = MS_EXTEND; + sdtr_buf.msg_len = MS_SDTR_LEN; + sdtr_buf.msg_req = MS_SDTR_CODE; + sdtr_buf.xfer_period = sdtr_period; + sdtr_offset &= ASC_SYN_MAX_OFFSET; + sdtr_buf.req_ack_offset = sdtr_offset; + if ((sdtr_period_index = + AscGetSynPeriodIndex(asc_dvc, sdtr_period)) <= + asc_dvc->max_sdtr_index) { + AscMemWordCopyToLram(iop_base, + ASCV_MSGOUT_BEG, + (ushort *) & sdtr_buf, + (ushort) (sizeof (EXT_MSG) >> 1)); + return ((sdtr_period_index << 4) | sdtr_offset); + } else { + + sdtr_buf.req_ack_offset = 0; + AscMemWordCopyToLram(iop_base, + ASCV_MSGOUT_BEG, + (ushort *) & sdtr_buf, + (ushort) (sizeof (EXT_MSG) >> 1)); + return (0); + } +} + +STATIC uchar +AscCalSDTRData( + REG ASC_DVC_VAR asc_ptr_type * asc_dvc, + uchar sdtr_period, + uchar syn_offset +) +{ + uchar byte; + uchar sdtr_period_ix; + + sdtr_period_ix = AscGetSynPeriodIndex(asc_dvc, sdtr_period); + if ( + (sdtr_period_ix > asc_dvc->max_sdtr_index) +) { + return (0xFF); + } + byte = (sdtr_period_ix << 4) | (syn_offset & ASC_SYN_MAX_OFFSET); + return (byte); +} + +STATIC void +AscSetChipSDTR( + PortAddr iop_base, + uchar sdtr_data, + uchar tid_no +) +{ + AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data); + AscPutMCodeSDTRDoneAtID(iop_base, tid_no, sdtr_data); + return; +} + +STATIC uchar +AscGetSynPeriodIndex( + ASC_DVC_VAR asc_ptr_type * asc_dvc, + ruchar syn_time +) +{ + ruchar *period_table; + 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 ; + if ((syn_time <= period_table[max_index])) { + for (i = min_index; i < (max_index - 1); i++) { + if (syn_time <= period_table[i]) { + return ((uchar) i); + } + } + return ((uchar) max_index); + } else { + return ((uchar) (max_index + 1)); + } +} + +STATIC uchar +AscAllocFreeQueue( + PortAddr iop_base, + uchar free_q_head +) +{ + 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)); + next_qp = AscReadLramByte(iop_base, + (ushort) (q_addr + ASC_SCSIQ_B_FWD)); + if (((q_status & QS_READY) == 0) && (next_qp != ASC_QLINK_END)) { + return (next_qp); + } + return (ASC_QLINK_END); +} + +STATIC uchar +AscAllocMultipleFreeQueue( + PortAddr iop_base, + uchar free_q_head, + uchar n_free_q +) +{ + uchar i; + + for (i = 0; i < n_free_q; i++) { + if ((free_q_head = AscAllocFreeQueue(iop_base, free_q_head)) + == ASC_QLINK_END) { + return (ASC_QLINK_END); + } + } + return (free_q_head); +} + +STATIC int +AscRiscHaltedAbortSRB( + REG ASC_DVC_VAR asc_ptr_type * asc_dvc, + ulong srb_ptr +) +{ + PortAddr iop_base; + ushort q_addr; + uchar q_no; + ASC_QDONE_INFO scsiq_buf; + 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(); + scsiq = (ASC_QDONE_INFO *) & scsiq_buf; + for (q_no = ASC_MIN_ACTIVE_QNO; q_no <= asc_dvc->max_total_qng; + q_no++) { + q_addr = ASC_QNO_TO_QADDR(q_no); + scsiq->d2.srb_ptr = AscReadLramDWord(iop_base, + (ushort) (q_addr + (ushort) ASC_SCSIQ_D_SRBPTR)); + if (scsiq->d2.srb_ptr == srb_ptr) { + _AscCopyLramScsiDoneQ(iop_base, q_addr, scsiq, asc_dvc->max_dma_count); + if (((scsiq->q_status & QS_READY) != 0) + && ((scsiq->q_status & QS_ABORTED) == 0) + && ((scsiq->cntl & QCSG_SG_XFER_LIST) == 0)) { + scsiq->q_status |= QS_ABORTED; + scsiq->d3.done_stat = QD_ABORTED_BY_HOST; + AscWriteLramDWord(iop_base, + (ushort) (q_addr + (ushort) ASC_SCSIQ_D_SRBPTR), + 0L); + AscWriteLramByte(iop_base, + (ushort) (q_addr + (ushort) ASC_SCSIQ_B_STATUS), + scsiq->q_status); + (*asc_isr_callback) (asc_dvc, scsiq); + return (1); + } + } + } + DvcLeaveCritical(last_int_level); + return (0); +} + +#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) +STATIC int +AscRiscHaltedAbortTIX( + REG ASC_DVC_VAR asc_ptr_type * asc_dvc, + uchar target_ix +) +{ + PortAddr iop_base; + ushort q_addr; + uchar q_no; + ASC_QDONE_INFO scsiq_buf; + 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(); + scsiq = (ASC_QDONE_INFO *) & scsiq_buf; + for (q_no = ASC_MIN_ACTIVE_QNO; q_no <= asc_dvc->max_total_qng; + q_no++) { + q_addr = ASC_QNO_TO_QADDR(q_no); + _AscCopyLramScsiDoneQ(iop_base, q_addr, scsiq, asc_dvc->max_dma_count); + if (((scsiq->q_status & QS_READY) != 0) && + ((scsiq->q_status & QS_ABORTED) == 0) && + ((scsiq->cntl & QCSG_SG_XFER_LIST) == 0)) { + if (scsiq->d2.target_ix == target_ix) { + scsiq->q_status |= QS_ABORTED; + scsiq->d3.done_stat = QD_ABORTED_BY_HOST; + AscWriteLramDWord(iop_base, + (ushort) (q_addr + (ushort) ASC_SCSIQ_D_SRBPTR), + 0L); + AscWriteLramByte(iop_base, + (ushort) (q_addr + (ushort) ASC_SCSIQ_B_STATUS), + scsiq->q_status); + (*asc_isr_callback) (asc_dvc, scsiq); + } + } + } + DvcLeaveCritical(last_int_level); + return (1); +} +#endif /* version >= v1.3.89 */ + +STATIC int +AscHostReqRiscHalt( + PortAddr iop_base +) +{ + 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); + AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, + ASC_STOP_HOST_REQ_RISC_HALT | ASC_STOP_REQ_RISC_STOP +); + do { + if (AscIsChipHalted(iop_base)) { + sta = 1; + break; + } + DvcSleepMilliSecond(100); + } while (count++ < 20); + AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, saved_stop_code); + return (sta); +} + +STATIC int +AscStopQueueExe( + PortAddr iop_base +) +{ + int count = 0; + + if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) == 0) { + AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, + ASC_STOP_REQ_RISC_STOP); + do { + if ( + AscReadLramByte(iop_base, ASCV_STOP_CODE_B) & + ASC_STOP_ACK_RISC_STOP) { + return (1); + } + DvcSleepMilliSecond(100); + } while (count++ < 20); + } + return (0); +} + +STATIC int +AscStartQueueExe( + PortAddr iop_base +) +{ + if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) != 0) { + AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, 0); + } + return (1); +} + +STATIC int +AscCleanUpBusyQueue( + PortAddr iop_base +) +{ + int count; + uchar stop_code; + + count = 0; + if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) != 0) { + AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, + ASC_STOP_CLEAN_UP_BUSY_Q); + do { + stop_code = AscReadLramByte(iop_base, ASCV_STOP_CODE_B); + if ((stop_code & ASC_STOP_CLEAN_UP_BUSY_Q) == 0) + break; + DvcSleepMilliSecond(100); + } while (count++ < 20); + } + return (1); +} + +#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) +STATIC int +AscCleanUpDiscQueue( + PortAddr iop_base +) +{ + int count; + uchar stop_code; + + count = 0; + if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) != 0) { + AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, + ASC_STOP_CLEAN_UP_DISC_Q); + do { + stop_code = AscReadLramByte(iop_base, ASCV_STOP_CODE_B); + if ((stop_code & ASC_STOP_CLEAN_UP_DISC_Q) == 0) + break; + DvcSleepMilliSecond(100); + } while (count++ < 20); + } + return (1); +} +#endif /* version >= v1.3.89 */ + +STATIC int +AscWaitTixISRDone( + ASC_DVC_VAR asc_ptr_type * asc_dvc, + uchar target_ix +) +{ + uchar cur_req; + uchar tid_no; + int i = 0; + + tid_no = ASC_TIX_TO_TID(target_ix); + while (i++ < 10) { + if ((cur_req = asc_dvc->cur_dvc_qng[tid_no]) == 0) { + break; + } + DvcSleepMilliSecond(100L); + if (asc_dvc->cur_dvc_qng[tid_no] == cur_req) { + break; + } + } + return (1); +} + +STATIC int +AscWaitISRDone( + REG ASC_DVC_VAR asc_ptr_type * asc_dvc +) +{ + int tid; + + for (tid = 0; tid <= ASC_MAX_TID; tid++) { + AscWaitTixISRDone(asc_dvc, ASC_TID_TO_TIX(tid)); + } + return (1); +} + +STATIC ulong +AscGetOnePhyAddr( + REG ASC_DVC_VAR asc_ptr_type * asc_dvc, + uchar * buf_addr, + ulong buf_size +) +{ + 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) { + return (0L); + } + if (sg_head.entry_cnt > 1) { + return (0L); + } + return (sg_head.sg_list[0].addr); +} + +STATIC void +DvcDelayMicroSecond(ADV_DVC_VAR *asc_dvc, ushort micro_sec) +{ + udelay(micro_sec); +} + +STATIC void +DvcDelayNanoSecond(ASC_DVC_VAR asc_ptr_type * asc_dvc, ulong nano_sec) +{ + udelay((nano_sec + 999)/1000); +} + +ASC_INITFUNC( +STATIC ulong +AscGetEisaProductID( + PortAddr iop_base +) +) +{ + 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); + product_id = ((ulong) product_id_high << 16) | (ulong) product_id_low; + return (product_id); +} + +ASC_INITFUNC( +STATIC PortAddr +AscSearchIOPortAddrEISA( + PortAddr iop_base +) +) +{ + ulong eisa_product_id; + + if (iop_base == 0) { + iop_base = ASC_EISA_MIN_IOP_ADDR; + } else { + if (iop_base == ASC_EISA_MAX_IOP_ADDR) + return (0); + if ((iop_base & 0x0050) == 0x0050) { + iop_base += ASC_EISA_BIG_IOP_GAP; + } else { + iop_base += ASC_EISA_SMALL_IOP_GAP; + } + } + while (iop_base <= ASC_EISA_MAX_IOP_ADDR) { + eisa_product_id = AscGetEisaProductID(iop_base); + if ((eisa_product_id == ASC_EISA_ID_740) || + (eisa_product_id == ASC_EISA_ID_750)) { + if (AscFindSignature(iop_base)) { + inpw(iop_base + 4); + return (iop_base); + } + } + if (iop_base == ASC_EISA_MAX_IOP_ADDR) + return (0); + if ((iop_base & 0x0050) == 0x0050) { + iop_base += ASC_EISA_BIG_IOP_GAP; + } else { + iop_base += ASC_EISA_SMALL_IOP_GAP; + } + } + return (0); +} + +STATIC int +AscStartChip( + PortAddr iop_base +) +{ + AscSetChipControl(iop_base, 0); + if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) { + return (0); + } + return (1); +} + +STATIC int +AscStopChip( + PortAddr iop_base +) +{ + 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); + AscSetChipIH(iop_base, INS_RFLAG_WTM); + if ((AscGetChipStatus(iop_base) & CSW_HALTED) == 0) { + return (0); + } + return (1); +} + +STATIC int +AscIsChipHalted( + PortAddr iop_base +) +{ + if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) { + if ((AscGetChipControl(iop_base) & CC_HALT) != 0) { + return (1); + } + } + return (0); +} + +STATIC void +AscSetChipIH( + PortAddr iop_base, + ushort ins_code +) +{ + AscSetBank(iop_base, 1); + AscWriteChipIH(iop_base, ins_code); + AscSetBank(iop_base, 0); + return; +} + +STATIC void +AscAckInterrupt( + PortAddr iop_base +) +{ + uchar host_flag; + uchar risc_flag; + ushort loop; + + loop = 0; + do { + risc_flag = AscReadLramByte(iop_base, ASCV_RISC_FLAG_B); + if (loop++ > 0x7FFF) { + break; + } + } while ((risc_flag & ASC_RISC_FLAG_GEN_INT) != 0); + host_flag = AscReadLramByte(iop_base, ASCV_HOST_FLAG_B) & (~ASC_HOST_FLAG_ACK_INT); + AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, + (uchar) (host_flag | ASC_HOST_FLAG_ACK_INT)); + AscSetChipStatus(iop_base, CIW_INT_ACK); + loop = 0; + while (AscGetChipStatus(iop_base) & CSW_INT_PENDING) { + AscSetChipStatus(iop_base, CIW_INT_ACK); + if (loop++ > 3) { + break; + } + } + AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag); + return; +} + +STATIC void +AscDisableInterrupt( + PortAddr iop_base +) +{ + ushort cfg; + + cfg = AscGetChipCfgLsw(iop_base); + AscSetChipCfgLsw(iop_base, cfg & (~ASC_CFG0_HOST_INT_ON)); + return; +} + +STATIC void +AscEnableInterrupt( + PortAddr iop_base +) +{ + ushort cfg; + + cfg = AscGetChipCfgLsw(iop_base); + AscSetChipCfgLsw(iop_base, cfg | ASC_CFG0_HOST_INT_ON); + return; +} + + + +STATIC void +AscSetBank( + PortAddr iop_base, + uchar bank +) +{ + uchar val; + + val = AscGetChipControl(iop_base) & + (~(CC_SINGLE_STEP | CC_TEST | CC_DIAG | CC_SCSI_RESET | CC_CHIP_RESET)); + if (bank == 1) { + val |= CC_BANK_ONE; + } else if (bank == 2) { + val |= CC_DIAG | CC_BANK_ONE; + } else { + val &= ~CC_BANK_ONE; + } + AscSetChipControl(iop_base, val); + return; +} + +STATIC int +AscResetChipAndScsiBus( + 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); + DvcDelayNanoSecond(asc_dvc, 60000); + AscSetChipIH(iop_base, INS_RFLAG_WTM); + AscSetChipIH(iop_base, INS_HALT); + AscSetChipControl(iop_base, CC_CHIP_RESET | CC_HALT); + AscSetChipControl(iop_base, CC_HALT); + DvcSleepMilliSecond(200); + AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT); + AscSetChipStatus(iop_base, 0); + return (AscIsChipHalted(iop_base)); +} + +ASC_INITFUNC( +STATIC ulong +AscGetMaxDmaCount( + ushort bus_type +) +) +{ + if (bus_type & ASC_IS_ISA) + return (ASC_MAX_ISA_DMA_COUNT); + else if (bus_type & (ASC_IS_EISA | ASC_IS_VL)) + return (ASC_MAX_VL_DMA_COUNT); + return (ASC_MAX_PCI_DMA_COUNT); +} + +ASC_INITFUNC( +STATIC ushort +AscGetIsaDmaChannel( + PortAddr iop_base +) +) +{ + ushort channel; + + channel = AscGetChipCfgLsw(iop_base) & 0x0003; + if (channel == 0x03) + return (0); + else if (channel == 0x00) + return (7); + return (channel + 4); +} + +ASC_INITFUNC( +STATIC ushort +AscSetIsaDmaChannel( + PortAddr iop_base, + ushort dma_channel +) +) +{ + ushort cfg_lsw; + uchar value; + + if ((dma_channel >= 5) && (dma_channel <= 7)) { + if (dma_channel == 7) + value = 0x00; + else + value = dma_channel - 4; + cfg_lsw = AscGetChipCfgLsw(iop_base) & 0xFFFC; + cfg_lsw |= value; + AscSetChipCfgLsw(iop_base, cfg_lsw); + return (AscGetIsaDmaChannel(iop_base)); + } + return (0); +} + +ASC_INITFUNC( +STATIC uchar +AscSetIsaDmaSpeed( + PortAddr iop_base, + uchar speed_value +) +) +{ + speed_value &= 0x07; + AscSetBank(iop_base, 1); + AscWriteChipDmaSpeed(iop_base, speed_value); + AscSetBank(iop_base, 0); + return (AscGetIsaDmaSpeed(iop_base)); +} + +ASC_INITFUNC( +STATIC uchar +AscGetIsaDmaSpeed( + PortAddr iop_base +) +) +{ + uchar speed_value; + + AscSetBank(iop_base, 1); + speed_value = AscReadChipDmaSpeed(iop_base); + speed_value &= 0x07; + AscSetBank(iop_base, 0); + return (speed_value); +} + +ASC_INITFUNC( +STATIC ushort +AscReadPCIConfigWord( + ASC_DVC_VAR asc_ptr_type *asc_dvc, + ushort pci_config_offset) +) +{ + uchar lsb, msb; + + lsb = DvcReadPCIConfigByte(asc_dvc, pci_config_offset); + msb = DvcReadPCIConfigByte(asc_dvc, pci_config_offset + 1); + return ((ushort) ((msb << 8) | lsb)); +} + +ASC_INITFUNC( +STATIC ushort +AscInitGetConfig( + ASC_DVC_VAR asc_ptr_type * asc_dvc +) +) +{ + ushort warn_code; + PortAddr iop_base; + ushort PCIDeviceID; + ushort PCIVendorID; + uchar PCIRevisionID; + uchar prevCmdRegBits; + + warn_code = 0; + iop_base = asc_dvc->iop_base; + asc_dvc->init_state = ASC_INIT_STATE_BEG_GET_CFG; + if (asc_dvc->err_code != 0) { + return (UW_ERR); + } + if (asc_dvc->bus_type == ASC_IS_PCI) { + PCIVendorID = AscReadPCIConfigWord(asc_dvc, + AscPCIConfigVendorIDRegister); + + PCIDeviceID = AscReadPCIConfigWord(asc_dvc, + AscPCIConfigDeviceIDRegister); + + PCIRevisionID = DvcReadPCIConfigByte(asc_dvc, + AscPCIConfigRevisionIDRegister); + + if (PCIVendorID != ASC_PCI_VENDORID) { + warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE; + } + prevCmdRegBits = DvcReadPCIConfigByte(asc_dvc, + AscPCIConfigCommandRegister); + + if ((prevCmdRegBits & AscPCICmdRegBits_IOMemBusMaster) != + AscPCICmdRegBits_IOMemBusMaster) { + DvcWritePCIConfigByte(asc_dvc, + AscPCIConfigCommandRegister, + (prevCmdRegBits | + AscPCICmdRegBits_IOMemBusMaster)); + + if ((DvcReadPCIConfigByte(asc_dvc, + AscPCIConfigCommandRegister) + & AscPCICmdRegBits_IOMemBusMaster) + != AscPCICmdRegBits_IOMemBusMaster) { + warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE; + } + } + if ((PCIDeviceID == ASC_PCI_DEVICEID_1200A) || + (PCIDeviceID == ASC_PCI_DEVICEID_1200B)) { + DvcWritePCIConfigByte(asc_dvc, + AscPCIConfigLatencyTimer, 0x00); + if (DvcReadPCIConfigByte(asc_dvc, AscPCIConfigLatencyTimer) + != 0x00) { + warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE; + } + } else if (PCIDeviceID == ASC_PCI_DEVICEID_ULTRA) { + if (DvcReadPCIConfigByte(asc_dvc, + AscPCIConfigLatencyTimer) < 0x20) { + DvcWritePCIConfigByte(asc_dvc, + AscPCIConfigLatencyTimer, 0x20); + + if (DvcReadPCIConfigByte(asc_dvc, + AscPCIConfigLatencyTimer) < 0x20) { + warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE; + } + } + } + } + + if (AscFindSignature(iop_base)) { + warn_code |= AscInitAscDvcVar(asc_dvc); + warn_code |= AscInitFromEEP(asc_dvc); + asc_dvc->init_state |= ASC_INIT_STATE_END_GET_CFG; + if (asc_dvc->scsi_reset_wait > ASC_MAX_SCSI_RESET_WAIT) { + asc_dvc->scsi_reset_wait = ASC_MAX_SCSI_RESET_WAIT; + } + } else { + asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE; + } + return(warn_code); +} + +ASC_INITFUNC( +STATIC ushort +AscInitSetConfig( + ASC_DVC_VAR asc_ptr_type * asc_dvc +) +) +{ + ushort warn_code = 0; + + asc_dvc->init_state |= ASC_INIT_STATE_BEG_SET_CFG; + if (asc_dvc->err_code != 0) + return (UW_ERR); + if (AscFindSignature(asc_dvc->iop_base)) { + warn_code |= AscInitFromAscDvcVar(asc_dvc); + asc_dvc->init_state |= ASC_INIT_STATE_END_SET_CFG; + } else { + asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE; + } + return (warn_code); +} + +ASC_INITFUNC( +STATIC ushort +AscInitFromAscDvcVar( + ASC_DVC_VAR asc_ptr_type * asc_dvc +) +) +{ + PortAddr iop_base; + 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; + cfg_msw = AscGetChipCfgMsw(iop_base); + if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) { + cfg_msw &= (~(ASC_CFG_MSW_CLR_MASK)); + warn_code |= ASC_WARN_CFG_MSW_RECOVER; + AscSetChipCfgMsw(iop_base, cfg_msw); + } + if ((asc_dvc->cfg->cmd_qng_enabled & asc_dvc->cfg->disc_enable) != + asc_dvc->cfg->cmd_qng_enabled) { + asc_dvc->cfg->disc_enable = asc_dvc->cfg->cmd_qng_enabled; + warn_code |= ASC_WARN_CMD_QNG_CONFLICT; + } + if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) { + warn_code |= ASC_WARN_AUTO_CONFIG; + } + if ((asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL)) != 0) { + if (AscSetChipIRQ(iop_base, asc_dvc->irq_no, asc_dvc->bus_type) + != asc_dvc->irq_no) { + asc_dvc->err_code |= ASC_IERR_SET_IRQ_NO; + } + } + if (asc_dvc->bus_type & ASC_IS_PCI) { + cfg_msw &= 0xFFC0; + AscSetChipCfgMsw(iop_base, cfg_msw); + if ((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) { + } else { + if ((pci_device_id == ASC_PCI_DEVICE_ID_REV_A) || + (pci_device_id == ASC_PCI_DEVICE_ID_REV_B)) { + asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_IF_NOT_DWB; + asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_ASYN_USE_SYN; + } + } + } else if (asc_dvc->bus_type == ASC_IS_ISAPNP) { + if (AscGetChipVersion(iop_base, asc_dvc->bus_type) + == ASC_CHIP_VER_ASYN_BUG) { + asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_ASYN_USE_SYN; + } + } + if (AscSetChipScsiID(iop_base, asc_dvc->cfg->chip_scsi_id) != + asc_dvc->cfg->chip_scsi_id) { + asc_dvc->err_code |= ASC_IERR_SET_SCSI_ID; + } if (asc_dvc->bus_type & ASC_IS_ISA) { AscSetIsaDmaChannel(iop_base, asc_dvc->cfg->isa_dma_channel); AscSetIsaDmaSpeed(iop_base, asc_dvc->cfg->isa_dma_speed); } - return (warn_code); + return (warn_code); +} + +ASC_INITFUNC( +STATIC ushort +AscInitAsc1000Driver( + ASC_DVC_VAR asc_ptr_type * asc_dvc +) +) +{ + ushort warn_code; + PortAddr iop_base; + 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(asc_dvc); + DvcSleepMilliSecond((ulong) ((ushort) asc_dvc->scsi_reset_wait * 1000)); + } + asc_dvc->init_state |= ASC_INIT_STATE_BEG_LOAD_MC; + if (asc_dvc->err_code != 0) + return (UW_ERR); + if (!AscFindSignature(asc_dvc->iop_base)) { + asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE; + return (warn_code); + } + AscDisableInterrupt(iop_base); + warn_code |= AscInitLram(asc_dvc); + if (asc_dvc->err_code != 0) + return (UW_ERR); + 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); + } + warn_code |= AscInitMicroCodeVar(asc_dvc); + asc_dvc->init_state |= ASC_INIT_STATE_END_LOAD_MC; + AscEnableInterrupt(iop_base); + return (warn_code); +} + +ASC_INITFUNC( +STATIC ushort +AscInitAscDvcVar( + ASC_DVC_VAR asc_ptr_type * asc_dvc +) +) +{ + int i; + PortAddr iop_base; + ushort warn_code; + uchar chip_version; + + iop_base = asc_dvc->iop_base; + warn_code = 0; + asc_dvc->err_code = 0; + if ((asc_dvc->bus_type & + (ASC_IS_ISA | ASC_IS_PCI | ASC_IS_EISA | ASC_IS_VL)) == 0) { + asc_dvc->err_code |= ASC_IERR_NO_BUS_TYPE; + } + AscSetChipControl(iop_base, CC_HALT); + AscSetChipStatus(iop_base, 0); + asc_dvc->bug_fix_cntl = 0; + asc_dvc->pci_fix_asyn_xfer = 0; + asc_dvc->pci_fix_asyn_xfer_always = 0; + asc_dvc->init_state = 0; + asc_dvc->sdtr_done = 0; + asc_dvc->cur_total_qng = 0; + asc_dvc->is_in_int = 0; + asc_dvc->in_critical_cnt = 0; + asc_dvc->last_q_shortage = 0; + asc_dvc->use_tagged_qng = 0; + asc_dvc->no_scam = 0; + asc_dvc->unit_not_ready = 0; + asc_dvc->queue_full_or_busy = 0; + asc_dvc->redo_scam = 0 ; + asc_dvc->res2 = 0 ; + asc_dvc->host_init_sdtr_index = 0 ; + asc_dvc->res7 = 0 ; + asc_dvc->res8 = 0 ; + asc_dvc->cfg->can_tagged_qng = 0 ; + asc_dvc->cfg->cmd_qng_enabled = 0; + asc_dvc->dvc_cntl = ASC_DEF_DVC_CNTL; + asc_dvc->init_sdtr = ASC_SCSI_WIDTH_BIT_SET; + asc_dvc->max_total_qng = ASC_DEF_MAX_TOTAL_QNG; + asc_dvc->scsi_reset_wait = 3; + asc_dvc->start_motor = ASC_SCSI_WIDTH_BIT_SET; + asc_dvc->max_dma_count = AscGetMaxDmaCount(asc_dvc->bus_type); + asc_dvc->cfg->disc_enable = ASC_SCSI_WIDTH_BIT_SET; + asc_dvc->cfg->chip_scsi_id = ASC_DEF_CHIP_SCSI_ID; + asc_dvc->cfg->lib_serial_no = ASC_LIB_SERIAL_NUMBER; + asc_dvc->cfg->lib_version = (ASC_LIB_VERSION_MAJOR << 8) | + ASC_LIB_VERSION_MINOR; + chip_version = AscGetChipVersion(iop_base, asc_dvc->bus_type); + asc_dvc->cfg->chip_version = chip_version; + asc_dvc->sdtr_period_tbl[0] = SYN_XFER_NS_0; + asc_dvc->sdtr_period_tbl[1] = SYN_XFER_NS_1; + asc_dvc->sdtr_period_tbl[2] = SYN_XFER_NS_2; + asc_dvc->sdtr_period_tbl[3] = SYN_XFER_NS_3; + asc_dvc->sdtr_period_tbl[4] = SYN_XFER_NS_4; + asc_dvc->sdtr_period_tbl[5] = SYN_XFER_NS_5; + asc_dvc->sdtr_period_tbl[6] = SYN_XFER_NS_6; + asc_dvc->sdtr_period_tbl[7] = SYN_XFER_NS_7; + asc_dvc->max_sdtr_index = 7; + if ((asc_dvc->bus_type & ASC_IS_PCI) && + (chip_version >= ASC_CHIP_VER_PCI_ULTRA_3150)) { + asc_dvc->bus_type = ASC_IS_PCI_ULTRA; + asc_dvc->sdtr_period_tbl[0] = SYN_ULTRA_XFER_NS_0; + asc_dvc->sdtr_period_tbl[1] = SYN_ULTRA_XFER_NS_1; + asc_dvc->sdtr_period_tbl[2] = SYN_ULTRA_XFER_NS_2; + asc_dvc->sdtr_period_tbl[3] = SYN_ULTRA_XFER_NS_3; + asc_dvc->sdtr_period_tbl[4] = SYN_ULTRA_XFER_NS_4; + asc_dvc->sdtr_period_tbl[5] = SYN_ULTRA_XFER_NS_5; + asc_dvc->sdtr_period_tbl[6] = SYN_ULTRA_XFER_NS_6; + asc_dvc->sdtr_period_tbl[7] = SYN_ULTRA_XFER_NS_7; + asc_dvc->sdtr_period_tbl[8] = SYN_ULTRA_XFER_NS_8; + asc_dvc->sdtr_period_tbl[9] = SYN_ULTRA_XFER_NS_9; + asc_dvc->sdtr_period_tbl[10] = SYN_ULTRA_XFER_NS_10; + asc_dvc->sdtr_period_tbl[11] = SYN_ULTRA_XFER_NS_11; + asc_dvc->sdtr_period_tbl[12] = SYN_ULTRA_XFER_NS_12; + asc_dvc->sdtr_period_tbl[13] = SYN_ULTRA_XFER_NS_13; + asc_dvc->sdtr_period_tbl[14] = SYN_ULTRA_XFER_NS_14; + asc_dvc->sdtr_period_tbl[15] = SYN_ULTRA_XFER_NS_15; + asc_dvc->max_sdtr_index = 15; + if (chip_version == ASC_CHIP_VER_PCI_ULTRA_3150) + { + AscSetExtraControl(iop_base, + (SEC_ACTIVE_NEGATE | SEC_SLEW_RATE)); + } else if (chip_version >= ASC_CHIP_VER_PCI_ULTRA_3050) { + AscSetExtraControl(iop_base, + (SEC_ACTIVE_NEGATE | SEC_ENABLE_FILTER)); + } + } + if (asc_dvc->bus_type == ASC_IS_PCI) { + AscSetExtraControl(iop_base, (SEC_ACTIVE_NEGATE | SEC_SLEW_RATE)); + } + + asc_dvc->cfg->isa_dma_speed = ASC_DEF_ISA_DMA_SPEED; + if (AscGetChipBusType(iop_base) == ASC_IS_ISAPNP) { + AscSetChipIFC(iop_base, IFC_INIT_DEFAULT); + asc_dvc->bus_type = ASC_IS_ISAPNP; + } + if ((asc_dvc->bus_type & ASC_IS_ISA) != 0) { + asc_dvc->cfg->isa_dma_channel = (uchar) AscGetIsaDmaChannel(iop_base); + } + for (i = 0; i <= ASC_MAX_TID; i++) { + asc_dvc->cur_dvc_qng[i] = 0; + asc_dvc->max_dvc_qng[i] = ASC_MAX_SCSI1_QNG; + asc_dvc->scsiq_busy_head[i] = (ASC_SCSI_Q *) 0L; + asc_dvc->scsiq_busy_tail[i] = (ASC_SCSI_Q *) 0L; + asc_dvc->cfg->max_tag_qng[i] = ASC_MAX_INRAM_TAG_QNG; + } + return (warn_code); +} + +ASC_INITFUNC( +STATIC ushort +AscInitFromEEP( + ASC_DVC_VAR asc_ptr_type * asc_dvc +) +) +{ + ASCEEP_CONFIG eep_config_buf; + 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); + AscStopQueueExe(iop_base); + if ((AscStopChip(iop_base) == FALSE) || + (AscGetChipScsiCtrl(iop_base) != 0)) { + asc_dvc->init_state |= ASC_INIT_RESET_SCSI_DONE; + AscResetChipAndScsiBus(asc_dvc); + DvcSleepMilliSecond((ulong) ((ushort) asc_dvc->scsi_reset_wait * 1000)); + } + if (AscIsChipHalted(iop_base) == FALSE) { + asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP; + return (warn_code); + } + AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR); + if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) { + asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR; + return (warn_code); + } + eep_config = (ASCEEP_CONFIG *) & eep_config_buf; + cfg_msw = AscGetChipCfgMsw(iop_base); + cfg_lsw = AscGetChipCfgLsw(iop_base); + if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) { + cfg_msw &= (~(ASC_CFG_MSW_CLR_MASK)); + warn_code |= ASC_WARN_CFG_MSW_RECOVER; + AscSetChipCfgMsw(iop_base, cfg_msw); + } + chksum = AscGetEEPConfig(iop_base, eep_config, asc_dvc->bus_type); + 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) { + if (eep_config->cfg_lsw != cfg_lsw) { + warn_code |= ASC_WARN_EEPROM_RECOVER; + eep_config->cfg_lsw = AscGetChipCfgLsw(iop_base); + } + if (eep_config->cfg_msw != cfg_msw) { + warn_code |= ASC_WARN_EEPROM_RECOVER; + eep_config->cfg_msw = AscGetChipCfgMsw(iop_base); + } + } + } + eep_config->cfg_msw &= ~ASC_CFG_MSW_CLR_MASK; + eep_config->cfg_lsw |= ASC_CFG0_HOST_INT_ON; + if (chksum != eep_config->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; + asc_dvc->cfg->cmd_qng_enabled = eep_config->use_cmd_qng; + asc_dvc->cfg->isa_dma_speed = eep_config->isa_dma_speed; + 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; + eep_config->max_tag_qng = ASC_MAX_PCI_ULTRA_INRAM_TAG_QNG; + } else { + eep_config->cfg_msw |= 0x0800; + cfg_msw |= 0x0800; + AscSetChipCfgMsw(iop_base, cfg_msw); + eep_config->max_total_qng = ASC_MAX_PCI_INRAM_TOTAL_QNG; + eep_config->max_tag_qng = ASC_MAX_INRAM_TAG_QNG; + } + } else { + } + if (eep_config->max_total_qng < ASC_MIN_TOTAL_QNG) { + eep_config->max_total_qng = ASC_MIN_TOTAL_QNG; + } + if (eep_config->max_total_qng > ASC_MAX_TOTAL_QNG) { + eep_config->max_total_qng = ASC_MAX_TOTAL_QNG; + } + if (eep_config->max_tag_qng > eep_config->max_total_qng) { + eep_config->max_tag_qng = eep_config->max_total_qng; + } + if (eep_config->max_tag_qng < ASC_MIN_TAG_Q_PER_DVC) { + eep_config->max_tag_qng = ASC_MIN_TAG_Q_PER_DVC; + } + asc_dvc->max_total_qng = eep_config->max_total_qng; + if ((eep_config->use_cmd_qng & eep_config->disc_enable) != + eep_config->use_cmd_qng) { + eep_config->disc_enable = eep_config->use_cmd_qng; + warn_code |= ASC_WARN_CMD_QNG_CONFLICT; + } + if (asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL | ASC_IS_EISA)) { + asc_dvc->irq_no = AscGetChipIRQ(iop_base, asc_dvc->bus_type); + } + eep_config->chip_scsi_id &= ASC_MAX_TID; + asc_dvc->cfg->chip_scsi_id = eep_config->chip_scsi_id; + if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) && + !(asc_dvc->dvc_cntl & ASC_CNTL_SDTR_ENABLE_ULTRA)) { + asc_dvc->host_init_sdtr_index = ASC_SDTR_ULTRA_PCI_10MB_INDEX; + } + + for (i = 0; i <= ASC_MAX_TID; i++) { + asc_dvc->dos_int13_table[i] = eep_config->dos_int13_table[i]; + asc_dvc->cfg->max_tag_qng[i] = eep_config->max_tag_qng; + asc_dvc->cfg->sdtr_period_offset[i] = + (uchar) (ASC_DEF_SDTR_OFFSET | + (asc_dvc->host_init_sdtr_index << 4)); + } + eep_config->cfg_msw = AscGetChipCfgMsw(iop_base); + if (write_eep) { + (void) AscSetEEPConfig(iop_base, eep_config, asc_dvc->bus_type); + } + return (warn_code); +} + +ASC_INITFUNC( +STATIC ushort +AscInitMicroCodeVar( + ASC_DVC_VAR asc_ptr_type * asc_dvc +) +) +{ + int i; + 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++) { + AscPutMCodeInitSDTRAtID(iop_base, i, + asc_dvc->cfg->sdtr_period_offset[i] +); + } + AscInitQLinkVar(asc_dvc); + AscWriteLramByte(iop_base, ASCV_DISC_ENABLE_B, + asc_dvc->cfg->disc_enable); + AscWriteLramByte(iop_base, ASCV_HOSTSCSI_ID_B, + ASC_TID_TO_TARGET_ID(asc_dvc->cfg->chip_scsi_id)); + if ((phy_addr = AscGetOnePhyAddr(asc_dvc, + (uchar *) asc_dvc->cfg->overrun_buf, + ASC_OVERRUN_BSIZE)) == 0L) { + asc_dvc->err_code |= ASC_IERR_GET_PHY_ADDR; + } else { + phy_addr = (phy_addr & 0xFFFFFFF8UL) + 8; + AscWriteLramDWord(iop_base, ASCV_OVERRUN_PADDR_D, phy_addr); + AscWriteLramDWord(iop_base, ASCV_OVERRUN_BSIZE_D, + ASC_OVERRUN_BSIZE - 8); + } + asc_dvc->cfg->mcode_date = AscReadLramWord(iop_base, + (ushort) ASCV_MC_DATE_W); + asc_dvc->cfg->mcode_version = AscReadLramWord(iop_base, + (ushort) ASCV_MC_VER_W); + AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR); + if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) { + asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR; + return (warn_code); + } + if (AscStartChip(iop_base) != 1) { + asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP; + return (warn_code); + } + return (warn_code); +} + +STATIC void +AscInitPollIsrCallBack( + ASC_DVC_VAR asc_ptr_type * asc_dvc, + ASC_QDONE_INFO * scsi_done_q +) +{ + ASC_SCSI_REQ_Q *scsiq_req; + 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; + scsiq_req->r3.done_stat = scsi_done_q->d3.done_stat; + scsiq_req->r3.host_stat = scsi_done_q->d3.host_stat; + scsiq_req->r3.scsi_stat = scsi_done_q->d3.scsi_stat; + scsiq_req->r3.scsi_msg = scsi_done_q->d3.scsi_msg; + ASC_DBG4(1, "AscInitPollIsrCallBack: done_stat %x, host_stat %x, scsi_stat %x, scsi_msg %x\n", + scsi_done_q->d3.done_stat, scsi_done_q->d3.host_stat, + scsi_done_q->d3.scsi_stat, scsi_done_q->d3.scsi_msg); + if ((scsi_done_q->d3.scsi_stat == SS_CHK_CONDITION) && + (scsi_done_q->d3.host_stat == 0)) { + cp_sen_len = (uchar) ASC_MIN_SENSE_LEN; + if (scsiq_req->r1.sense_len < ASC_MIN_SENSE_LEN) { + cp_sen_len = (uchar) scsiq_req->r1.sense_len; + } + for (i = 0; i < cp_sen_len; i++) { + scsiq_req->sense[i] = scsiq_req->sense_ptr[i]; + } + } + } else { + if (asc_dvc->isr_callback != 0) { + asc_isr_callback = (ASC_ISR_CALLBACK) asc_dvc->isr_callback; + (*asc_isr_callback) (asc_dvc, scsi_done_q); + } + } + ASC_DBG(1, "AscInitPollIsrCallBack: end\n"); + return; +} + +ASC_INITFUNC( +STATIC int +AscTestExternalLram( + ASC_DVC_VAR asc_ptr_type * asc_dvc +) +) +{ + PortAddr iop_base; + ushort q_addr; + ushort saved_word; + int sta; + + iop_base = asc_dvc->iop_base; + sta = 0; + q_addr = ASC_QNO_TO_QADDR(241); + saved_word = AscReadLramWord(iop_base, q_addr); + AscSetChipLramAddr(iop_base, q_addr); + AscSetChipLramData(iop_base, 0x55AA); + DvcSleepMilliSecond(10); + AscSetChipLramAddr(iop_base, q_addr); + if (AscGetChipLramData(iop_base) == 0x55AA) { + sta = 1; + AscWriteLramWord(iop_base, q_addr, saved_word); + } + return (sta); +} + +ASC_INITFUNC( +STATIC int +AscWriteEEPCmdReg( + PortAddr iop_base, + uchar cmd_reg +) +) +{ + uchar read_back; + int retry; + + retry = 0; + while (TRUE) { + AscSetChipEEPCmd(iop_base, cmd_reg); + DvcSleepMilliSecond(1); + read_back = AscGetChipEEPCmd(iop_base); + if (read_back == cmd_reg) { + return (1); + } + if (retry++ > ASC_EEP_MAX_RETRY) { + return (0); + } + } +} + +ASC_INITFUNC( +STATIC int +AscWriteEEPDataReg( + PortAddr iop_base, + ushort data_reg +) +) +{ + ushort read_back; + int retry; + + retry = 0; + while (TRUE) { + AscSetChipEEPData(iop_base, data_reg); + DvcSleepMilliSecond(1); + read_back = AscGetChipEEPData(iop_base); + if (read_back == data_reg) { + return (1); + } + if (retry++ > ASC_EEP_MAX_RETRY) { + return (0); + } + } +} + +ASC_INITFUNC( +STATIC void +AscWaitEEPRead( + void +) +) +{ + DvcSleepMilliSecond(1); + return; +} + +ASC_INITFUNC( +STATIC void +AscWaitEEPWrite( + void +) +) +{ + DvcSleepMilliSecond(20); + return; +} + +ASC_INITFUNC( +STATIC ushort +AscReadEEPWord( + PortAddr iop_base, + uchar addr +) +) +{ + ushort read_wval; + uchar cmd_reg; + + AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE); + AscWaitEEPRead(); + cmd_reg = addr | ASC_EEP_CMD_READ; + AscWriteEEPCmdReg(iop_base, cmd_reg); + AscWaitEEPRead(); + read_wval = AscGetChipEEPData(iop_base); + AscWaitEEPRead(); + return (read_wval); +} + +ASC_INITFUNC( +STATIC ushort +AscWriteEEPWord( + PortAddr iop_base, + uchar addr, + ushort word_val +) +) +{ + ushort read_wval; + + read_wval = AscReadEEPWord(iop_base, addr); + if (read_wval != word_val) { + AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_ABLE); + AscWaitEEPRead(); + AscWriteEEPDataReg(iop_base, word_val); + AscWaitEEPRead(); + AscWriteEEPCmdReg(iop_base, + (uchar) ((uchar) ASC_EEP_CMD_WRITE | addr)); + AscWaitEEPWrite(); + AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE); + AscWaitEEPRead(); + return (AscReadEEPWord(iop_base, addr)); + } + return (read_wval); +} + +ASC_INITFUNC( +STATIC ushort +AscGetEEPConfig( + PortAddr iop_base, + ASCEEP_CONFIG * cfg_buf, ushort bus_type +) +) +{ + ushort wval; + ushort sum; + ushort *wbuf; + int cfg_beg; + int cfg_end; + int s_addr; + int isa_pnp_wsize; + + wbuf = (ushort *) cfg_buf; + sum = 0; + isa_pnp_wsize = 0; + for (s_addr = 0; s_addr < (2 + isa_pnp_wsize); s_addr++, wbuf++) { + wval = AscReadEEPWord(iop_base, (uchar) s_addr); + sum += wval; + *wbuf = wval; + } + if (bus_type & ASC_IS_VL) { + cfg_beg = ASC_EEP_DVC_CFG_BEG_VL; + cfg_end = ASC_EEP_MAX_DVC_ADDR_VL; + } else { + cfg_beg = ASC_EEP_DVC_CFG_BEG; + cfg_end = ASC_EEP_MAX_DVC_ADDR; + } + for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); + s_addr++, wbuf++) { + wval = AscReadEEPWord(iop_base, (uchar) s_addr); + sum += wval; + *wbuf = wval; + } + *wbuf = AscReadEEPWord(iop_base, (uchar) s_addr); + return (sum); } ASC_INITFUNC( -STATIC ushort -AscInitAsc1000Driver( - ASC_DVC_VAR asc_ptr_type * asc_dvc +STATIC int +AscSetEEPConfigOnce( + PortAddr iop_base, + ASCEEP_CONFIG * cfg_buf, ushort bus_type ) ) { - ushort warn_code; - PortAddr iop_base; - extern ushort _mcode_size; - extern ulong _mcode_chksum; - extern uchar _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); - DvcSleepMilliSecond((ulong) ((ushort) asc_dvc->scsi_reset_wait * 1000)); + int n_error; + ushort *wbuf; + ushort sum; + int s_addr; + int cfg_beg; + int cfg_end; + + wbuf = (ushort *) cfg_buf; + n_error = 0; + sum = 0; + for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) { + sum += *wbuf; + if (*wbuf != AscWriteEEPWord(iop_base, (uchar) s_addr, *wbuf)) { + n_error++; + } } - asc_dvc->init_state |= ASC_INIT_STATE_BEG_LOAD_MC; - if (asc_dvc->err_code != 0) - return (UW_ERR); - if (!AscFindSignature(asc_dvc->iop_base)) { - asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE; - return (warn_code); + if (bus_type & ASC_IS_VL) { + cfg_beg = ASC_EEP_DVC_CFG_BEG_VL; + cfg_end = ASC_EEP_MAX_DVC_ADDR_VL; + } else { + cfg_beg = ASC_EEP_DVC_CFG_BEG; + cfg_end = ASC_EEP_MAX_DVC_ADDR; } - AscDisableInterrupt(iop_base); - 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) { - asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM; - return (warn_code); + for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); + s_addr++, wbuf++) { + sum += *wbuf; + if (*wbuf != AscWriteEEPWord(iop_base, (uchar) s_addr, *wbuf)) { + n_error++; + } } - warn_code |= AscInitMicroCodeVar(asc_dvc); - asc_dvc->init_state |= ASC_INIT_STATE_END_LOAD_MC; - AscEnableInterrupt(iop_base); - return (warn_code); + *wbuf = sum; + if (sum != AscWriteEEPWord(iop_base, (uchar) s_addr, sum)) { + n_error++; + } + wbuf = (ushort *) cfg_buf; + for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) { + if (*wbuf != AscReadEEPWord(iop_base, (uchar) s_addr)) { + n_error++; + } + } + for (s_addr = cfg_beg; s_addr <= cfg_end; + s_addr++, wbuf++) { + if (*wbuf != AscReadEEPWord(iop_base, (uchar) s_addr)) { + n_error++; + } + } + return (n_error); } ASC_INITFUNC( -STATIC ushort -AscInitAscDvcVar( - ASC_DVC_VAR asc_ptr_type * asc_dvc +STATIC int +AscSetEEPConfig( + PortAddr iop_base, + ASCEEP_CONFIG * cfg_buf, ushort bus_type ) ) { - int i; + int retry; + int n_error; + + retry = 0; + while (TRUE) { + if ((n_error = AscSetEEPConfigOnce(iop_base, cfg_buf, + bus_type)) == 0) { + break; + } + if (++retry > ASC_EEP_MAX_RETRY) { + break; + } + } + return (n_error); +} + +STATIC int +AscInitPollBegin( + REG ASC_DVC_VAR asc_ptr_type * asc_dvc +) +{ PortAddr iop_base; - ushort warn_code; - uchar chip_version; + iop_base = asc_dvc->iop_base; - warn_code = 0; - asc_dvc->err_code = 0; - if ((asc_dvc->bus_type & - (ASC_IS_ISA | ASC_IS_PCI | ASC_IS_EISA | ASC_IS_VL)) == 0) { - asc_dvc->err_code |= ASC_IERR_NO_BUS_TYPE; - } - AscSetChipControl(iop_base, CC_HALT); - AscSetChipStatus(iop_base, 0); - asc_dvc->bug_fix_cntl = 0; - asc_dvc->pci_fix_asyn_xfer = 0; - asc_dvc->pci_fix_asyn_xfer_always = 0; - asc_dvc->init_state = 0; - asc_dvc->sdtr_done = 0; - asc_dvc->cur_total_qng = 0; - asc_dvc->is_in_int = 0; - asc_dvc->in_critical_cnt = 0; - asc_dvc->last_q_shortage = 0; + AscDisableInterrupt(iop_base); + asc_dvc->init_state |= ASC_INIT_STATE_BEG_INQUIRY; + AscWriteLramByte(iop_base, ASCV_DISC_ENABLE_B, 0x00); asc_dvc->use_tagged_qng = 0; - asc_dvc->no_scam = 0; - asc_dvc->unit_not_ready = 0; - asc_dvc->queue_full_or_busy = 0; - asc_dvc->redo_scam = 0 ; - asc_dvc->res2 = 0 ; - asc_dvc->host_init_sdtr_index = 0 ; - asc_dvc->res7 = 0 ; - asc_dvc->res8 = 0 ; - asc_dvc->cfg->can_tagged_qng = 0 ; - asc_dvc->cfg->cmd_qng_enabled = 0; - asc_dvc->dvc_cntl = ASC_DEF_DVC_CNTL; - asc_dvc->init_sdtr = ASC_SCSI_WIDTH_BIT_SET; - asc_dvc->max_total_qng = ASC_DEF_MAX_TOTAL_QNG; - asc_dvc->scsi_reset_wait = 3; - asc_dvc->start_motor = ASC_SCSI_WIDTH_BIT_SET; - asc_dvc->max_dma_count = AscGetMaxDmaCount(asc_dvc->bus_type); - asc_dvc->cfg->disc_enable = ASC_SCSI_WIDTH_BIT_SET; - asc_dvc->cfg->chip_scsi_id = ASC_DEF_CHIP_SCSI_ID; - asc_dvc->cfg->lib_serial_no = ASC_LIB_SERIAL_NUMBER; - asc_dvc->cfg->lib_version = (ASC_LIB_VERSION_MAJOR << 8) | - ASC_LIB_VERSION_MINOR; - chip_version = AscGetChipVersion(iop_base, asc_dvc->bus_type); - asc_dvc->cfg->chip_version = chip_version; - asc_dvc->sdtr_period_tbl[0] = SYN_XFER_NS_0; - asc_dvc->sdtr_period_tbl[1] = SYN_XFER_NS_1; - asc_dvc->sdtr_period_tbl[2] = SYN_XFER_NS_2; - asc_dvc->sdtr_period_tbl[3] = SYN_XFER_NS_3; - asc_dvc->sdtr_period_tbl[4] = SYN_XFER_NS_4; - asc_dvc->sdtr_period_tbl[5] = SYN_XFER_NS_5; - asc_dvc->sdtr_period_tbl[6] = SYN_XFER_NS_6; - asc_dvc->sdtr_period_tbl[7] = SYN_XFER_NS_7; - asc_dvc->max_sdtr_index = 7; - if ((asc_dvc->bus_type & ASC_IS_PCI) && - (chip_version >= ASC_CHIP_VER_PCI_ULTRA_3150)) { - asc_dvc->bus_type = ASC_IS_PCI_ULTRA; - asc_dvc->sdtr_period_tbl[0] = SYN_ULTRA_XFER_NS_0; - asc_dvc->sdtr_period_tbl[1] = SYN_ULTRA_XFER_NS_1; - asc_dvc->sdtr_period_tbl[2] = SYN_ULTRA_XFER_NS_2; - asc_dvc->sdtr_period_tbl[3] = SYN_ULTRA_XFER_NS_3; - asc_dvc->sdtr_period_tbl[4] = SYN_ULTRA_XFER_NS_4; - asc_dvc->sdtr_period_tbl[5] = SYN_ULTRA_XFER_NS_5; - asc_dvc->sdtr_period_tbl[6] = SYN_ULTRA_XFER_NS_6; - asc_dvc->sdtr_period_tbl[7] = SYN_ULTRA_XFER_NS_7; - asc_dvc->sdtr_period_tbl[8] = SYN_ULTRA_XFER_NS_8; - asc_dvc->sdtr_period_tbl[9] = SYN_ULTRA_XFER_NS_9; - asc_dvc->sdtr_period_tbl[10] = SYN_ULTRA_XFER_NS_10; - asc_dvc->sdtr_period_tbl[11] = SYN_ULTRA_XFER_NS_11; - asc_dvc->sdtr_period_tbl[12] = SYN_ULTRA_XFER_NS_12; - asc_dvc->sdtr_period_tbl[13] = SYN_ULTRA_XFER_NS_13; - asc_dvc->sdtr_period_tbl[14] = SYN_ULTRA_XFER_NS_14; - asc_dvc->sdtr_period_tbl[15] = SYN_ULTRA_XFER_NS_15; - asc_dvc->max_sdtr_index = 15; - if (chip_version == ASC_CHIP_VER_PCI_ULTRA_3150) - { - AscSetExtraControl(iop_base, - (SEC_ACTIVE_NEGATE | SEC_SLEW_RATE)); - } else if (chip_version >= ASC_CHIP_VER_PCI_ULTRA_3050) { - AscSetExtraControl(iop_base, - (SEC_ACTIVE_NEGATE | SEC_ENABLE_FILTER)); - } - } - if (asc_dvc->bus_type == ASC_IS_PCI) { - AscSetExtraControl(iop_base, (SEC_ACTIVE_NEGATE | SEC_SLEW_RATE)); - } + asc_dvc->cfg->can_tagged_qng = 0; + asc_dvc->saved_ptr2func = (ulong) asc_dvc->isr_callback; + asc_dvc->isr_callback = ASC_GET_PTR2FUNC(AscInitPollIsrCallBack); + return (0); +} - asc_dvc->cfg->isa_dma_speed = ASC_DEF_ISA_DMA_SPEED; - if (AscGetChipBusType(iop_base) == ASC_IS_ISAPNP) { - AscSetChipIFC(iop_base, IFC_INIT_DEFAULT); - asc_dvc->bus_type = ASC_IS_ISAPNP; - } - if ((asc_dvc->bus_type & ASC_IS_ISA) != 0) { - asc_dvc->cfg->isa_dma_channel = (uchar) AscGetIsaDmaChannel(iop_base); - } +STATIC int +AscInitPollEnd( + REG ASC_DVC_VAR asc_ptr_type * asc_dvc +) +{ + 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, + asc_dvc->cfg->disc_enable); + AscWriteLramByte(iop_base, ASCV_USE_TAGGED_QNG_B, + asc_dvc->use_tagged_qng); + AscWriteLramByte(iop_base, ASCV_CAN_TAGGED_QNG_B, + asc_dvc->cfg->can_tagged_qng); for (i = 0; i <= ASC_MAX_TID; i++) { - asc_dvc->cur_dvc_qng[i] = 0; - asc_dvc->max_dvc_qng[i] = ASC_MAX_SCSI1_QNG; - asc_dvc->scsiq_busy_head[i] = (ASC_SCSI_Q *) 0L; - asc_dvc->scsiq_busy_tail[i] = (ASC_SCSI_Q *) 0L; - asc_dvc->cfg->max_tag_qng[i] = ASC_MAX_INRAM_TAG_QNG; + AscWriteLramByte(iop_base, + (ushort) ((ushort) ASCV_MAX_DVC_QNG_BEG + (ushort) i), + asc_dvc->max_dvc_qng[i]); } - return (warn_code); + AscAckInterrupt(iop_base); + AscEnableInterrupt(iop_base); + asc_dvc->init_state |= ASC_INIT_STATE_END_INQUIRY; + return (0); } -#if CC_INCLUDE_EEP_CONFIG -ASC_INITFUNC( -STATIC ushort -AscInitFromEEP( - ASC_DVC_VAR asc_ptr_type * asc_dvc -) +STATIC int +AscInitPollTarget( + REG ASC_DVC_VAR asc_ptr_type * asc_dvc, + REG ASC_SCSI_REQ_Q * scsiq, + REG ASC_SCSI_INQUIRY * inq, + REG ASC_CAP_INFO * cap_info ) { - ASCEEP_CONFIG eep_config_buf; - ASCEEP_CONFIG *eep_config; - PortAddr iop_base; - ushort chksum; - ushort warn_code; - ushort cfg_msw, cfg_lsw; - int i; - iop_base = asc_dvc->iop_base; - warn_code = 0; - AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0x00FE); - AscStopQueueExe(iop_base); - if ((AscStopChip(iop_base) == FALSE) || - (AscGetChipScsiCtrl(iop_base) != 0)) { - asc_dvc->init_state |= ASC_INIT_RESET_SCSI_DONE; - AscResetChipAndScsiBus(iop_base); - DvcSleepMilliSecond((ulong) ((ushort) asc_dvc->scsi_reset_wait * 1000)); - } - if (AscIsChipHalted(iop_base) == FALSE) { - asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP; - return (warn_code); - } - AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR); - if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) { - asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR; - return (warn_code); - } - eep_config = (ASCEEP_CONFIG *) & eep_config_buf; - cfg_msw = AscGetChipCfgMsw(iop_base); - cfg_lsw = AscGetChipCfgLsw(iop_base); - if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) { - cfg_msw &= (~(ASC_CFG_MSW_CLR_MASK)); - warn_code |= ASC_WARN_CFG_MSW_RECOVER; - AscSetChipCfgMsw(iop_base, cfg_msw); + uchar tid_no, lun; + uchar dvc_type; + ASC_SCSI_BIT_ID_TYPE tid_bits; + int dvc_found; + int support_read_cap; + int tmp_disable_init_sdtr; + int sta; + + dvc_found = 0; + tmp_disable_init_sdtr = FALSE; + tid_bits = scsiq->r1.target_id; + lun = scsiq->r1.target_lun; + tid_no = ASC_TIX_TO_TID(scsiq->r2.target_ix); + if (((asc_dvc->init_sdtr & tid_bits) != 0) && + ((asc_dvc->sdtr_done & tid_bits) == 0)) { + asc_dvc->init_sdtr &= ~tid_bits; + tmp_disable_init_sdtr = TRUE; } - chksum = AscGetEEPConfig(iop_base, eep_config, asc_dvc->bus_type); - eep_config->cfg_msw &= (~(ASC_CFG_MSW_CLR_MASK)); - if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) { - warn_code |= ASC_WARN_AUTO_CONFIG; - if (asc_dvc->cfg->chip_version == 3) { - if (eep_config->cfg_lsw != cfg_lsw) { - warn_code |= ASC_WARN_EEPROM_RECOVER; - eep_config->cfg_lsw = AscGetChipCfgLsw(iop_base); + ASC_DBG(1, "AscInitPollTarget: before PollScsiInquiry\n"); + if (PollScsiInquiry(asc_dvc, scsiq, (uchar *) inq, + sizeof (ASC_SCSI_INQUIRY)) == 1) { + dvc_found = 1; + 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) + && (dvc_type != SCSI_TYPE_OPTMEM)) { + asc_dvc->start_motor &= ~tid_bits; + support_read_cap = FALSE; } - if (eep_config->cfg_msw != cfg_msw) { - warn_code |= ASC_WARN_EEPROM_RECOVER; - eep_config->cfg_msw = AscGetChipCfgMsw(iop_base); + if (lun == 0) { + if ((inq->byte3.rsp_data_fmt >= 2) || + (inq->byte2.ansi_apr_ver >= 2)) { + if (inq->byte7.CmdQue) { + asc_dvc->cfg->can_tagged_qng |= tid_bits; + if (asc_dvc->cfg->cmd_qng_enabled & tid_bits) { + asc_dvc->use_tagged_qng |= tid_bits; + asc_dvc->max_dvc_qng[tid_no] = asc_dvc->cfg->max_tag_qng[tid_no]; + } + } + if (!inq->byte7.Sync) { + asc_dvc->init_sdtr &= ~tid_bits; + asc_dvc->sdtr_done &= ~tid_bits; + } else if (tmp_disable_init_sdtr) { + asc_dvc->init_sdtr |= tid_bits; + } + } else { + asc_dvc->init_sdtr &= ~tid_bits; + asc_dvc->sdtr_done &= ~tid_bits; + asc_dvc->use_tagged_qng &= ~tid_bits; + } + } + if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_ASYN_USE_SYN) { + if (!(asc_dvc->init_sdtr & tid_bits)) { + if ((dvc_type == SCSI_TYPE_CDROM) && + (AscCompareString((uchar *) inq->vendor_id, + (uchar *) "HP ", 3) == 0)) { + asc_dvc->pci_fix_asyn_xfer_always |= tid_bits; + } + asc_dvc->pci_fix_asyn_xfer |= tid_bits; + if ((dvc_type == SCSI_TYPE_PROC) || (dvc_type == SCSI_TYPE_SCANNER)) { + asc_dvc->pci_fix_asyn_xfer &= ~tid_bits; + } + if ((dvc_type == SCSI_TYPE_SASD) && + (AscCompareString((uchar *) inq->vendor_id, + (uchar *) "TANDBERG", 8) == 0) && + (AscCompareString((uchar *) inq->product_id, + (uchar *) " TDC 36", 7) == 0)) { + asc_dvc->pci_fix_asyn_xfer &= ~tid_bits; + } + if ((dvc_type == SCSI_TYPE_SASD) && + (AscCompareString((uchar *) inq->vendor_id, + (uchar *) "WANGTEK ", 8) == 0)) { + asc_dvc->pci_fix_asyn_xfer &= ~tid_bits; + } + + if ((dvc_type == SCSI_TYPE_CDROM) && + (AscCompareString((uchar *)inq->vendor_id, + (uchar *)"NEC ", 8) == 0) && + (AscCompareString((uchar *)inq->product_id, + (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, + ASYN_SDTR_DATA_FIX_PCI_REV_AB); + } + } + } + sta = 1; + ASC_DBG(1, "AscInitPollTarget: before InitTestUnitReady\n"); + sta = InitTestUnitReady(asc_dvc, scsiq); + if (sta == 1) { + if ((cap_info != 0L) && support_read_cap) { + ASC_DBG(1, + "AscInitPollTarget: before PollScsiReadCapacity\n"); + if (PollScsiReadCapacity(asc_dvc, scsiq, + cap_info) != 1) { + cap_info->lba = 0L; + cap_info->blk_size = 0x0000; + } else { + } + } } - } - } - eep_config->cfg_lsw |= ASC_CFG0_HOST_INT_ON; - if (chksum != eep_config->chksum) { - warn_code |= ASC_WARN_EEPROM_CHKSUM; - } - asc_dvc->init_sdtr = eep_config->init_sdtr; - asc_dvc->cfg->disc_enable = eep_config->disc_enable; - asc_dvc->cfg->cmd_qng_enabled = eep_config->use_cmd_qng; - asc_dvc->cfg->isa_dma_speed = eep_config->isa_dma_speed; - asc_dvc->start_motor = eep_config->start_motor; - asc_dvc->dvc_cntl = eep_config->cntl; - asc_dvc->no_scam = eep_config->no_scam; - 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; - eep_config->max_tag_qng = ASC_MAX_PCI_ULTRA_INRAM_TAG_QNG; } else { - eep_config->cfg_msw |= 0x0800; - cfg_msw |= 0x0800; - AscSetChipCfgMsw(iop_base, cfg_msw); - eep_config->max_total_qng = ASC_MAX_PCI_INRAM_TOTAL_QNG; - eep_config->max_tag_qng = ASC_MAX_INRAM_TAG_QNG; + asc_dvc->start_motor &= ~tid_bits; } - } else { - } - if (eep_config->max_total_qng < ASC_MIN_TOTAL_QNG) { - eep_config->max_total_qng = ASC_MIN_TOTAL_QNG; - } - if (eep_config->max_total_qng > ASC_MAX_TOTAL_QNG) { - eep_config->max_total_qng = ASC_MAX_TOTAL_QNG; - } - if (eep_config->max_tag_qng > eep_config->max_total_qng) { - eep_config->max_tag_qng = eep_config->max_total_qng; - } - if (eep_config->max_tag_qng < ASC_MIN_TAG_Q_PER_DVC) { - eep_config->max_tag_qng = ASC_MIN_TAG_Q_PER_DVC; - } - asc_dvc->max_total_qng = eep_config->max_total_qng; - if ((eep_config->use_cmd_qng & eep_config->disc_enable) != - eep_config->use_cmd_qng) { - eep_config->disc_enable = eep_config->use_cmd_qng; - warn_code |= ASC_WARN_CMD_QNG_CONFLICT; + } else if (tmp_disable_init_sdtr) { + asc_dvc->init_sdtr |= tid_bits; } - if (asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL | ASC_IS_EISA)) { - asc_dvc->irq_no = AscGetChipIRQ(iop_base, asc_dvc->bus_type); + ASC_DBG1(1, "AscInitPollTarget: dvc_found %d\n", dvc_found); + return (dvc_found); +} + +STATIC int +PollQueueDone( + REG ASC_DVC_VAR asc_ptr_type * asc_dvc, + REG ASC_SCSI_REQ_Q * scsiq, + int timeout_sec +) +{ + int status; + int retry = 0; + + ASC_DBG1(1, "PollQueueDone: timeout_sec %d\n", timeout_sec); + do { + ASC_DBG(1, "PollQueueDone: before AscExeScsiQueue\n"); + if ((status = AscExeScsiQueue(asc_dvc, + (ASC_SCSI_Q *) scsiq)) == 1) { + ASC_DBG(1, "PollQueueDone: before AscPollQDone\n"); + if ((status = AscPollQDone(asc_dvc, scsiq, + timeout_sec)) != 1) { + ASC_DBG1(1, "PollQueueDone: status %x\n", status); + if (status == 0x80) { + if (retry++ > ASC_MAX_INIT_BUSY_RETRY) { + break; + } + scsiq->r3.done_stat = 0; + scsiq->r3.host_stat = 0; + scsiq->r3.scsi_stat = 0; + scsiq->r3.scsi_msg = 0; + DvcSleepMilliSecond(1000); + continue; + } + scsiq->r3.done_stat = 0; + scsiq->r3.host_stat = 0; + scsiq->r3.scsi_stat = 0; + scsiq->r3.scsi_msg = 0; + ASC_DBG(1, "PollQueueDone: before AscAbortSRB()\n"); + AscAbortSRB(asc_dvc, (ulong) scsiq); + } + ASC_DBG1(1, "PollQueueDone: status %x\n", status); + ASC_DBG1(1, "PollQueueDone: done_stat %x\n", scsiq->r3.done_stat); + return (scsiq->r3.done_stat); + } + ASC_DBG1(1, "PollQueueDone: status %x\n", status); + DvcSleepMilliSecond(5); + } while (((status == 0) || (status == 0x80)) && + retry++ < ASC_MAX_INIT_BUSY_RETRY); + ASC_DBG1(1, "PollQueueDone: status %x\n", status); + ASC_DBG(1, "PollQueueDone: done_stat QD_WITH_ERROR\n"); + return (scsiq->r3.done_stat = QD_WITH_ERROR); +} + +STATIC int +PollScsiInquiry( + REG ASC_DVC_VAR asc_ptr_type * asc_dvc, + REG ASC_SCSI_REQ_Q * scsiq, + uchar * buf, + int buf_len +) +{ + if (AscScsiInquiry(asc_dvc, scsiq, buf, buf_len) == ERR) { + return (scsiq->r3.done_stat = QD_WITH_ERROR); } - eep_config->chip_scsi_id &= ASC_MAX_TID; - asc_dvc->cfg->chip_scsi_id = eep_config->chip_scsi_id; - if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) && - !(asc_dvc->dvc_cntl & ASC_CNTL_SDTR_ENABLE_ULTRA)) { - asc_dvc->host_init_sdtr_index = ASC_SDTR_ULTRA_PCI_10MB_INDEX; + return (PollQueueDone(asc_dvc, (ASC_SCSI_REQ_Q *) scsiq, 4)); +} + +STATIC int +PollScsiStartUnit( + REG ASC_DVC_VAR asc_ptr_type * asc_dvc, + REG ASC_SCSI_REQ_Q * scsiq +) +{ + if (AscScsiStartStopUnit(asc_dvc, scsiq, 1) == ERR) { + return (scsiq->r3.done_stat = QD_WITH_ERROR); } + return (PollQueueDone(asc_dvc, (ASC_SCSI_REQ_Q *) scsiq, 40)); +} - for (i = 0; i <= ASC_MAX_TID; i++) { -#if CC_TMP_USE_EEP_SDTR - asc_dvc->cfg->sdtr_period_offset[i] = eep_config->dos_int13_table[i]; -#endif - asc_dvc->dos_int13_table[i] = eep_config->dos_int13_table[i]; - asc_dvc->cfg->max_tag_qng[i] = eep_config->max_tag_qng; - asc_dvc->cfg->sdtr_period_offset[i] = - (uchar) (ASC_DEF_SDTR_OFFSET | - (asc_dvc->host_init_sdtr_index << 4)); +STATIC int +PollScsiReadCapacity( + REG ASC_DVC_VAR asc_ptr_type * asc_dvc, + REG ASC_SCSI_REQ_Q * scsiq, + REG ASC_CAP_INFO * cap_info +) +{ + 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); } - 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; + status = PollQueueDone(asc_dvc, (ASC_SCSI_REQ_Q *) scsiq, 8); + if (status == 1) { + cap_info->lba = (ulong) * swapfarbuf4((uchar *) & scsi_cap_info.lba); + cap_info->blk_size = (ulong) * swapfarbuf4((uchar *) & scsi_cap_info.blk_size); + return (scsiq->r3.done_stat); } -#endif - return (warn_code); + return (scsiq->r3.done_stat = QD_WITH_ERROR); } -#endif -ASC_INITFUNC( -STATIC ushort -AscInitMicroCodeVar( - ASC_DVC_VAR asc_ptr_type * asc_dvc +STATIC ulong * +swapfarbuf4( + uchar *buf ) +{ + uchar tmp; + + tmp = buf[3]; + buf[3] = buf[0]; + buf[0] = tmp; + + tmp = buf[1]; + buf[1] = buf[2]; + buf[2] = tmp; + + return ((ulong *) buf); +} + +STATIC int +PollScsiTestUnitReady( + REG ASC_DVC_VAR asc_ptr_type * asc_dvc, + REG ASC_SCSI_REQ_Q * scsiq ) { - int i; - 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++) { - AscPutMCodeInitSDTRAtID(iop_base, i, - asc_dvc->cfg->sdtr_period_offset[i] -); - } - AscInitQLinkVar(asc_dvc); - AscWriteLramByte(iop_base, ASCV_DISC_ENABLE_B, - asc_dvc->cfg->disc_enable); - AscWriteLramByte(iop_base, ASCV_HOSTSCSI_ID_B, - ASC_TID_TO_TARGET_ID(asc_dvc->cfg->chip_scsi_id)); - if ((phy_addr = AscGetOnePhyAddr(asc_dvc, - (uchar *) asc_dvc->cfg->overrun_buf, - ASC_OVERRUN_BSIZE)) == 0L) { - asc_dvc->err_code |= ASC_IERR_GET_PHY_ADDR; - } else { - phy_addr = (phy_addr & 0xFFFFFFF8UL) + 8; - AscWriteLramDWord(iop_base, ASCV_OVERRUN_PADDR_D, phy_addr); - AscWriteLramDWord(iop_base, ASCV_OVERRUN_BSIZE_D, - ASC_OVERRUN_BSIZE - 8); - } - asc_dvc->cfg->mcode_date = AscReadLramWord(iop_base, - (ushort) ASCV_MC_DATE_W); - asc_dvc->cfg->mcode_version = AscReadLramWord(iop_base, - (ushort) ASCV_MC_VER_W); - AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR); - if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) { - asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR; - return (warn_code); - } - if (AscStartChip(iop_base) != 1) { - asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP; - return (warn_code); + if (AscScsiTestUnitReady(asc_dvc, scsiq) == ERR) { + return (scsiq->r3.done_stat = QD_WITH_ERROR); } - return (warn_code); + return (PollQueueDone(asc_dvc, (ASC_SCSI_REQ_Q *) scsiq, 12)); } -STATIC void -AscInitPollIsrCallBack( - ASC_DVC_VAR asc_ptr_type * asc_dvc, - ASC_QDONE_INFO * scsi_done_q +STATIC int +InitTestUnitReady( + REG ASC_DVC_VAR asc_ptr_type * asc_dvc, + REG ASC_SCSI_REQ_Q * scsiq ) { - ASC_SCSI_REQ_Q *scsiq_req; - 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; - scsiq_req->r3.done_stat = scsi_done_q->d3.done_stat; - scsiq_req->r3.host_stat = scsi_done_q->d3.host_stat; - scsiq_req->r3.scsi_stat = scsi_done_q->d3.scsi_stat; - scsiq_req->r3.scsi_msg = scsi_done_q->d3.scsi_msg; - ASC_DBG4(1, "AscInitPollIsrCallBack: done_stat %x, host_stat %x, scsi_stat %x, scsi_msg %x\n", - scsi_done_q->d3.done_stat, scsi_done_q->d3.host_stat, - scsi_done_q->d3.scsi_stat, scsi_done_q->d3.scsi_msg); - if ((scsi_done_q->d3.scsi_stat == SS_CHK_CONDITION) && - (scsi_done_q->d3.host_stat == 0)) { - cp_sen_len = (uchar) ASC_MIN_SENSE_LEN; - if (scsiq_req->r1.sense_len < ASC_MIN_SENSE_LEN) { - cp_sen_len = (uchar) scsiq_req->r1.sense_len; - } - for (i = 0; i < cp_sen_len; i++) { - scsiq_req->sense[i] = scsiq_req->sense_ptr[i]; + ASC_SCSI_BIT_ID_TYPE tid_bits; + int retry; + ASC_REQ_SENSE *sen; + + retry = 0; + tid_bits = scsiq->r1.target_id; + while (retry++ < 4) { + PollScsiTestUnitReady(asc_dvc, scsiq); + if (scsiq->r3.done_stat == 0x01) { + return (1); + } else if (scsiq->r3.done_stat == QD_WITH_ERROR) { + 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) { + DvcSleepMilliSecond(250); + continue; + } else { + asc_dvc->start_motor &= ~tid_bits; + break; + } + } else { + DvcSleepMilliSecond(250); + } + } else if (sen->sense_key == SCSI_SENKEY_ATTENTION) { + DvcSleepMilliSecond(250); + } else { + break; + } + } else { + break; } - } - } else { - if (asc_dvc->isr_callback != 0) { - asc_isr_callback = (ASC_ISR_CALLBACK) asc_dvc->isr_callback; - (*asc_isr_callback) (asc_dvc, scsi_done_q); + } else if (scsiq->r3.done_stat == QD_ABORTED_BY_HOST) { + break; + } else { + break; } } - ASC_DBG(1, "AscInitPollIsrCallBack: end\n"); - return; + return (0); } -ASC_INITFUNC( STATIC int -AscTestExternalLram( - ASC_DVC_VAR asc_ptr_type * asc_dvc -) +AscPollQDone( + REG ASC_DVC_VAR asc_ptr_type * asc_dvc, + REG ASC_SCSI_REQ_Q * scsiq, + int timeout_sec ) { - PortAddr iop_base; - ushort q_addr; - ushort saved_word; + int loop, loop_end; int sta; + PortAddr iop_base; + iop_base = asc_dvc->iop_base; - sta = 0; - q_addr = ASC_QNO_TO_QADDR(241); - saved_word = AscReadLramWord(iop_base, q_addr); - AscSetChipLramAddr(iop_base, q_addr); - AscSetChipLramData(iop_base, 0x55AA); - DvcSleepMilliSecond(10); - AscSetChipLramAddr(iop_base, q_addr); - if (AscGetChipLramData(iop_base) == 0x55AA) { - sta = 1; - AscWriteLramWord(iop_base, q_addr, saved_word); + loop = 0; + loop_end = timeout_sec * 100; + sta = 1; + while (TRUE) { + if (asc_dvc->err_code != 0) { + scsiq->r3.done_stat = QD_WITH_ERROR; + ASC_DBG1(1, "AscPollQDone: err_code %x\n", asc_dvc->err_code); + sta = ERR; + break; + } + if (scsiq->r3.done_stat != QD_IN_PROGRESS) { + if ((scsiq->r3.done_stat == QD_WITH_ERROR) && + (scsiq->r3.scsi_stat == SS_TARGET_BUSY)) { + sta = 0x80; + } + break; + } + DvcSleepMilliSecond(10); + if (loop++ > loop_end) { + ASC_DBG(1, "AscPollQDone: loop finished\n"); + sta = 0; + break; + } + if (AscIsChipHalted(iop_base)) { + ASC_DBG(1, "AscPollQDone: AscIsChipHalted()\n"); + AscISR(asc_dvc); + loop = 0; + } else { + if (AscIsIntPending(iop_base)) { + ASC_DBG(1, "AscPollQDone: AscIsIntPending()\n"); + AscISR(asc_dvc); + } + } } return (sta); } -#if CC_INCLUDE_EEP_CONFIG -ASC_INITFUNC( STATIC int -AscWriteEEPCmdReg( - PortAddr iop_base, - uchar cmd_reg -) +AscCompareString( + ruchar * str1, + ruchar * str2, + int len ) { - uchar read_back; - int retry; - retry = 0; - while (TRUE) { - AscSetChipEEPCmd(iop_base, cmd_reg); - DvcSleepMilliSecond(1); - read_back = AscGetChipEEPCmd(iop_base); - if (read_back == cmd_reg) { - return (1); - } - if (retry++ > ASC_EEP_MAX_RETRY) { - return (0); - } + int i; + int diff; + + for (i = 0; i < len; i++) { + diff = (int) (str1[i] - str2[i]); + if (diff != 0) + return (diff); } + return (0); } -ASC_INITFUNC( -STATIC int -AscWriteEEPDataReg( - PortAddr iop_base, - ushort data_reg -) +STATIC uchar +AscReadLramByte( + PortAddr iop_base, + ushort addr ) { - ushort read_back; - int retry; - retry = 0; - while (TRUE) { - AscSetChipEEPData(iop_base, data_reg); - DvcSleepMilliSecond(1); - read_back = AscGetChipEEPData(iop_base); - if (read_back == data_reg) { - return (1); - } - if (retry++ > ASC_EEP_MAX_RETRY) { - return (0); - } + uchar byte_data; + ushort word_data; + + if (isodd_word(addr)) { + AscSetChipLramAddr(iop_base, addr - 1); + word_data = AscGetChipLramData(iop_base); + byte_data = (uchar) ((word_data >> 8) & 0xFF); + } else { + AscSetChipLramAddr(iop_base, addr); + word_data = AscGetChipLramData(iop_base); + byte_data = (uchar) (word_data & 0xFF); } + return (byte_data); } -ASC_INITFUNC( -STATIC void -AscWaitEEPRead( - void -) +STATIC ushort +AscReadLramWord( + PortAddr iop_base, + ushort addr ) { - DvcSleepMilliSecond(1); - return; -} + ushort word_data; -ASC_INITFUNC( -STATIC void -AscWaitEEPWrite( - void -) -) -{ - DvcSleepMilliSecond(20); - return; + AscSetChipLramAddr(iop_base, addr); + word_data = AscGetChipLramData(iop_base); + return (word_data); } -ASC_INITFUNC( -STATIC ushort -AscReadEEPWord( - PortAddr iop_base, - uchar addr -) +STATIC ulong +AscReadLramDWord( + PortAddr iop_base, + ushort addr ) { - ushort read_wval; - uchar cmd_reg; - AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE); - AscWaitEEPRead(); - cmd_reg = addr | ASC_EEP_CMD_READ; - AscWriteEEPCmdReg(iop_base, cmd_reg); - AscWaitEEPRead(); - read_wval = AscGetChipEEPData(iop_base); - AscWaitEEPRead(); - return (read_wval); + ushort val_low, val_high; + ulong dword_data; + + AscSetChipLramAddr(iop_base, addr); + val_low = AscGetChipLramData(iop_base); + val_high = AscGetChipLramData(iop_base); + dword_data = ((ulong) val_high << 16) | (ulong) val_low; + return (dword_data); } -ASC_INITFUNC( -STATIC ushort -AscWriteEEPWord( - PortAddr iop_base, - uchar addr, - ushort word_val -) +STATIC void +AscWriteLramWord( + PortAddr iop_base, + ushort addr, + ushort word_val ) { - ushort read_wval; - read_wval = AscReadEEPWord(iop_base, addr); - if (read_wval != word_val) { - AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_ABLE); - AscWaitEEPRead(); - AscWriteEEPDataReg(iop_base, word_val); - AscWaitEEPRead(); - AscWriteEEPCmdReg(iop_base, - (uchar) ((uchar) ASC_EEP_CMD_WRITE | addr)); - AscWaitEEPWrite(); - AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE); - AscWaitEEPRead(); - return (AscReadEEPWord(iop_base, addr)); - } - return (read_wval); + AscSetChipLramAddr(iop_base, addr); + AscSetChipLramData(iop_base, word_val); + return; } -ASC_INITFUNC( -STATIC ushort -AscGetEEPConfig( - PortAddr iop_base, - ASCEEP_CONFIG * cfg_buf, ushort bus_type -) +STATIC void +AscWriteLramDWord( + PortAddr iop_base, + ushort addr, + ulong dword_val ) { - ushort wval; - ushort sum; - ushort *wbuf; - int cfg_beg; - int cfg_end; - int s_addr; - int isa_pnp_wsize; - wbuf = (ushort *) cfg_buf; - sum = 0; - isa_pnp_wsize = 0; - for (s_addr = 0; s_addr < (2 + isa_pnp_wsize); s_addr++, wbuf++) { - wval = AscReadEEPWord(iop_base, (uchar) s_addr); - sum += wval; - *wbuf = wval; - } - if (bus_type & ASC_IS_VL) { - cfg_beg = ASC_EEP_DVC_CFG_BEG_VL; - cfg_end = ASC_EEP_MAX_DVC_ADDR_VL; - } else { - cfg_beg = ASC_EEP_DVC_CFG_BEG; - cfg_end = ASC_EEP_MAX_DVC_ADDR; - } - for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); - s_addr++, wbuf++) { - wval = AscReadEEPWord(iop_base, (uchar) s_addr); - sum += wval; - *wbuf = wval; - } - *wbuf = AscReadEEPWord(iop_base, (uchar) s_addr); - return (sum); + ushort word_val; + + AscSetChipLramAddr(iop_base, addr); + word_val = (ushort) dword_val; + AscSetChipLramData(iop_base, word_val); + word_val = (ushort) (dword_val >> 16); + AscSetChipLramData(iop_base, word_val); + return; } -#if CC_CHK_FIX_EEP_CONTENT -ASC_INITFUNC( -STATIC int -AscSetEEPConfigOnce( - PortAddr iop_base, - ASCEEP_CONFIG * cfg_buf, ushort bus_type -) +STATIC void +AscWriteLramByte( + PortAddr iop_base, + ushort addr, + uchar byte_val ) { - int n_error; - ushort *wbuf; - ushort sum; - int s_addr; - int cfg_beg; - int cfg_end; - wbuf = (ushort *) cfg_buf; - n_error = 0; - sum = 0; - for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) { - sum += *wbuf; - if (*wbuf != AscWriteEEPWord(iop_base, (uchar) s_addr, *wbuf)) { - n_error++; - } - } - if (bus_type & ASC_IS_VL) { - cfg_beg = ASC_EEP_DVC_CFG_BEG_VL; - cfg_end = ASC_EEP_MAX_DVC_ADDR_VL; - } else { - cfg_beg = ASC_EEP_DVC_CFG_BEG; - cfg_end = ASC_EEP_MAX_DVC_ADDR; - } - for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); - s_addr++, wbuf++) { - sum += *wbuf; - if (*wbuf != AscWriteEEPWord(iop_base, (uchar) s_addr, *wbuf)) { - n_error++; - } - } - *wbuf = sum; - if (sum != AscWriteEEPWord(iop_base, (uchar) s_addr, sum)) { - n_error++; - } - wbuf = (ushort *) cfg_buf; - for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) { - if (*wbuf != AscReadEEPWord(iop_base, (uchar) s_addr)) { - n_error++; - } - } - for (s_addr = cfg_beg; s_addr <= cfg_end; - s_addr++, wbuf++) { - if (*wbuf != AscReadEEPWord(iop_base, (uchar) s_addr)) { - n_error++; - } + ushort word_data; + + if (isodd_word(addr)) { + addr--; + word_data = AscReadLramWord(iop_base, addr); + word_data &= 0x00FF; + word_data |= (((ushort) byte_val << 8) & 0xFF00); + } else { + word_data = AscReadLramWord(iop_base, addr); + word_data &= 0xFF00; + word_data |= ((ushort) byte_val & 0x00FF); } - return (n_error); + AscWriteLramWord(iop_base, addr, word_data); + return; } -ASC_INITFUNC( -STATIC int -AscSetEEPConfig( - PortAddr iop_base, - ASCEEP_CONFIG * cfg_buf, ushort bus_type -) +STATIC void +AscMemWordCopyToLram( + PortAddr iop_base, + ushort s_addr, + ushort * s_buffer, + int words ) { - int retry; - int n_error; + AscSetChipLramAddr(iop_base, s_addr); + DvcOutPortWords(iop_base + IOP_RAM_DATA, s_buffer, words); + return; +} - retry = 0; - while (TRUE) { - if ((n_error = AscSetEEPConfigOnce(iop_base, cfg_buf, - bus_type)) == 0) { - break; - } - if (++retry > ASC_EEP_MAX_RETRY) { - break; - } - } - return (n_error); +STATIC void +AscMemDWordCopyToLram( + PortAddr iop_base, + ushort s_addr, + ulong * s_buffer, + int dwords +) +{ + AscSetChipLramAddr(iop_base, s_addr); + DvcOutPortDWords(iop_base + IOP_RAM_DATA, s_buffer, dwords); + return; } -#endif -#endif -STATIC int -AscInitPollBegin( - REG ASC_DVC_VAR asc_ptr_type * asc_dvc +STATIC void +AscMemWordCopyFromLram( + PortAddr iop_base, + ushort s_addr, + ushort * d_buffer, + int words ) { - PortAddr iop_base; - iop_base = asc_dvc->iop_base; - AscDisableInterrupt(iop_base); - asc_dvc->init_state |= ASC_INIT_STATE_BEG_INQUIRY; - AscWriteLramByte(iop_base, ASCV_DISC_ENABLE_B, 0x00); - asc_dvc->use_tagged_qng = 0; - asc_dvc->cfg->can_tagged_qng = 0; - asc_dvc->saved_ptr2func = (ulong) asc_dvc->isr_callback; - asc_dvc->isr_callback = ASC_GET_PTR2FUNC(AscInitPollIsrCallBack); - return (0); + AscSetChipLramAddr(iop_base, s_addr); + DvcInPortWords(iop_base + IOP_RAM_DATA, d_buffer, words); + return; } -STATIC int -AscInitPollEnd( - REG ASC_DVC_VAR asc_ptr_type * asc_dvc +STATIC ulong +AscMemSumLramWord( + PortAddr iop_base, + ushort s_addr, + rint words ) { - 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, - asc_dvc->cfg->disc_enable); - AscWriteLramByte(iop_base, ASCV_USE_TAGGED_QNG_B, - asc_dvc->use_tagged_qng); - AscWriteLramByte(iop_base, ASCV_CAN_TAGGED_QNG_B, - asc_dvc->cfg->can_tagged_qng); - for (i = 0; i <= ASC_MAX_TID; i++) { - AscWriteLramByte(iop_base, - (ushort) ((ushort) ASCV_MAX_DVC_QNG_BEG + (ushort) i), - asc_dvc->max_dvc_qng[i]); + ulong sum; + int i; + + sum = 0L; + for (i = 0; i < words; i++, s_addr += 2) { + sum += AscReadLramWord(iop_base, s_addr); } - AscAckInterrupt(iop_base); - AscEnableInterrupt(iop_base); - asc_dvc->init_state |= ASC_INIT_STATE_END_INQUIRY; - return (0); + return (sum); } -STATIC int _asc_wait_slow_device_ = FALSE; - -STATIC int -AscInitPollTarget( - REG ASC_DVC_VAR asc_ptr_type * asc_dvc, - REG ASC_SCSI_REQ_Q * scsiq, - REG ASC_SCSI_INQUIRY * inq, - REG ASC_CAP_INFO * cap_info +STATIC void +AscMemWordSetLram( + PortAddr iop_base, + ushort s_addr, + ushort set_wval, + rint words ) { - uchar tid_no, lun; - uchar dvc_type; - ASC_SCSI_BIT_ID_TYPE tid_bits; - int dvc_found; - int support_read_cap; - int tmp_disable_init_sdtr; - int sta; + rint i; - dvc_found = 0; - tmp_disable_init_sdtr = FALSE; - tid_bits = scsiq->r1.target_id; - lun = scsiq->r1.target_lun; - tid_no = ASC_TIX_TO_TID(scsiq->r2.target_ix); - if (((asc_dvc->init_sdtr & tid_bits) != 0) && - ((asc_dvc->sdtr_done & tid_bits) == 0)) { - asc_dvc->init_sdtr &= ~tid_bits; - tmp_disable_init_sdtr = TRUE; + AscSetChipLramAddr(iop_base, s_addr); + for (i = 0; i < words; i++) { + AscSetChipLramData(iop_base, set_wval); } - ASC_DBG(1, "AscInitPollTarget: before PollScsiInquiry\n"); - 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) { - if ((dvc_type != SCSI_TYPE_DASD) - && (dvc_type != SCSI_TYPE_WORM) - && (dvc_type != SCSI_TYPE_CDROM) - && (dvc_type != SCSI_TYPE_OPTMEM)) { - 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)) { - if (inq->byte7.CmdQue) { - asc_dvc->cfg->can_tagged_qng |= tid_bits; - if (asc_dvc->cfg->cmd_qng_enabled & tid_bits) { - asc_dvc->use_tagged_qng |= tid_bits; - asc_dvc->max_dvc_qng[tid_no] = asc_dvc->cfg->max_tag_qng[tid_no]; - } - } - if (!inq->byte7.Sync) { - asc_dvc->init_sdtr &= ~tid_bits; - asc_dvc->sdtr_done &= ~tid_bits; - } else if (tmp_disable_init_sdtr) { - asc_dvc->init_sdtr |= tid_bits; - } - } else { - asc_dvc->init_sdtr &= ~tid_bits; - asc_dvc->sdtr_done &= ~tid_bits; - asc_dvc->use_tagged_qng &= ~tid_bits; - } - } - if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_ASYN_USE_SYN) { - if (!(asc_dvc->init_sdtr & tid_bits)) { - if ((dvc_type == SCSI_TYPE_CDROM) && - (AscCompareString((uchar *) inq->vendor_id, - (uchar *) "HP ", 3) == 0)) { - asc_dvc->pci_fix_asyn_xfer_always |= tid_bits; - } - asc_dvc->pci_fix_asyn_xfer |= tid_bits; - if ((dvc_type == SCSI_TYPE_PROC) || (dvc_type == SCSI_TYPE_SCANNER)) { - asc_dvc->pci_fix_asyn_xfer &= ~tid_bits; - } - if ((dvc_type == SCSI_TYPE_SASD) && - (AscCompareString((uchar *) inq->vendor_id, - (uchar *) "TANDBERG", 8) == 0) && - (AscCompareString((uchar *) inq->product_id, - (uchar *) " TDC 36", 7) == 0)) { - asc_dvc->pci_fix_asyn_xfer &= ~tid_bits; - } - if ((dvc_type == SCSI_TYPE_SASD) && - (AscCompareString((uchar *) inq->vendor_id, - (uchar *) "WANGTEK ", 8) == 0)) { - asc_dvc->pci_fix_asyn_xfer &= ~tid_bits; - } + return; +} - if ((dvc_type == SCSI_TYPE_CDROM) && - (AscCompareString((uchar *)inq->vendor_id, - (uchar *)"NEC ", 8) == 0) && - (AscCompareString((uchar *)inq->product_id, - (uchar *)"CD-ROM DRIVE ", 16) == 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, - ASYN_SDTR_DATA_FIX_PCI_REV_AB); - } - } - } - sta = 1; - ASC_DBG(1, "AscInitPollTarget: before InitTestUnitReady\n"); - sta = InitTestUnitReady(asc_dvc, scsiq); - if (sta == 1) { - if ((cap_info != 0L) && support_read_cap) { - ASC_DBG(1, - "AscInitPollTarget: before PollScsiReadCapacity\n"); - if (PollScsiReadCapacity(asc_dvc, scsiq, - cap_info) != 1) { - cap_info->lba = 0L; - cap_info->blk_size = 0x0000; - } else { - } - } - } - } else { - asc_dvc->start_motor &= ~tid_bits; - } - } else if (tmp_disable_init_sdtr) { - asc_dvc->init_sdtr |= tid_bits; + +STATIC int +AscScsiInquiry( + REG ASC_DVC_VAR asc_ptr_type * asc_dvc, + REG ASC_SCSI_REQ_Q * scsiq, + uchar * buf, + int buf_len +) +{ + if (AscScsiSetupCmdQ(asc_dvc, scsiq, buf, + (ulong) buf_len) == ERR) { + return (scsiq->r3.done_stat = QD_WITH_ERROR); } - ASC_DBG1(1, "AscInitPollTarget: dvc_found %d\n", dvc_found); - return (dvc_found); + scsiq->cdb[0] = (uchar) SCSICMD_Inquiry; + scsiq->cdb[1] = scsiq->r1.target_lun << 5; + scsiq->cdb[2] = 0; + scsiq->cdb[3] = 0; + scsiq->cdb[4] = buf_len; + scsiq->cdb[5] = 0; + scsiq->r2.cdb_len = 6; + return (0); } STATIC int -PollQueueDone( - REG ASC_DVC_VAR asc_ptr_type * asc_dvc, - REG ASC_SCSI_REQ_Q * scsiq, - int timeout_sec +AscScsiReadCapacity( + REG ASC_DVC_VAR asc_ptr_type * asc_dvc, + REG ASC_SCSI_REQ_Q * scsiq, + uchar * info ) { - int status; - int retry = 0; + if (AscScsiSetupCmdQ(asc_dvc, scsiq, info, 8L) == ERR) { + return (scsiq->r3.done_stat = QD_WITH_ERROR); + } + scsiq->cdb[0] = (uchar) SCSICMD_ReadCapacity; + scsiq->cdb[1] = scsiq->r1.target_lun << 5; + scsiq->cdb[2] = 0; + scsiq->cdb[3] = 0; + scsiq->cdb[4] = 0; + scsiq->cdb[5] = 0; + scsiq->cdb[6] = 0; + scsiq->cdb[7] = 0; + scsiq->cdb[8] = 0; + scsiq->cdb[9] = 0; + scsiq->r2.cdb_len = 10; + return (0); +} - ASC_DBG1(1, "PollQueueDone: timeout_sec %d\n", timeout_sec); - do { - ASC_DBG(1, "PollQueueDone: before AscExeScsiQueue\n"); - if ((status = AscExeScsiQueue(asc_dvc, - (ASC_SCSI_Q *) scsiq)) == 1) { - ASC_DBG(1, "PollQueueDone: before AscPollQDone\n"); - if ((status = AscPollQDone(asc_dvc, scsiq, - timeout_sec)) != 1) { - ASC_DBG1(1, "PollQueueDone: status %x\n", status); - if (status == 0x80) { - if (retry++ > ASC_MAX_INIT_BUSY_RETRY) { - break; - } - scsiq->r3.done_stat = 0; - scsiq->r3.host_stat = 0; - scsiq->r3.scsi_stat = 0; - scsiq->r3.scsi_msg = 0; - DvcSleepMilliSecond(2000); - continue; - } - scsiq->r3.done_stat = 0; - scsiq->r3.host_stat = 0; - scsiq->r3.scsi_stat = 0; - scsiq->r3.scsi_msg = 0; - ASC_DBG(1, "PollQueueDone: before AscAbortSRB()\n"); - AscAbortSRB(asc_dvc, (ulong) scsiq); - } - ASC_DBG1(1, "PollQueueDone: status %x\n", status); - ASC_DBG1(1, "PollQueueDone: done_stat %x\n", scsiq->r3.done_stat); - return (scsiq->r3.done_stat); - } - ASC_DBG1(1, "PollQueueDone: status %x\n", status); - DvcSleepMilliSecond(5); - } while (((status == 0) || (status == 0x80)) && - retry++ < ASC_MAX_INIT_BUSY_RETRY); - ASC_DBG1(1, "PollQueueDone: status %x\n", status); - ASC_DBG(1, "PollQueueDone: done_stat QD_WITH_ERROR\n"); - return (scsiq->r3.done_stat = QD_WITH_ERROR); +STATIC int +AscScsiTestUnitReady( + REG ASC_DVC_VAR asc_ptr_type * asc_dvc, + REG ASC_SCSI_REQ_Q * scsiq +) +{ + if (AscScsiSetupCmdQ(asc_dvc, scsiq, FNULLPTR, + (ulong) 0L) == ERR) { + return (scsiq->r3.done_stat = QD_WITH_ERROR); + } + scsiq->r1.cntl = (uchar) ASC_SCSIDIR_NODATA; + scsiq->cdb[0] = (uchar) SCSICMD_TestUnitReady; + scsiq->cdb[1] = scsiq->r1.target_lun << 5; + scsiq->cdb[2] = 0; + scsiq->cdb[3] = 0; + scsiq->cdb[4] = 0; + scsiq->cdb[5] = 0; + scsiq->r2.cdb_len = 6; + return (0); } STATIC int -PollScsiInquiry( - REG ASC_DVC_VAR asc_ptr_type * asc_dvc, - REG ASC_SCSI_REQ_Q * scsiq, - uchar * buf, - int buf_len +AscScsiStartStopUnit( + REG ASC_DVC_VAR asc_ptr_type * asc_dvc, + REG ASC_SCSI_REQ_Q * scsiq, + uchar op_mode ) { - if (AscScsiInquiry(asc_dvc, scsiq, buf, buf_len) == ERR) { + if (AscScsiSetupCmdQ(asc_dvc, scsiq, FNULLPTR, (ulong) 0L) == ERR) { return (scsiq->r3.done_stat = QD_WITH_ERROR); } - return (PollQueueDone(asc_dvc, (ASC_SCSI_REQ_Q *) scsiq, 4)); -} + scsiq->r1.cntl = (uchar) ASC_SCSIDIR_NODATA; + scsiq->cdb[0] = (uchar) SCSICMD_StartStopUnit; + scsiq->cdb[1] = scsiq->r1.target_lun << 5; + scsiq->cdb[2] = 0; + scsiq->cdb[3] = 0; + scsiq->cdb[4] = op_mode; + 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; + } -STATIC int -PollScsiStartUnit( - REG ASC_DVC_VAR asc_ptr_type * asc_dvc, - REG ASC_SCSI_REQ_Q * scsiq -) -{ - if (AscScsiStartStopUnit(asc_dvc, scsiq, 1) == ERR) { - return (scsiq->r3.done_stat = QD_WITH_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; } - return (PollQueueDone(asc_dvc, (ASC_SCSI_REQ_Q *) scsiq, 40)); -} -STATIC int -PollScsiReadCapacity( - REG ASC_DVC_VAR asc_ptr_type * asc_dvc, - REG ASC_SCSI_REQ_Q * scsiq, - REG ASC_CAP_INFO * cap_info -) -{ - 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); + /* + * 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; } - 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); + + /* + * 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; + } } - return (scsiq->r3.done_stat = QD_WITH_ERROR); -} -STATIC ulong * -swapfarbuf4( - uchar *buf -) -{ - uchar tmp; + /* + * Clear any set TERM_CTL_H and TERM_CTL_L bits. + */ + scsi_cfg1 &= ~TERM_CTL; - tmp = buf[3]; - buf[3] = buf[0]; - buf[0] = tmp; + /* + * 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)); - tmp = buf[1]; - buf[1] = buf[2]; - buf[2] = tmp; + /* + * 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); - return ((ulong *) buf); -} + /* + * 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)); -STATIC int -PollScsiTestUnitReady( - REG ASC_DVC_VAR asc_ptr_type * asc_dvc, - REG ASC_SCSI_REQ_Q * scsiq -) -{ - if (AscScsiTestUnitReady(asc_dvc, scsiq) == ERR) { - return (scsiq->r3.done_stat = QD_WITH_ERROR); + /* + * 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); } - return (PollQueueDone(asc_dvc, (ASC_SCSI_REQ_Q *) scsiq, 12)); -} -STATIC int -InitTestUnitReady( - REG ASC_DVC_VAR asc_ptr_type * asc_dvc, - REG ASC_SCSI_REQ_Q * scsiq -) -{ - ASC_SCSI_BIT_ID_TYPE tid_bits; - int retry; - ASC_REQ_SENSE *sen; - retry = 0; - tid_bits = scsiq->r1.target_id; - while (retry++ < 4) { - PollScsiTestUnitReady(asc_dvc, scsiq); - 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 (asc_dvc->start_motor & tid_bits) { - if (PollScsiStartUnit(asc_dvc, scsiq) == 1) { - retry = 0; - continue; - } else { - asc_dvc->start_motor &= ~tid_bits; - break; - } - } else { - DvcSleepMilliSecond(5000); - } - } else if (sen->sense_key == SCSI_SENKEY_ATTENTION) { - DvcSleepMilliSecond((ulong)(500L*retry)) ; - } else { - DvcSleepMilliSecond(500) ; - break; - } - } else { - break; - } - } else if (scsiq->r3.done_stat == QD_ABORTED_BY_HOST) { - break; - } else { - break; - } - } - return (0); + /* + * 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 -AscPollQDone( - REG ASC_DVC_VAR asc_ptr_type * asc_dvc, - REG ASC_SCSI_REQ_Q * scsiq, - int timeout_sec +AdvInitFromEEP(ADV_DVC_VAR *asc_dvc) ) { - int loop, loop_end; - int sta; - PortAddr iop_base; + AdvPortAddr iop_base; + ushort warn_code; + ADVEEP_CONFIG eep_config; + int i; + iop_base = asc_dvc->iop_base; - loop = 0; - loop_end = timeout_sec * 100; - sta = 1; - while (TRUE) { - if (asc_dvc->err_code != 0) { - scsiq->r3.done_stat = QD_WITH_ERROR; - ASC_DBG1(1, "AscPollQDone: err_code %x\n", asc_dvc->err_code); - sta = ERR; - break; + + 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); } - if (scsiq->r3.done_stat != QD_IN_PROGRESS) { - if ((scsiq->r3.done_stat == QD_WITH_ERROR) && - (scsiq->r3.scsi_stat == SS_TARGET_BUSY)) { - sta = 0x80; - } - break; + + /* + * 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; } - DvcSleepMilliSecond(10); - if (loop++ > loop_end) { - ASC_DBG(1, "AscPollQDone: loop finished\n"); - sta = 0; - break; + } + + 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 (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); - } + } + + /* + * 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 (sta); -} -STATIC int -AscCompareString( - ruchar * str1, - ruchar * str2, - int len -) -{ - int i; - int diff; - for (i = 0; i < len; i++) { - diff = (int) (str1[i] - str2[i]); - if (diff != 0) - return (diff); - } - return (0); + return warn_code; } -STATIC uchar -AscReadLramByte( - PortAddr iop_base, - ushort addr +/* + * 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) ) { - uchar byte_data; - ushort word_data; - if (isodd_word(addr)) { - AscSetChipLramAddr(iop_base, addr - 1); - word_data = AscGetChipLramData(iop_base); - byte_data = (uchar) ((word_data >> 8) & 0xFF); - } else { - AscSetChipLramAddr(iop_base, addr); - word_data = AscGetChipLramData(iop_base); - byte_data = (uchar) (word_data & 0xFF); + 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; } - return (byte_data); + *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 -AscReadLramWord( - PortAddr iop_base, - ushort addr +AdvReadEEPWord(AdvPortAddr iop_base, int eep_word_addr) ) { - ushort word_data; - AscSetChipLramAddr(iop_base, addr); - word_data = AscGetChipLramData(iop_base); - return (word_data); + AdvWriteWordRegister(iop_base, IOPW_EE_CMD, + ASC_EEP_CMD_READ | eep_word_addr); + AdvWaitEEPCmd(iop_base); + return AdvReadWordRegister(iop_base, IOPW_EE_DATA); } -STATIC ulong -AscReadLramDWord( - PortAddr iop_base, - ushort addr +/* + * Wait for EEPROM command to complete + */ +ASC_INITFUNC( +STATIC void +AdvWaitEEPCmd(AdvPortAddr iop_base) ) { - ushort val_low, val_high; - ulong dword_data; - AscSetChipLramAddr(iop_base, addr); - val_low = AscGetChipLramData(iop_base); - val_high = AscGetChipLramData(iop_base); - dword_data = ((ulong) val_high << 16) | (ulong) val_low; - return (dword_data); + 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 -AscWriteLramWord( - PortAddr iop_base, - ushort addr, - ushort word_val +AdvSetEEPConfig(AdvPortAddr iop_base, ADVEEP_CONFIG *cfg_buf) ) { - AscSetChipLramAddr(iop_base, addr); - AscSetChipLramData(iop_base, word_val); + 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 -AscWriteLramDWord( - PortAddr iop_base, - ushort addr, - ulong dword_val +AdvResetChip(ADV_DVC_VAR *asc_dvc) ) { - ushort word_val; - AscSetChipLramAddr(iop_base, addr); - word_val = (ushort) dword_val; - AscSetChipLramData(iop_base, word_val); - word_val = (ushort) (dword_val >> 16); - AscSetChipLramData(iop_base, word_val); - return; + 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); } -STATIC void -AscWriteLramByte( - PortAddr iop_base, - ushort addr, - uchar byte_val -) +/* 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) { - ushort word_data; - if (isodd_word(addr)) { - addr--; - word_data = AscReadLramWord(iop_base, addr); - word_data &= 0x00FF; - word_data |= (((ushort) byte_val << 8) & 0xFF00); - } else { - word_data = AscReadLramWord(iop_base, addr); - word_data &= 0xFF00; - word_data |= ((ushort) byte_val & 0x00FF); + if (scsiq == (ADV_SCSI_REQ_Q *) 0L) + { + /* 'scsiq' should never be NULL. */ + ADV_ASSERT(0); + return ADV_ERROR; } - AscWriteLramWord(iop_base, addr, word_data); - return; + + 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 -AscMemWordCopyToLram( - PortAddr iop_base, - ushort s_addr, - ushort * s_buffer, - int words -) +AdvResetSCSIBus(ADV_DVC_VAR *asc_dvc) { - AscSetChipLramAddr(iop_base, s_addr); - DvcOutPortWords(iop_base + IOP_RAM_DATA, s_buffer, words); - return; + 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); } -STATIC void -AscMemDWordCopyToLram( - PortAddr iop_base, - ushort s_addr, - ulong * s_buffer, - int dwords -) -{ - AscSetChipLramAddr(iop_base, s_addr); - DvcOutPortDWords(iop_base + IOP_RAM_DATA, s_buffer, dwords); - return; + +/* + * 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; } -STATIC void -AscMemWordCopyFromLram( - PortAddr iop_base, - ushort s_addr, - ushort * d_buffer, - int words -) +/* + * 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) { - AscSetChipLramAddr(iop_base, s_addr); - DvcInPortWords(iop_base + IOP_RAM_DATA, d_buffer, words); - return; -} + int last_int_level; + ulong i; + AdvPortAddr iop_base; + int ret; -STATIC ulong -AscMemSumLramWord( - PortAddr iop_base, - ushort s_addr, - rint words -) -{ - ulong sum; - int i; - sum = 0L; - for (i = 0; i < words; i++, s_addr += 2) { - sum += AscReadLramWord(iop_base, s_addr); + 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; } - return (sum); -} -STATIC void -AscMemWordSetLram( - PortAddr iop_base, - ushort s_addr, - ushort set_wval, - rint words -) -{ - rint i; - AscSetChipLramAddr(iop_base, s_addr); - for (i = 0; i < words; i++) { - AscSetChipLramData(iop_base, set_wval); + 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); } - return; -} + last_int_level = DvcEnterCritical(); -STATIC int -AscScsiInquiry( - REG ASC_DVC_VAR asc_ptr_type * asc_dvc, - REG ASC_SCSI_REQ_Q * scsiq, - uchar * buf, - int buf_len -) -{ - if (AscScsiSetupCmdQ(asc_dvc, scsiq, buf, - (ulong) buf_len) == ERR) { - return (scsiq->r3.done_stat = QD_WITH_ERROR); + 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; } - scsiq->cdb[0] = (uchar) SCSICMD_Inquiry; - scsiq->cdb[1] = scsiq->r1.target_lun << 5; - scsiq->cdb[2] = 0; - scsiq->cdb[3] = 0; - scsiq->cdb[4] = buf_len; - scsiq->cdb[5] = 0; - scsiq->r2.cdb_len = 6; - return (0); } +/* + * 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 -AscScsiReadCapacity( - REG ASC_DVC_VAR asc_ptr_type * asc_dvc, - REG ASC_SCSI_REQ_Q * scsiq, - uchar * info -) +AdvSendScsiCmd( + ADV_DVC_VAR *asc_dvc, + ADV_SCSI_REQ_Q *scsiq) { - if (AscScsiSetupCmdQ(asc_dvc, scsiq, info, 8L) == ERR) { - return (scsiq->r3.done_stat = QD_WITH_ERROR); + 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; } - scsiq->cdb[0] = (uchar) SCSICMD_ReadCapacity; - scsiq->cdb[1] = scsiq->r1.target_lun << 5; - scsiq->cdb[2] = 0; - scsiq->cdb[3] = 0; - scsiq->cdb[4] = 0; - scsiq->cdb[5] = 0; - scsiq->cdb[6] = 0; - scsiq->cdb[7] = 0; - scsiq->cdb[8] = 0; - scsiq->cdb[9] = 0; - scsiq->r2.cdb_len = 10; - return (0); -} -STATIC int -AscScsiTestUnitReady( - REG ASC_DVC_VAR asc_ptr_type * asc_dvc, - REG ASC_SCSI_REQ_Q * scsiq -) -{ - if (AscScsiSetupCmdQ(asc_dvc, scsiq, FNULLPTR, - (ulong) 0L) == ERR) { - return (scsiq->r3.done_stat = QD_WITH_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++; } - scsiq->r1.cntl = (uchar) ASC_SCSIDIR_NODATA; - scsiq->cdb[0] = (uchar) SCSICMD_TestUnitReady; - scsiq->cdb[1] = scsiq->r1.target_lun << 5; - scsiq->cdb[2] = 0; - scsiq->cdb[3] = 0; - scsiq->cdb[4] = 0; - scsiq->cdb[5] = 0; - scsiq->r2.cdb_len = 6; - return (0); + + /* + * 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; } -STATIC int -AscScsiStartStopUnit( - REG ASC_DVC_VAR asc_ptr_type * asc_dvc, - REG ASC_SCSI_REQ_Q * scsiq, - uchar op_mode -) +/* + * 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) { - if (AscScsiSetupCmdQ(asc_dvc, scsiq, FNULLPTR, (ulong) 0L) == ERR) { - return (scsiq->r3.done_stat = QD_WITH_ERROR); + 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); + } } - scsiq->r1.cntl = (uchar) ASC_SCSIDIR_NODATA; - scsiq->cdb[0] = (uchar) SCSICMD_StartStopUnit; - scsiq->cdb[1] = scsiq->r1.target_lun << 5; - scsiq->cdb[2] = 0; - scsiq->cdb[3] = 0; - scsiq->cdb[4] = op_mode; - scsiq->cdb[5] = 0; - scsiq->r2.cdb_len = 6; - return (0); } diff --git a/drivers/scsi/advansys.h b/drivers/scsi/advansys.h index 54858404a..010cd6153 100644 --- a/drivers/scsi/advansys.h +++ b/drivers/scsi/advansys.h @@ -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 @@ const char *advansys_info(struct Scsi_Host *); 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 @@ void advansys_setup(char *, int *); /* * 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 --git a/drivers/scsi/pci2000.h b/drivers/scsi/pci2000.h index 415cc8794..ab8458d1d 100644 --- a/drivers/scsi/pci2000.h +++ b/drivers/scsi/pci2000.h @@ -209,7 +209,7 @@ extern struct proc_dir_entry Proc_Scsi_Pci2000; 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 --git a/drivers/scsi/pci2220i.h b/drivers/scsi/pci2220i.h index 1658135be..1a9bd6cad 100644 --- a/drivers/scsi/pci2220i.h +++ b/drivers/scsi/pci2220i.h @@ -328,7 +328,7 @@ extern struct proc_dir_entry Proc_Scsi_Pci2220i; 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 --git a/drivers/scsi/pluto.c b/drivers/scsi/pluto.c new file mode 100644 index 000000000..3b4598a3f --- /dev/null +++ b/drivers/scsi/pluto.c @@ -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 --git a/drivers/scsi/pluto.h b/drivers/scsi/pluto.h new file mode 100644 index 000000000..6dbda6a57 --- /dev/null +++ b/drivers/scsi/pluto.h @@ -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 --git a/drivers/scsi/psi240i.h b/drivers/scsi/psi240i.h index 0580c758c..1aed96ec7 100644 --- a/drivers/scsi/psi240i.h +++ b/drivers/scsi/psi240i.h @@ -327,7 +327,7 @@ extern struct proc_dir_entry Proc_Scsi_Psi240i; 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 --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 91f0eb3fe..262c6da58 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -200,16 +200,6 @@ extern int dispatch_scsi_info(int ino, char *buffer, char **start, 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 @@ scsi_dump_status(int level) 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 --git a/drivers/scsi/t128.c b/drivers/scsi/t128.c index ff074388c..48036ed33 100644 --- a/drivers/scsi/t128.c +++ b/drivers/scsi/t128.c @@ -141,11 +141,11 @@ static struct override { #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 @@ __initfunc(void t128_setup(char *str, int *ints)) { 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 @@ __initfunc(int t128_detect(Scsi_Host_Template * tpnt)) { 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 @@ __initfunc(int t128_detect(Scsi_Host_Template * tpnt)) { 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 --git a/drivers/sound/audio.c b/drivers/sound/audio.c index 2eb2c0da7..9b6fa5c12 100644 --- a/drivers/sound/audio.c +++ b/drivers/sound/audio.c @@ -350,7 +350,7 @@ int audio_read(int dev, struct fileinfo *file, char *buf, int count) 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 --git a/drivers/sound/dev_table.c b/drivers/sound/dev_table.c index 79583cbca..63dacee8e 100644 --- a/drivers/sound/dev_table.c +++ b/drivers/sound/dev_table.c @@ -36,9 +36,9 @@ int snd_find_driver(int type) static void start_services(void) { +#ifdef FIXME int soundcards_installed; -#ifdef FIXME if (!(soundcards_installed = sndtable_get_cardcount())) return; /* No cards detected */ #endif diff --git a/drivers/sound/gus_card.c b/drivers/sound/gus_card.c index 823452ef4..141cd7db8 100644 --- a/drivers/sound/gus_card.c +++ b/drivers/sound/gus_card.c @@ -28,8 +28,7 @@ extern int gus_pcm_volume; 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 @@ attach_gus_card(struct address_info *hw_config) #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 @@ probe_gus(struct address_info *hw_config) 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 @@ probe_gus(struct address_info *hw_config) 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 @@ unload_gus(struct address_info *hw_config) 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 @@ gusintr(int irq, void *dev_id, struct pt_regs *dummy) #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 @@ attach_gus_db16(struct address_info *hw_config) 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(type, "i"); 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 @@ init_module(void) #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 @@ init_module(void) return 0; } -void -cleanup_module(void) +void cleanup_module(void) { #if defined(CONFIG_GUS16) if (db16) diff --git a/drivers/sound/gus_midi.c b/drivers/sound/gus_midi.c index 67e4d928d..b3a33061e 100644 --- a/drivers/sound/gus_midi.c +++ b/drivers/sound/gus_midi.c @@ -33,24 +33,18 @@ static volatile unsigned char qhead, qtail; 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 @@ gus_midi_open(int dev, int mode, 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 @@ gus_midi_open(int dev, int mode, 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 @@ dump_to_midi(unsigned char midi_byte) 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 @@ gus_midi_close(int dev) 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 @@ gus_midi_out(int dev, unsigned char midi_byte) 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 @@ gus_midi_out(int dev, unsigned char midi_byte) */ /* - * 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 @@ gus_midi_out(int dev, unsigned char midi_byte) 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 @@ gus_midi_buffer_status(int dev) 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 @@ gus_midi_buffer_status(int dev) 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 @@ static struct midi_operations gus_midi_operations = 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 @@ gus_midi_init(struct address_info *hw_config) 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 --git a/drivers/sound/gus_vol.c b/drivers/sound/gus_vol.c index a42c5c6e1..b68fca34a 100644 --- a/drivers/sound/gus_vol.c +++ b/drivers/sound/gus_vol.c @@ -34,10 +34,10 @@ extern int gus_wave_volume; * 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 @@ gus_adagio_vol(int vel, int mainv, int xpn, int voicev) /* * Boost expression by voice volume above neutral. */ + if (voicev > 65) xpn += voicev - 64; xpn += (voicev - 64) / 2; @@ -85,18 +86,22 @@ gus_adagio_vol(int vel, int mainv, int xpn, int voicev) * 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 @@ gus_adagio_vol(int vel, int mainv, int xpn, int voicev) * 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 @@ gus_adagio_vol(int vel, int mainv, int xpn, int voicev) * 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 @@ gus_linear_vol(int vol, int mainvol) #else mainvol = 127; #endif - return gus_linearvol[(((vol * mainvol) / 127) * mixer_mainvol) / 100]; } diff --git a/drivers/sound/gus_wave.c b/drivers/sound/gus_wave.c index 8db5f08db..6f3f4a689 100644 --- a/drivers/sound/gus_wave.c +++ b/drivers/sound/gus_wave.c @@ -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]; + 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; + /* + * 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; + /* 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 @@ int gus_timer_enabled = 0; * 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 int gus_audio_bsize; 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 mixer_type = 0; 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 @@ static void gus_tmr_install(int io_base); #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 @@ reset_sample_memory(void) 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 @@ gus_poke(long addr, unsigned char data) 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 @@ gus_peek(long addr) 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 @@ gus_write8(int reg, unsigned int data) 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 @@ gus_read8(int reg) 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 @@ gus_look8(int reg) 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 @@ gus_write16(int reg, unsigned int data) 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 @@ gus_read16(int reg) 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 @@ gus_look16(int reg) 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 @@ gus_write_addr(int reg, unsigned long address, int frac, int is16bit) 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 @@ gus_select_max_voices(int nvoices) 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_voice_mode(unsigned int m) 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_voice_freq(unsigned long freq) 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_rampon(unsigned int m) 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_ramp_mode(unsigned int m) 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 @@ gus_set_voice_pos(int voice, long position) 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 @@ gus_voice_init(int voice) } -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 @@ gus_voice_init2(int voice) 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 @@ step_envelope(int voice) 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 @@ init_envelope(int voice) 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 @@ start_release(int voice, long int flags) 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 @@ gus_voice_fade(int voice) 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 @@ gus_reset(void) 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_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_dma_map[8] = { + 0, 1, 0, 2, 0, 3, 4, 5 + }; save_flags(flags); cli(); @@ -787,37 +767,39 @@ gus_initialize(void) 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) */ + { + 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"); + tmp = gus_dma_map[gus_dma]; + if (!tmp) + printk(KERN_WARNING "Warning! GUS DMA not selected\n"); - dma_image |= tmp; - } else + 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 @@ gus_initialize(void) 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 @@ gus_initialize(void) } -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 @@ pnp_mem_init(void) * 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; - - 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)); - } + { + /* 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)); + } 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; - - 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. - */ + { + 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. + */ 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 @@ pnp_mem_init(void) 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_wave_detect(int baseaddr) 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 @@ gus_wave_detect(int baseaddr) /* 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; - - /* 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; - } - - if (failed) - break; - } + { + 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; + } + if (failed) + break; + } gus_mem_size = i << 10; return 1; } @@ -1113,30 +1098,30 @@ gus_wave_detect(int baseaddr) 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)); + 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_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 @@ guswave_set_instr(int dev, int voice, int instr_no) 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 @@ compute_and_set_volume(int voice, int volume, int ramp_time) 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 @@ compute_and_set_volume(int voice, int volume, int ramp_time) 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 @@ compute_and_set_volume(int voice, int volume, int ramp_time) 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; - - gus_ramp_range(target, curr); - gus_rampon(0x40); /* Ramp down, once, no irq */ - } + { + 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 */ + } 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 @@ dynamic_volume_change(int voice) 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 @@ dynamic_volume_change(int voice) 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 @@ dynamic_volume_change(int voice) } -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 @@ guswave_controller(int dev, int voice, int ctrl_num, int value) 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; - - default: - break; - } + { + 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; + + 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 @@ guswave_start_note2(int dev, int voice, int note_num, int volume) 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 @@ guswave_start_note2(int dev, int voice, int note_num, int volume) gus_write8(0x15, 0x00); /* RAM, Reset voice deactivate bit of SMSI */ if (voices[voice].mode & WAVE_ENVELOPES) - { - 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]; - } - } + { + 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]; + } + } 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 @@ guswave_start_note2(int dev, int voice, int note_num, int volume) 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 @@ guswave_start_note2(int dev, int voice, int note_num, int volume) 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 @@ guswave_start_note2(int dev, int voice, int note_num, int volume) 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 @@ guswave_start_note2(int dev, int voice, int note_num, int volume) * 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 @@ guswave_open(int dev, int mode) 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 @@ guswave_open(int dev, int mode) return 0; } -static void -guswave_close(int dev) +static void guswave_close(int dev) { gus_busy = 0; active_device = 0; @@ -1707,35 +1680,34 @@ guswave_close(int dev) 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 @@ guswave_load_patch(int dev, int format, const char *addr, 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; - - if ((tmp_mem + patch.len) > gus_mem_size) - return -ENOSPC; - - free_mem_ptr = tmp_mem; /* This leaves unusable memory */ - } - } + { + /* + * 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; + + free_mem_ptr = tmp_mem; /* This leaves unusable memory */ + } + } if ((free_mem_ptr + patch.len) > gus_mem_size) return -ENOSPC; @@ -1816,9 +1788,9 @@ guswave_load_patch(int dev, int format, const char *addr, patch.mode &= ~WAVE_TREMOLO; if (!(patch.mode & WAVE_FRACTIONS)) - { + { patch.fractions = 0; - } + } memcpy((char *) &samples[free_sample], &patch, sizeof_patch); /* @@ -1837,162 +1809,154 @@ guswave_load_patch(int dev, int format, const char *addr, 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; - - 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; - - - { - 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; - - gus_write8(0x41, 0); /* Stop DMA */ - } + { + blk_sz = audio_devs[gus_devnum]->dmap_out->bytes_in_use; + if (blk_sz > left) + blk_sz = left; - free_mem_ptr += patch.len; + /* + * 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; + unsigned long tlimit; + 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 @@ guswave_hw_control(int dev, unsigned char *event_rec) 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_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; - - default:; - } + { + 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; + + 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_set_speed(int speed) 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 @@ gus_audio_set_channels(int channels) 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 @@ static int gus_audio_ioctl(int dev, unsigned int cmd, caddr_t arg) { 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_audio_open(int dev, int mode) 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 @@ gus_audio_open(int dev, int mode) 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 @@ gus_audio_close(int dev) 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 @@ play_next_pcm_block(void) 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)); - - 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 */ + { + 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; - restore_flags(flags); - } + dram_loc = this_one * pcm_bsize; + dram_loc += chn * pcm_banksize; - 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); - } + 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)); + + 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 @@ gus_transfer_output_block(int dev, unsigned long buf, * 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 @@ gus_transfer_output_block(int dev, unsigned long buf, 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 @@ gus_transfer_output_block(int dev, unsigned long buf, 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_transfer_output_block(int dev, unsigned long buf, 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 @@ gus_audio_output_block(int dev, unsigned long buf, int total_count, 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 @@ gus_audio_start_input(int dev, unsigned long buf, int count, 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_audio_prepare_for_input(int dev, int bsize, int bcount) 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 @@ gus_audio_prepare_for_output(int dev, int bsize, int bcount) 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 @@ static struct audio_driver gus_audio_driver = 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 @@ guswave_setup_voice(int dev, int voice, int chn) 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 @@ guswave_bender(int dev, int voice, int value) 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 @@ static struct synth_operations guswave_operations = 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 @@ set_input_volumes(void) 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 @@ int gus_default_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg) 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_DEVMASK: + val = MIX_DEVS; + break; - case SOUND_MIXER_STEREODEVS: - val = 0; - break; + case SOUND_MIXER_STEREODEVS: + val = 0; + break; - case SOUND_MIXER_RECMASK: - val = SOUND_MASK_MIC | SOUND_MASK_LINE; - break; + case SOUND_MIXER_RECMASK: + val = SOUND_MASK_MIC | SOUND_MASK_LINE; + break; - case SOUND_MIXER_CAPS: - val = 0; - break; + case SOUND_MIXER_CAPS: + val = 0; + break; - case SOUND_MIXER_MIC: - val = gus_mic_vol | (gus_mic_vol << 8); - 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_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_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_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 @@ static struct mixer_operations gus_mixer_operations = 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 */ + 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; + 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 @@ void gus_wave_init(struct address_info *hw_config) { 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 @@ void gus_wave_init(struct address_info *hw_config) /* * 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 @@ void gus_wave_init(struct address_info *hw_config) } } 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 @@ static void do_loop_irq(int voice) 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; - - default:; - } + 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; + + 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 @@ do_volume_irq(int voice) 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; - - 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:; - } + 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: + } 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 @@ guswave_dma_irq(void) 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 @@ gus_timer_command(unsigned int addr, unsigned int val) 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 @@ static struct sound_lowlev_timer gus_tmr = 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 --git a/drivers/sound/soundcard.c b/drivers/sound/soundcard.c index 3cd56ae5b..11c63ff1b 100644 --- a/drivers/sound/soundcard.c +++ b/drivers/sound/soundcard.c @@ -1101,8 +1101,7 @@ sound_alloc_dmap(int dev, struct dma_buffparms *dmap, int chan) 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 --git a/fs/dcache.c b/fs/dcache.c index a19ad2337..80562646f 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -68,6 +68,7 @@ static inline void dentry_iput(struct dentry * dentry) 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 --git a/fs/fat/buffer.c b/fs/fat/buffer.c index 2c4c7a89f..86b3a2f5a 100644 --- a/fs/fat/buffer.c +++ b/fs/fat/buffer.c @@ -30,9 +30,9 @@ struct buffer_head *fat_bread ( * 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 @@ struct buffer_head *fat_bread ( 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 @@ struct buffer_head *fat_bread ( } 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 @@ void fat_brelse ( 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_brelse ( 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 @@ void fat_set_uptodate ( 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 @@ int fat_is_uptodate ( 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 @@ void fat_ll_rw_block ( 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 --git a/fs/fat/cache.c b/fs/fat/cache.c index edc976bd4..9083d6b31 100644 --- a/fs/fat/cache.c +++ b/fs/fat/cache.c @@ -30,9 +30,9 @@ int fat_access(struct super_block *sb,int nr,int new_value) 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 fat_smap(struct inode *inode,int sector) 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 --git a/fs/fat/dir.c b/fs/fat/dir.c index 23b15726c..7ba11ec2d 100644 --- a/fs/fat/dir.c +++ b/fs/fat/dir.c @@ -437,10 +437,10 @@ int fat_dir_ioctl(struct inode * inode, struct file * filp, } 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 --git a/fs/fat/file.c b/fs/fat/file.c index d0418d6c6..4a271e876 100644 --- a/fs/fat/file.c +++ b/fs/fat/file.c @@ -312,9 +312,10 @@ ssize_t fat_file_read( 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 @@ ssize_t fat_file_write( 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 --git a/fs/fat/inode.c b/fs/fat/inode.c index d1c43bf17..184a4d19b 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -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 @@ void fat_delete_inode(struct inode *inode) /* * 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_delete_inode(struct inode *inode) 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 @@ void fat_put_super(struct super_block *sb) 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 @@ fat_read_super(struct super_block *sb, void *data, int silent) 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 @@ fat_read_super(struct super_block *sb, void *data, int silent) /* 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 @@ fat_read_super(struct super_block *sb, void *data, int silent) 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 fat_statfs(struct super_block *sb,struct statfs *buf, int bufsiz) 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 fat_bmap(struct inode *inode,int block) 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 @@ void fat_read_inode(struct inode *inode, struct inode_operations *fs_dir_inode_o 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 @@ void fat_read_inode(struct inode *inode, struct inode_operations *fs_dir_inode_o 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 @@ void fat_read_inode(struct inode *inode, struct inode_operations *fs_dir_inode_o !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 @@ void fat_read_inode(struct inode *inode, struct inode_operations *fs_dir_inode_o 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 @@ void fat_write_inode(struct inode *inode) 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 @@ void fat_write_inode(struct inode *inode) 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 --git a/fs/fat/misc.c b/fs/fat/misc.c index dc3a2545c..b398a0bbd 100644 --- a/fs/fat/misc.c +++ b/fs/fat/misc.c @@ -221,9 +221,9 @@ if (last) printk("next set to %d\n",fat_access(sb,last,-1)); #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 --git a/fs/fat/mmap.c b/fs/fat/mmap.c index a95db457f..641c414a7 100644 --- a/fs/fat/mmap.c +++ b/fs/fat/mmap.c @@ -97,9 +97,9 @@ struct vm_operations_struct fat_file_mmap = { 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_mmap(struct file * file, struct vm_area_struct * vma) 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 --git a/fs/msdos/namei.c b/fs/msdos/namei.c index 38f131d84..87c62e4c9 100644 --- a/fs/msdos/namei.c +++ b/fs/msdos/namei.c @@ -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 msdos_lookup(struct inode *dir,struct dentry *dentry) 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 @@ int msdos_lookup(struct inode *dir,struct dentry *dentry) 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 @@ static int msdos_empty(struct inode *dir) 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 @@ int msdos_rmdir(struct inode *dir, struct dentry *dentry) 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 @@ static int rename_diff_dir(struct inode *old_dir,char *old_name, 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 @@ free_inode->i_ino, new_inode->i_ino); iput(dotdot_inode); fat_brelse(sb, dotdot_bh); } + /* Update the dcache */ d_move(old_dentry, new_dentry); error = 0; diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index 4ea31ed33..836c1b4d6 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c @@ -433,19 +433,37 @@ exp_readlock(void) 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 --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c index 7bd2b5ebe..2cd24e78f 100644 --- a/fs/nfsd/nfsfh.c +++ b/fs/nfsd/nfsfh.c @@ -999,21 +999,19 @@ out: 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 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) * 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 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) /* 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 --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 3d392eea6..cba32eea7 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -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 @@ nfsd(struct svc_rqst *rqstp) 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 @@ nfsd(struct svc_rqst *rqstp) /* 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 --git a/fs/ntfs/fs.c b/fs/ntfs/fs.c index 18704ea59..ac4f5892b 100644 --- a/fs/ntfs/fs.c +++ b/fs/ntfs/fs.c @@ -881,8 +881,8 @@ ntfs_read_super_unl: 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 --git a/fs/open.c b/fs/open.c index a2e512d88..e417119a9 100644 --- a/fs/open.c +++ b/fs/open.c @@ -546,6 +546,23 @@ asmlinkage int sys_chown(const char * filename, uid_t user, gid_t group) 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 --git a/fs/proc/root.c b/fs/proc/root.c index 4bd075df6..ae9ccce2e 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c @@ -342,11 +342,6 @@ int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp) 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 --git a/fs/vfat/namei.c b/fs/vfat/namei.c index fb3023765..97d2d2f62 100644 --- a/fs/vfat/namei.c +++ b/fs/vfat/namei.c @@ -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 @@ void vfat_put_super(struct super_block *sb) 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 @@ struct super_block *vfat_read_super(struct super_block *sb,void *data, 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 @@ static int vfat_create_shortname(struct inode *dir, const char *name, 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 @@ static int vfat_create_shortname(struct inode *dir, const char *name, 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 @@ static loff_t vfat_find_free_slots(struct inode *dir,int slots) 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 @@ static loff_t vfat_find_free_slots(struct inode *dir,int slots) 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 @@ vfat_fill_long_slots(struct msdos_dir_slot *ds, const char *name, int len, 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 @@ vfat_fill_long_slots(struct msdos_dir_slot *ds, const char *name, int len, 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 @@ static int vfat_build_slots(struct inode *dir,const char *name,int len, 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 @@ static int vfat_build_slots(struct inode *dir,const char *name,int len, } 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 @@ static int vfat_find(struct inode *dir,struct qstr* qname, 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 @@ static int vfat_find(struct inode *dir,struct qstr* qname, 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 @@ static int vfat_find(struct inode *dir,struct qstr* qname, 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 @@ static int vfat_find(struct inode *dir,struct qstr* qname, 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 @@ static int vfat_find(struct inode *dir,struct qstr* qname, 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 @@ static int vfat_find(struct inode *dir,struct qstr* qname, 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 @@ int vfat_lookup(struct inode *dir,struct dentry *dentry) 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 @@ int vfat_lookup(struct inode *dir,struct dentry *dentry) 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 @@ static int vfat_create_entry(struct inode *dir,struct qstr* qname, 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 @@ static int vfat_create_entry(struct inode *dir,struct qstr* qname, 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 @@ int vfat_create(struct inode *dir,struct dentry* dentry,int mode) 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 @@ static int vfat_create_a_dotdir(struct inode *dir,struct inode *parent, 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 @@ static int vfat_create_a_dotdir(struct inode *dir,struct inode *parent, iput(dot); - PRINTK(("vfat_create_a_dotdir 2\n")); + PRINTK3(("vfat_create_a_dotdir 2\n")); return 0; } @@ -1348,31 +1363,31 @@ static int vfat_create_dotdirs(struct inode *dir, struct inode *parent) 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 @@ static int vfat_empty(struct inode *dir) 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 @@ static int vfat_rmdir_free_ino(struct inode *dir,struct buffer_head *bh, 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 @@ static int vfat_remove_entry(struct inode *dir,struct vfat_slot_info *sinfo, 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 @@ static void vfat_delete_dentries(struct dentry *dentry) 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 @@ static int vfat_rmdirx(struct inode *dir,struct dentry* dentry) 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 @@ static int vfat_rmdirx(struct inode *dir,struct dentry* dentry) 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 @@ static int vfat_unlinkx( 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 @@ int vfat_mkdir(struct inode *dir,struct dentry* dentry,int mode) 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 vfat_unlink(struct inode *dir,struct dentry* dentry) { 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 vfat_rename(struct inode *old_dir,struct dentry *old_dentry, 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 @@ int vfat_rename(struct inode *old_dir,struct dentry *old_dentry, 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 @@ int vfat_rename(struct inode *old_dir,struct dentry *old_dentry, 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 @@ int vfat_rename(struct inode *old_dir,struct dentry *old_dentry, 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 @@ int vfat_rename(struct inode *old_dir,struct dentry *old_dentry, 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")); + PRINTK3(("vfat_rename 15b\n")); - fat_mark_buffer_dirty(sb, new_bh, 1); - - /* 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 @@ int vfat_rename(struct inode *old_dir,struct dentry *old_dentry, } 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 @@ rename_done: fat_brelse(sb, old_bh); if (new_bh) fat_brelse(sb, new_bh); + if (put_new_inode) + iput(new_inode); return res; } diff --git a/include/asm-i386/hardirq.h b/include/asm-i386/hardirq.h index 39a8206ef..1d45fded1 100644 --- a/include/asm-i386/hardirq.h +++ b/include/asm-i386/hardirq.h @@ -15,7 +15,6 @@ extern unsigned int local_irq_count[NR_CPUS]; #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 @@ static inline void release_irqlock(int cpu) /* 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 @@ static inline void hardirq_endlock(int cpu) } extern void synchronize_irq(void); -extern void synchronize_one_irq(unsigned int irq); #endif /* __SMP__ */ diff --git a/include/asm-i386/softirq.h b/include/asm-i386/softirq.h index 8946d577e..a28f6bae8 100644 --- a/include/asm-i386/softirq.h +++ b/include/asm-i386/softirq.h @@ -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 @@ extern inline void mark_bh(int nr) 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 @@ extern inline void enable_bh(int nr) * 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 --git a/include/asm-i386/uaccess.h b/include/asm-i386/uaccess.h index 349329515..ef08ac510 100644 --- a/include/asm-i386/uaccess.h +++ b/include/asm-i386/uaccess.h @@ -263,7 +263,7 @@ do { \ " .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 --git a/include/asm-i386/unistd.h b/include/asm-i386/unistd.h index 1a45b75c3..2dc02df02 100644 --- a/include/asm-i386/unistd.h +++ b/include/asm-i386/unistd.h @@ -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 --git a/include/asm-mips/ioctls.h b/include/asm-mips/ioctls.h index 5648eae7f..d04de37f1 100644 --- a/include/asm-mips/ioctls.h +++ b/include/asm-mips/ioctls.h @@ -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 --git a/include/linux/blk.h b/include/linux/blk.h index 8893b170a..f5d58f4bb 100644 --- a/include/linux/blk.h +++ b/include/linux/blk.h @@ -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 --git a/include/linux/msdos_fs_i.h b/include/linux/msdos_fs_i.h index 530930e53..674999c58 100644 --- a/include/linux/msdos_fs_i.h +++ b/include/linux/msdos_fs_i.h @@ -28,16 +28,9 @@ struct msdos_inode_info { 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 --git a/include/linux/nfsd/nfsfh.h b/include/linux/nfsd/nfsfh.h index 10be0abc6..3e3410776 100644 --- a/include/linux/nfsd/nfsfh.h +++ b/include/linux/nfsd/nfsfh.h @@ -116,12 +116,16 @@ fh_lock(struct svc_fh *fhp) 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 @@ fh_lock(struct svc_fh *fhp) 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 --git a/include/linux/signal.h b/include/linux/signal.h index 0dd75b886..ff193cd24 100644 --- a/include/linux/signal.h +++ b/include/linux/signal.h @@ -174,6 +174,11 @@ extern inline void sigdelsetmask(sigset_t *set, unsigned long mask) 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 --git a/include/linux/tty.h b/include/linux/tty.h index a9e697da7..7f3c97b36 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -303,6 +303,7 @@ extern int tty_init(void); 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); @@ -352,10 +353,6 @@ extern long serial_console_init(long kmem_start, long kmem_end); 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 */ extern void update_screen(int new_console); diff --git a/include/linux/videodev.h b/include/linux/videodev.h index f6e398b83..064ee9d06 100644 --- a/include/linux/videodev.h +++ b/include/linux/videodev.h @@ -173,4 +173,14 @@ struct video_key #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 --git a/kernel/acct.c b/kernel/acct.c index 27f99ff92..801f3c002 100644 --- a/kernel/acct.c +++ b/kernel/acct.c @@ -268,8 +268,8 @@ int acct_process(long exitcode) /* - * 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 @@ int acct_process(long exitcode) } 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 --git a/kernel/printk.c b/kernel/printk.c index 8c16a6c76..de7daeb3a 100644 --- a/kernel/printk.c +++ b/kernel/printk.c @@ -229,9 +229,7 @@ asmlinkage int printk(const char *fmt, ...) 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 @@ asmlinkage int printk(const char *fmt, ...) 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 --git a/kernel/softirq.c b/kernel/softirq.c index de398bcff..4bc5ee4b6 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c @@ -62,14 +62,14 @@ static inline void run_bottom_halves(void) 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 --git a/scripts/Menuconfig b/scripts/Menuconfig index 657bb0489..4dd37ab52 100644 --- a/scripts/Menuconfig +++ b/scripts/Menuconfig @@ -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 @@ function l_bool () { case $x in y) eval $1=n ;; n) eval $1=y ;; + *) eval $1=y ;; esac ;; *) eval $1=n ;; esac @@ -392,6 +396,7 @@ As a result, this feature will be built as a module." 4 70 case $x in m) eval $1=n ;; n) eval $1=m ;; + *) eval $1=m ;; esac ;; *) eval $1=n ;; esac @@ -416,6 +421,7 @@ function l_tristate () { y) eval $1=n ;; n) eval $1=m ;; m) eval $1=y ;; + *) eval $1=y ;; esac ;; *) eval $1=n ;; esac -- 2.11.4.GIT